From 7cef9f1a32559970324f459f4245f7dcd3503284 Mon Sep 17 00:00:00 2001 From: Tower Deploy Date: Mon, 27 Apr 2026 13:43:58 +0300 Subject: [PATCH] Wipe cetmix_tower_yaml (polluted by overlapping uploads) --- addons/cetmix_tower_yaml/README.rst | 152 --- addons/cetmix_tower_yaml/__init__.py | 2 - addons/cetmix_tower_yaml/__manifest__.py | 42 - addons/cetmix_tower_yaml/demo/demo_data.xml | 13 - .../i18n/cetmix_tower_yaml.pot | 1017 ---------------- addons/cetmix_tower_yaml/i18n/hr.po | 587 --------- addons/cetmix_tower_yaml/i18n/it.po | 1069 ----------------- .../migrations/16.0.1.4.1/post-migration.py | 19 - addons/cetmix_tower_yaml/models/__init__.py | 21 - .../models/cx_tower_command.py | 31 - .../cetmix_tower_yaml/models/cx_tower_file.py | 46 - .../models/cx_tower_file_template.py | 25 - .../models/cx_tower_jet_action.py | 26 - .../models/cx_tower_jet_state.py | 22 - .../models/cx_tower_jet_template.py | 42 - .../cx_tower_jet_template_dependency.py | 19 - .../models/cx_tower_jet_waypoint_template.py | 32 - .../cetmix_tower_yaml/models/cx_tower_key.py | 20 - .../models/cx_tower_key_value.py | 18 - .../cetmix_tower_yaml/models/cx_tower_os.py | 20 - .../cetmix_tower_yaml/models/cx_tower_plan.py | 23 - .../models/cx_tower_plan_line.py | 21 - .../models/cx_tower_plan_line_action.py | 20 - .../models/cx_tower_scheduled_task.py | 23 - .../models/cx_tower_scheduled_task_cv.py | 36 - .../models/cx_tower_server.py | 52 - .../models/cx_tower_server_log.py | 23 - .../models/cx_tower_server_template.py | 41 - .../models/cx_tower_shortcut.py | 22 - .../cetmix_tower_yaml/models/cx_tower_tag.py | 16 - .../models/cx_tower_variable.py | 23 - .../models/cx_tower_variable_option.py | 18 - .../models/cx_tower_variable_value.py | 20 - .../models/cx_tower_yaml_manifest_author.py | 23 - .../models/cx_tower_yaml_manifest_template.py | 93 -- .../models/cx_tower_yaml_mixin.py | 577 --------- addons/cetmix_tower_yaml/pyproject.toml | 3 - addons/cetmix_tower_yaml/readme/CONFIGURE.md | 1 - .../cetmix_tower_yaml/readme/DESCRIPTION.md | 3 - addons/cetmix_tower_yaml/readme/HISTORY.md | 69 -- addons/cetmix_tower_yaml/readme/USAGE.md | 1 - .../readme/newsfragments/.gitkeep | 0 .../security/cetmix_tower_yaml_groups.xml | 30 - .../cx_tower_yaml_wizard_access_rules.xml | 39 - .../security/ir.model.access.csv | 9 - .../static/description/icon.png | Bin 22128 -> 0 bytes .../static/description/index.html | 534 -------- addons/cetmix_tower_yaml/tests/__init__.py | 8 - .../cetmix_tower_yaml/tests/test_command.py | 347 ------ .../tests/test_file_template.py | 320 ----- addons/cetmix_tower_yaml/tests/test_plan.py | 179 --- .../tests/test_server_log.py | 127 -- .../tests/test_server_yaml.py | 124 -- .../tests/test_tower_yaml_mixin.py | 525 -------- .../tests/test_yaml_export_wizard.py | 375 ------ .../tests/test_yaml_import_wizard.py | 703 ----------- .../views/cx_tower_command_view.xml | 35 - .../views/cx_tower_file_template_view.xml | 41 - .../views/cx_tower_key_view.xml | 12 - .../views/cx_tower_os_view.xml | 12 - .../views/cx_tower_plan_view.xml | 35 - .../views/cx_tower_scheduled_task_view.xml | 43 - .../views/cx_tower_server_template_view.xml | 41 - .../views/cx_tower_server_view.xml | 35 - .../views/cx_tower_shortcut_view.xml | 39 - .../views/cx_tower_tag_view.xml | 12 - .../views/cx_tower_variable_value_view.xml | 15 - .../views/cx_tower_variable_view.xml | 12 - .../cx_tower_yaml_manifest_author_views.xml | 33 - .../cx_tower_yaml_manifest_template_views.xml | 51 - addons/cetmix_tower_yaml/views/menuitems.xml | 33 - addons/cetmix_tower_yaml/wizards/__init__.py | 4 - .../wizards/cx_tower_yaml_export_wiz.py | 367 ------ .../wizards/cx_tower_yaml_export_wiz.xml | 130 -- .../cx_tower_yaml_export_wiz_download.py | 11 - .../cx_tower_yaml_export_wiz_download.xml | 20 - .../wizards/cx_tower_yaml_import_wiz.py | 314 ----- .../wizards/cx_tower_yaml_import_wiz.xml | 153 --- .../cx_tower_yaml_import_wiz_upload.py | 137 --- .../cx_tower_yaml_import_wiz_upload.xml | 39 - 80 files changed, 9275 deletions(-) delete mode 100644 addons/cetmix_tower_yaml/README.rst delete mode 100644 addons/cetmix_tower_yaml/__init__.py delete mode 100644 addons/cetmix_tower_yaml/__manifest__.py delete mode 100644 addons/cetmix_tower_yaml/demo/demo_data.xml delete mode 100644 addons/cetmix_tower_yaml/i18n/cetmix_tower_yaml.pot delete mode 100644 addons/cetmix_tower_yaml/i18n/hr.po delete mode 100644 addons/cetmix_tower_yaml/i18n/it.po delete mode 100644 addons/cetmix_tower_yaml/migrations/16.0.1.4.1/post-migration.py delete mode 100644 addons/cetmix_tower_yaml/models/__init__.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_command.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_file.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_file_template.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_jet_action.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_jet_state.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_jet_template.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_jet_template_dependency.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_jet_waypoint_template.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_key.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_key_value.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_os.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_plan.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_plan_line.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_plan_line_action.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_scheduled_task.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_scheduled_task_cv.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_server.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_server_log.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_server_template.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_shortcut.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_tag.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_variable.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_variable_option.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_variable_value.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_author.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_template.py delete mode 100644 addons/cetmix_tower_yaml/models/cx_tower_yaml_mixin.py delete mode 100644 addons/cetmix_tower_yaml/pyproject.toml delete mode 100644 addons/cetmix_tower_yaml/readme/CONFIGURE.md delete mode 100644 addons/cetmix_tower_yaml/readme/DESCRIPTION.md delete mode 100644 addons/cetmix_tower_yaml/readme/HISTORY.md delete mode 100644 addons/cetmix_tower_yaml/readme/USAGE.md delete mode 100644 addons/cetmix_tower_yaml/readme/newsfragments/.gitkeep delete mode 100644 addons/cetmix_tower_yaml/security/cetmix_tower_yaml_groups.xml delete mode 100644 addons/cetmix_tower_yaml/security/cx_tower_yaml_wizard_access_rules.xml delete mode 100644 addons/cetmix_tower_yaml/security/ir.model.access.csv delete mode 100644 addons/cetmix_tower_yaml/static/description/icon.png delete mode 100644 addons/cetmix_tower_yaml/static/description/index.html delete mode 100644 addons/cetmix_tower_yaml/tests/__init__.py delete mode 100644 addons/cetmix_tower_yaml/tests/test_command.py delete mode 100644 addons/cetmix_tower_yaml/tests/test_file_template.py delete mode 100644 addons/cetmix_tower_yaml/tests/test_plan.py delete mode 100644 addons/cetmix_tower_yaml/tests/test_server_log.py delete mode 100644 addons/cetmix_tower_yaml/tests/test_server_yaml.py delete mode 100644 addons/cetmix_tower_yaml/tests/test_tower_yaml_mixin.py delete mode 100644 addons/cetmix_tower_yaml/tests/test_yaml_export_wizard.py delete mode 100644 addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py delete mode 100644 addons/cetmix_tower_yaml/views/cx_tower_command_view.xml delete mode 100644 addons/cetmix_tower_yaml/views/cx_tower_file_template_view.xml delete mode 100644 addons/cetmix_tower_yaml/views/cx_tower_key_view.xml delete mode 100644 addons/cetmix_tower_yaml/views/cx_tower_os_view.xml delete mode 100644 addons/cetmix_tower_yaml/views/cx_tower_plan_view.xml delete mode 100644 addons/cetmix_tower_yaml/views/cx_tower_scheduled_task_view.xml delete mode 100644 addons/cetmix_tower_yaml/views/cx_tower_server_template_view.xml delete mode 100644 addons/cetmix_tower_yaml/views/cx_tower_server_view.xml delete mode 100644 addons/cetmix_tower_yaml/views/cx_tower_shortcut_view.xml delete mode 100644 addons/cetmix_tower_yaml/views/cx_tower_tag_view.xml delete mode 100644 addons/cetmix_tower_yaml/views/cx_tower_variable_value_view.xml delete mode 100644 addons/cetmix_tower_yaml/views/cx_tower_variable_view.xml delete mode 100644 addons/cetmix_tower_yaml/views/cx_tower_yaml_manifest_author_views.xml delete mode 100644 addons/cetmix_tower_yaml/views/cx_tower_yaml_manifest_template_views.xml delete mode 100644 addons/cetmix_tower_yaml/views/menuitems.xml delete mode 100644 addons/cetmix_tower_yaml/wizards/__init__.py delete mode 100644 addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py delete mode 100644 addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.xml delete mode 100644 addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz_download.py delete mode 100644 addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz_download.xml delete mode 100644 addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py delete mode 100644 addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.xml delete mode 100644 addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py delete mode 100644 addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.xml diff --git a/addons/cetmix_tower_yaml/README.rst b/addons/cetmix_tower_yaml/README.rst deleted file mode 100644 index 51d73cf..0000000 --- a/addons/cetmix_tower_yaml/README.rst +++ /dev/null @@ -1,152 +0,0 @@ -================= -Cetmix Tower YAML -================= - -.. - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! This file is generated by oca-gen-addon-readme !! - !! changes will be overwritten. !! - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:96e8f3f1df3ab25b952a9534d0914149740cc036b62efe2c7795f9d2d9636177 - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png - :target: https://odoo-community.org/page/development-status - :alt: Beta -.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png - :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html - :alt: License: AGPL-3 -.. |badge3| image:: https://img.shields.io/badge/github-cetmix%2Fcetmix--tower-lightgray.png?logo=github - :target: https://github.com/cetmix/cetmix-tower/tree/16.0/cetmix_tower_yaml - :alt: cetmix/cetmix-tower - -|badge1| |badge2| |badge3| - -This module implements YAML format data import/export for `Cetmix -Tower `__. - -Please refer to the `official -documentation `__ for detailed information. - -**Table of contents** - -.. contents:: - :local: - -Configuration -============= - -Please refer to the `official -documentation `__ for detailed configuration -instructions. - -Usage -===== - -Please refer to the `official -documentation `__ for detailed usage -instructions. - -Changelog -========= - -16.0.2.0.1 (2025-10-29) ------------------------ - -- Features: Improve the way secrets are listed in the YAML import - widget. (5010) - -16.0.1.4.2 (2025-10-06) ------------------------ - -- Bugfixes: Add the missing 'create' function decorator (4980) - -16.0.1.4.1 (2025-08-26) ------------------------ - -- Bugfixes: Make selection values lowercase to simplify their - management. (4896) - -16.0.1.3.0 (2025-07-30) ------------------------ - -- Features: Optional behaviour when file uploaded by command already - exists on the server. (4740) - -16.0.1.1.4 (2025-07-08) ------------------------ - -- Bugfixes: Fix missing model names in YAML exports when exporting - multiple commands with flight plans (4820) - -16.0.1.1.3 (2025-07-07) ------------------------ - -- Bugfixes: Import servers with ``Password`` ssh authentication mode - (4812) - -16.0.1.1.1 (2025-06-23) ------------------------ - -- Features: YAML code optimisation (4728) - -16.0.1.1.0 (2025-06-20) ------------------------ - -- Features: Export/import scheduled tasks to/from YAML. (4650) - -16.0.1.0.5 (2025-05-21) ------------------------ - -- Features: Export/import secret values related to Server. (4696) - -16.0.1.0.4 (2025-05-16) ------------------------ - -- Features: Export/import servers and files to/from YAML. (4670) - -16.0.1.0.3 (2025-05-09) ------------------------ - -- Bugfixes: Non-critical issues and performance improvements. (4663) - -16.0.1.0.2 (2025-04-30) ------------------------ - -- Features: User groups are visible without developer mode. (4642) - -16.0.1.0.1 (2025-04-21) ------------------------ - -- Features: Export additional fields for shortcuts, variables and - options. Add action menu to export keys/secrets. (4602) - -16.0.1.0.0 ----------- - -Release for Odoo 16.0 - -Bug Tracker -=========== - -Bugs are tracked on `GitHub Issues `_. -In case of trouble, please check there if your issue has already been reported. -If you spotted it first, help us to smash it by providing a detailed and welcomed -`feedback `_. - -Do not contact contributors directly about support or help with technical issues. - -Credits -======= - -Authors -------- - -* Cetmix - -Maintainers ------------ - -This module is part of the `cetmix/cetmix-tower `_ project on GitHub. - -You are welcome to contribute. diff --git a/addons/cetmix_tower_yaml/__init__.py b/addons/cetmix_tower_yaml/__init__.py deleted file mode 100644 index aee8895..0000000 --- a/addons/cetmix_tower_yaml/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from . import models -from . import wizards diff --git a/addons/cetmix_tower_yaml/__manifest__.py b/addons/cetmix_tower_yaml/__manifest__.py deleted file mode 100644 index a96cc96..0000000 --- a/addons/cetmix_tower_yaml/__manifest__.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright Cetmix OÜ 2024 -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -{ - "name": "Cetmix Tower YAML", - "summary": "Cetmix Tower YAML export/import", - "version": "16.0.2.0.3", - "development_status": "Beta", - "category": "Productivity", - "website": "https://tower.cetmix.com", - "author": "Cetmix", - "license": "AGPL-3", - "installable": True, - "depends": ["cetmix_tower_server"], - "external_dependencies": {"python": ["pyyaml"]}, - "data": [ - "security/cetmix_tower_yaml_groups.xml", - "security/cx_tower_yaml_wizard_access_rules.xml", - "security/ir.model.access.csv", - "views/cx_tower_command_view.xml", - "views/cx_tower_file_template_view.xml", - "views/cx_tower_plan_view.xml", - "views/cx_tower_server_template_view.xml", - "views/cx_tower_server_view.xml", - "views/cx_tower_variable_view.xml", - "views/cx_tower_variable_value_view.xml", - "views/cx_tower_os_view.xml", - "views/cx_tower_tag_view.xml", - "views/cx_tower_shortcut_view.xml", - "views/cx_tower_scheduled_task_view.xml", - "views/cx_tower_key_view.xml", - "views/cx_tower_yaml_manifest_template_views.xml", - "views/cx_tower_yaml_manifest_author_views.xml", - "wizards/cx_tower_yaml_export_wiz.xml", - "wizards/cx_tower_yaml_export_wiz_download.xml", - "wizards/cx_tower_yaml_import_wiz_upload.xml", - "wizards/cx_tower_yaml_import_wiz.xml", - "views/menuitems.xml", - ], - "demo": [ - "demo/demo_data.xml", - ], -} diff --git a/addons/cetmix_tower_yaml/demo/demo_data.xml b/addons/cetmix_tower_yaml/demo/demo_data.xml deleted file mode 100644 index 40f8de5..0000000 --- a/addons/cetmix_tower_yaml/demo/demo_data.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - diff --git a/addons/cetmix_tower_yaml/i18n/cetmix_tower_yaml.pot b/addons/cetmix_tower_yaml/i18n/cetmix_tower_yaml.pot deleted file mode 100644 index 8de30e5..0000000 --- a/addons/cetmix_tower_yaml/i18n/cetmix_tower_yaml.pot +++ /dev/null @@ -1,1017 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * cetmix_tower_yaml -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 16.0\n" -"Report-Msgid-Bugs-To: \n" -"Last-Translator: \n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Plural-Forms: \n" - -#. module: cetmix_tower_yaml -#: model:res.groups,comment:cetmix_tower_yaml.group_export -msgid "" -"\n" -" Export data to YAML.\n" -" " -msgstr "" - -#. module: cetmix_tower_yaml -#: model:res.groups,comment:cetmix_tower_yaml.group_import -msgid "" -"\n" -" Import data from YAML.\n" -" " -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "'%s' is not a valid model" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#, python-format -msgid "'invalid_model' is not a valid model" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "" -"Important: To maintain data consistency, the following\n" -" model records will always be updated if they exist in Odoo:" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__add_manifest -msgid "Add Manifest" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__explode_child_records -msgid "" -"Add entire child record definitions to the exported YAML file. Otherwise " -"only references to child records will be added." -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__file_prefix -msgid "" -"Add prefix to the exported YAML file name when this template is selected" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:res.groups,name:cetmix_tower_yaml.group_export -#: model:res.groups,name:cetmix_tower_yaml.group_import -msgid "Allow" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_author_string -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Author" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.constraint,message:cetmix_tower_yaml.constraint_cx_tower_yaml_manifest_author_yaml_manifest_author_name_uniq -msgid "Author name must be unique." -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_author_ids -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__author_ids -msgid "Authors" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_command -msgid "Cetmix Tower Command" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_file -msgid "Cetmix Tower File" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_file_template -msgid "Cetmix Tower File Template" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_plan -msgid "Cetmix Tower Flight Plan" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_plan_line -msgid "Cetmix Tower Flight Plan Line" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_plan_line_action -msgid "Cetmix Tower Flight Plan Line Action" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_key -msgid "Cetmix Tower Key/Secret Storage" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_os -msgid "Cetmix Tower Operating System" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_key_value -msgid "Cetmix Tower Secret Value Storage" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_server -msgid "Cetmix Tower Server" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_server_log -msgid "Cetmix Tower Server Log" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_server_template -msgid "Cetmix Tower Server Template" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_shortcut -msgid "Cetmix Tower Shortcut" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_tag -msgid "Cetmix Tower Tag" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_variable -msgid "Cetmix Tower Variable" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_variable_option -msgid "Cetmix Tower Variable Options" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_variable_value -msgid "Cetmix Tower Variable Values" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_export_wiz_download -msgid "Cetmix Tower YAML Export File Download" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_export_wiz -msgid "Cetmix Tower YAML Export Wizard" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_import_wiz -msgid "Cetmix Tower YAML Import Wizard" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_import_wiz_upload -msgid "Cetmix Tower YAML Import Wizard Upload" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_mixin -msgid "Cetmix Tower YAML rendering mixin" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_download_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_upload_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Close" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Code preview" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_author_string -msgid "Comma-separated list" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields.selection,name:cetmix_tower_yaml.selection__cx_tower_yaml_import_wiz__if_record_exists__create -msgid "Create a new record" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__create_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__create_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__create_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__create_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_author__create_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__create_uid -msgid "Created by" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__create_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__create_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__create_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__create_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_author__create_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__create_date -msgid "Created on" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_currency -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_currency -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__currency -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Currency" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__currency -msgid "Currency for pricing information." -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py:0 -#, python-format -msgid "Currency is required when price is specified" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_template.py:0 -#, python-format -msgid "Custom" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__license_text -msgid "Custom license text when license type is Custom." -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_description -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_description -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Description" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "Detailed description (optional)" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_author__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__display_name -msgid "Display Name" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#, python-format -msgid "Error creating record '%(reference)s' in model '%(model)s': %(error)s" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#, python-format -msgid "Error updating record %(reference)s: %(error)s" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_template.py:0 -#, python-format -msgid "Euro" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "" -"Existing record will be updated with the new data. Related records, present in the YAML code, will be updated too.\n" -" If any of those related records doesn't exist, it will be created automatically." -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__explode_child_records -msgid "Explode Child Records" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_command_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_file_template_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_key_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_os_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_plan_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_scheduled_task_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_server_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_server_template_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_shortcut_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_tag_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_variable_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_variable_value_export_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_command_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_file_template_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_plan_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_server_template_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_server_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_shortcut_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.view_cx_tower_scheduled_task_view_form -msgid "Export YAML" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_mixin.py:0 -#, python-format -msgid "Failed to convert dictionary to YAML: %(error)s" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py:0 -#, python-format -msgid "" -"Failed to encode YAML content. Please ensure all characters are UTF-8 " -"compatible." -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__file_name -msgid "File Name" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "File is empty" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "File is not a valid base64-encoded file" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__file_prefix -msgid "File prefix" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#, python-format -msgid "Following secrets are used in the code:
%(secrets)s" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "Generate YAML file" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_author__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__id -msgid "ID" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__if_record_exists -msgid "If Record Exists" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Import" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_yaml_import_wiz_upload -#: model:ir.ui.menu,name:cetmix_tower_yaml.menu_cetmix_tower_yaml_import -msgid "Import YAML" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#, python-format -msgid "Import result: %(model)s" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Information" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "Invalid YAML file" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Key/Secrets" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_author____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl____last_update -msgid "Last Modified on" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__write_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__write_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__write_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__write_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_author__write_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__write_uid -msgid "Last Updated by" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__write_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__write_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__write_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__write_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_author__write_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__write_date -msgid "Last Updated on" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_name -msgid "Leave this field blank if you don't want to create a manifest" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_license -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_license -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__license -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "License" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_license_text -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__license_text -msgid "License Text" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "License and pricing" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_license_text -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "License text" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py:0 -#, python-format -msgid "License text is required for a custom license" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__license -msgid "License used for the code snippet." -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__author_ids -msgid "List of author names to include in the YAML manifest." -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__secret_list -msgid "List of secrets present in the YAML file (formatted as HTML list)" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "Manifest" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.ui.menu,name:cetmix_tower_yaml.menu_yaml_manifest_author_action -msgid "Manifest Authors" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_template_id -msgid "Manifest Template" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.ui.menu,name:cetmix_tower_yaml.menu_yaml_manifest_template -msgid "Manifest Templates" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "Model '%s' does not support YAML import" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#, python-format -msgid "Model 'command_run_wizard' does not support YAML import" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__model_names -msgid "Model Names" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__model_names -msgid "Models to create records in" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_author__name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__name -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Name" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__name -msgid "Name of the manifest template." -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py:0 -#, python-format -msgid "No YAML code is present." -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py:0 -#, python-format -msgid "No model or records selected" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#, python-format -msgid "No records were created or updated" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py:0 -#, python-format -msgid "No valid records selected" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "OSs" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__preview_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__preview_code -msgid "Preview Code" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "Preview code" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_price -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_price -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Price" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_upload_view_form -msgid "Process" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_template.py:0 -#, python-format -msgid "Provide Custom License Text when License is set to 'Custom'." -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#, python-format -msgid "Record Import" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "Record model is missing for record %s" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#, python-format -msgid "Record reference is missing" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#, python-format -msgid "Records of the following models were created or updated: %(models)s" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__remove_empty_values -msgid "Remove Empty x2m Field Values" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__remove_empty_values -msgid "" -"Remove empty Many2one, Many2many and One2many field values from the exported" -" YAML file." -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_scheduled_task -msgid "Scheduled Task" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__secret_list -msgid "Secret List" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "Select a pre-defined template" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "Select a template to auto-populate manifest fields" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_summary -msgid "Short summary that includes core information. 160 symbols max" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "Short summary, 160 symbols max" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields.selection,name:cetmix_tower_yaml.selection__cx_tower_yaml_import_wiz__if_record_exists__skip -msgid "Skip record" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_name -msgid "Snippet Name" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__yaml_file_name -msgid "Snippet file name without extension, eg 'my_snippet'" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_summary -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_summary -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Summary" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Tags" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "This may overwrite existing records. Proceed?" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "" -"To create new entities instead of updating existing ones, remove or modify\n" -" the reference field in the YAML code for those entities." -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__preview_code -msgid "Toggle to show or hide YAML code preview" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_template.py:0 -#, python-format -msgid "US Dollar" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields.selection,name:cetmix_tower_yaml.selection__cx_tower_yaml_import_wiz__if_record_exists__update -msgid "Update existing record" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_version -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "Use the Major.Minor.Patch format, e.g. 1.2.3" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_mixin.py:0 -#: code:addons/cetmix_tower_yaml/tests/test_tower_yaml_mixin.py:0 -#, python-format -msgid "Values must be a dictionary" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Variable Options" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Variables" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_version -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_version -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__version -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Version" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__version -msgid "Version in Major.Minor.Patch format, e.g. 1.0.0" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py:0 -#, python-format -msgid "Version must be in format Major.Minor.Patch, e.g. 1.2.3" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_template.py:0 -#, python-format -msgid "Version must be in the Major.Minor.Patch format, e.g. 1.2.3" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_website -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_website -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__website -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Website" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__website -msgid "Website URL for the manifest." -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__if_record_exists -msgid "What to do if record with the same reference already exists" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_mixin.py:0 -#: code:addons/cetmix_tower_yaml/tests/test_tower_yaml_mixin.py:0 -#, python-format -msgid "Wrong value for 'access_level' key: %(acv)s" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_command_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_file_template_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_plan_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_server_template_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_server_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_shortcut_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.view_cx_tower_scheduled_task_view_form -msgid "YAML" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.module.category,name:cetmix_tower_yaml.ir_module_category_tower_yaml_export -msgid "YAML Export" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.ui.menu,name:cetmix_tower_yaml.menu_yaml_settings_root -msgid "YAML Export/Import" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__yaml_file_name -msgid "YAML File Name" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.module.category,name:cetmix_tower_yaml.ir_module_category_tower_yaml_import -msgid "YAML Import" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_manifest_author -msgid "YAML Manifest Author" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_yaml_manifest_author -msgid "YAML Manifest Authors" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_manifest_tmpl -msgid "YAML Manifest Template" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_yaml_manifest_template -msgid "YAML Manifest Templates" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "YAML file cannot be decoded properly" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "YAML file doesn't contain any records" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "" -"YAML version is higher than version supported by your Cetmix Tower instance." -" %(code_version)s > %(tower_version)s" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_command__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_file__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_file_template__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_key__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_key_value__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_os__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan_line__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan_line_action__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_scheduled_task__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_server__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_server_log__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_server_template__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_shortcut__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_tag__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable_option__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable_value__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_mixin__yaml_code -msgid "Yaml Code" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__yaml_file -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__yaml_file -msgid "Yaml File" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__yaml_file_name -msgid "Yaml File Name" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "Yaml file doesn't contain valid data" -msgstr "" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_mixin.py:0 -#, python-format -msgid "You are not allowed to create records from YAML" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_command_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_file_template_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_plan_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_server_template_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_server_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_shortcut_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.view_cx_tower_scheduled_task_view_form -msgid "You must be a member of the \"YAML/Export\" group to export data as YAML." -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "my_snippet.yaml" -msgstr "" diff --git a/addons/cetmix_tower_yaml/i18n/hr.po b/addons/cetmix_tower_yaml/i18n/hr.po deleted file mode 100644 index 4283e6a..0000000 --- a/addons/cetmix_tower_yaml/i18n/hr.po +++ /dev/null @@ -1,587 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * cetmix_tower_yaml -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 16.0\n" -"Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2025-03-06 09:11+0000\n" -"Last-Translator: Bole \n" -"Language-Team: Croatian \n" -"Language: hr\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " -"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Weblate 5.10.3-dev\n" - -#. module: cetmix_tower_yaml -#: model:res.groups,comment:cetmix_tower_yaml.group_export -msgid "" -"\n" -" Export data to YAML.\n" -" " -msgstr "" -"\n" -" Izvoz podataka u YAML.\n" -" " - -#. module: cetmix_tower_yaml -#: model:res.groups,comment:cetmix_tower_yaml.group_import -msgid "" -"\n" -" Import data from YAML.\n" -" " -msgstr "" -"\n" -" Uvoz podataka iz YAML.\n" -" " - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "" -"Important: To maintain data consistency, the following " -"model records will always be updated if they exist in Odoo:" -msgstr "" -"Važno: Za održavanje konsistencije podataka, sljedeći " -"zapisi modela će uvijek biti ažurirani ako postoje u Odoo:" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__explode_child_records -msgid "" -"Add entire child record definitions to the exported YAML file. Otherwise " -"only references to child records will be added." -msgstr "" -"Dodaj sve podređene definicije podataka u izveženu YAML datoteku. Inače će " -"biti dodane samo reference na podređene zapise." - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_command -msgid "Cetmix Tower Command" -msgstr "Cetmix Tower Naredba" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_plan -msgid "Cetmix Tower Flight Plan" -msgstr "Cetmix Tower Plan Leta" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_plan_line -msgid "Cetmix Tower Flight Plan Line" -msgstr "Cetmix Tower Stavka plana leta" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_plan_line_action -msgid "Cetmix Tower Flight Plan Line Action" -msgstr "Cetmix Tower Akcija stavke plana leta" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_os -msgid "Cetmix Tower Operating System" -msgstr "Cetmix Tower Operativni sistem" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_server_log -msgid "Cetmix Tower Server Log" -msgstr "Cetmix Tower Log servera" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_server_template -msgid "Cetmix Tower Server Template" -msgstr "Cetmix Tower Predložak servera" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_tag -msgid "Cetmix Tower Tag" -msgstr "Cetmix Tower Oznaka" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_variable -msgid "Cetmix Tower Variable" -msgstr "Cetmix Tower Varijabla" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_variable_option -msgid "Cetmix Tower Variable Options" -msgstr "Cetmix Tower Opcija varijable" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_variable_value -msgid "Cetmix Tower Variable Values" -msgstr "Cetmix Tower Vrijednosti varijabli" - -#. module: cetmix_tower_yaml -#: model:ir.module.category,name:cetmix_tower_yaml.ir_module_category_tower_yaml -msgid "Cetmix Tower YAML" -msgstr "Cetmix Tower YAML" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_export_wiz_download -msgid "Cetmix Tower YAML Export File Download" -msgstr "Cetmix Tower YAML preuzimanje izvežene datoteke" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_export_wiz -msgid "Cetmix Tower YAML Export Wizard" -msgstr "Cetmix Tower YAML Čarobnjak za izvoz" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_import_wiz -msgid "Cetmix Tower YAML Import Wizard" -msgstr "Cetmix Tower YAML Čarobnjak za uvoz" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_import_wiz_upload -msgid "Cetmix Tower YAML Import Wizard Upload" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_mixin -msgid "Cetmix Tower YAML rendering mixin" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_key -msgid "Cetmix Tower private key storage" -msgstr "Cetmix Tower Pohrana privatnih ključeva" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_download_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_upload_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Close" -msgstr "Zatvori" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__comment -msgid "Comment" -msgstr "Komentar" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__comment -msgid "Comment to be added to the beginning of exported YAML file" -msgstr "Komentar koje će biti dodan na početku izvežene YAML datoteke" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Create New Record" -msgstr "Kreiraj novi zapis" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__create_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__create_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__create_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__create_uid -msgid "Created by" -msgstr "Kreirao" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__create_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__create_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__create_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__create_date -msgid "Created on" -msgstr "Kreirano" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_file_template -msgid "Cx Tower File Template" -msgstr "CxTower Predložak datoteke" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_command__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_file_template__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_key__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_os__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan_line__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan_line_action__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_server_log__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_server_template__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_tag__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable_option__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable_value__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_mixin__display_name -msgid "Display Name" -msgstr "Naziv" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "" -"Existing record will be updated with the new data. Related records, present in the YAML code, will be updated too.\n" -" If any of those related records doesn't exist, it will be created automatically." -msgstr "" -"Postojeći zapis će biti ažuriran sa novim podacima. Povezani zapisi, " -"prisutni u YAML kodu, će također biti ažurirani.\n" -" Ukoliko neki od " -"povezanih zapisa ne postoji, biti će kreiran automatski." - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__explode_child_records -msgid "Explode Child Records" -msgstr "Proširi podređene zapise" - -#. module: cetmix_tower_yaml -#: model:res.groups,name:cetmix_tower_yaml.group_export -msgid "Export" -msgstr "Izvoz" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_command_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_file_template_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_plan_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_server_template_view_form -msgid "Export YAML" -msgstr "Izvoz YAML" - -#. module: cetmix_tower_yaml -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_mixin.py:0 -#, python-format -msgid "Failed to convert dictionary to YAML: %(error)s" -msgstr "Neuspjelo pretvaranje dictionary u YAML: %(error)s" - -#. module: cetmix_tower_yaml -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py:0 -#, python-format -msgid "" -"Failed to encode YAML content. Please ensure all characters are UTF-8 " -"compatible." -msgstr "" -"Neuspjelo kreiranje YAML sadržaja. Molimo provjerite jesu li svi znakovi UTF-" -"8 kompatabilni." - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__file_name -msgid "File Name" -msgstr "Naziv datoteke" - -#. module: cetmix_tower_yaml -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "File is not a valid base64-encoded file" -msgstr "Datoteka nije ispravno base64 kodirana" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "Generate YAML file" -msgstr "Generiraj YAML datoteku" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_command__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_file_template__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_key__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_os__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan_line__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan_line_action__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_server_log__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_server_template__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_tag__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable_option__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable_value__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_mixin__id -msgid "ID" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__update_existing_record -msgid "" -"If enabled, existing records will be updated with the new data. Otherwise, " -"new records will be created." -msgstr "" -"Ako je označeno, postojeći zapisi će biti ažurirani sa novim podacima. " -"Inače, novi zapisi će biti kreirani." - -#. module: cetmix_tower_yaml -#: model:res.groups,name:cetmix_tower_yaml.group_import -msgid "Import" -msgstr "Uvoz" - -#. module: cetmix_tower_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_yaml_import_wiz_upload -#: model:ir.ui.menu,name:cetmix_tower_yaml.menu_cetmix_tower_yaml_import -msgid "Import YAML" -msgstr "Uvoz YAML" - -#. module: cetmix_tower_yaml -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "Invalid YAML file" -msgstr "Neispravna YAML datoteka" - -#. module: cetmix_tower_yaml -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "Invalid model specified in the YAML file" -msgstr "Neispravan model naveden u YAML datoteci" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_command____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_file_template____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_key____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_os____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan_line____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan_line_action____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_server_log____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_server_template____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_tag____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable_option____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable_value____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_mixin____last_update -msgid "Last Modified on" -msgstr "Zadnje modificirano" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__write_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__write_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__write_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__write_uid -msgid "Last Updated by" -msgstr "Zadnji ažurirao" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__write_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__write_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__write_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__write_date -msgid "Last Updated on" -msgstr "Zadnje ažurirano" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__model_description -msgid "Model" -msgstr "" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__model_name -msgid "Model Name" -msgstr "Naziv modela" - -#. module: cetmix_tower_yaml -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "Model does not support YAML import" -msgstr "Model ne podržava YAML uvoz" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__model_name -msgid "Model to create records in" -msgstr "Model u kojem će podaci biti kreirani" - -#. module: cetmix_tower_yaml -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py:0 -#, python-format -msgid "No YAML code is present." -msgstr "YAML kod nije dostupan." - -#. module: cetmix_tower_yaml -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "No model for import is specified in the YAML file" -msgstr "Model za uvoz nije naveden u YAML datoteci" - -#. module: cetmix_tower_yaml -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py:0 -#, python-format -msgid "No model or records selected" -msgstr "Nisu odabrani zapisi ili model" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "OSs" -msgstr "" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Open Existing Record" -msgstr "Otvori postojeći zapis" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_upload_view_form -msgid "Process" -msgstr "U procesu" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__record_id -msgid "Record" -msgstr "Zapis" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__record_id -msgid "Record ID to update" -msgstr "ID zapisa za ažuriranje" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__remove_empty_values -msgid "Remove Empty x2m Field Values" -msgstr "Ukloni prazne x2m vrijednosti polja" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__remove_empty_values -msgid "" -"Remove empty Many2one, Many2many and One2many field values from the exported" -" YAML file." -msgstr "" -"Ukloni prazne Many2one, Many2many i One2many vrijednosti polja iz izvežene " -"YAML datoteke." - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Tags" -msgstr "Oznake" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "This will create a new record. Proceed?" -msgstr "Ovo će kreirati novi zapis. Nastaviti?" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "This will overwrite the existing record. Proceed?" -msgstr "Ovo će prepisati preko postojećeg zapisa. Nastaviti?" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "" -"To create new entities instead of updating existing ones, remove or modify " -"the reference field in the YAML code for those entities." -msgstr "" -"Za kreiranje novih entiteta umjesto ažuriranja postojećih, uklonite ili " -"modificirajte reference polje u YAML kodu za te zapise." - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__update_existing_record -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Update Existing Record" -msgstr "Ažuriraj postojeći zapis" - -#. module: cetmix_tower_yaml -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_mixin.py:0 -#: code:addons/cetmix_tower_yaml/tests/test_tower_yaml_mixin.py:0 -#, python-format -msgid "Values must be a dictionary" -msgstr "Vrijednosti moraju biti dictionary" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Variables" -msgstr "Varijable" - -#. module: cetmix_tower_yaml -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_mixin.py:0 -#: code:addons/cetmix_tower_yaml/tests/test_tower_yaml_mixin.py:0 -#, python-format -msgid "Wrong value for 'access_level' key: %(acv)s" -msgstr "Pogrešna vrijednost za ključ 'access_level': %(acv)s" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_command_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_file_template_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_plan_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_server_template_view_form -msgid "YAML" -msgstr "" - -#. module: cetmix_tower_yaml -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "YAML file cannot be decoded properly" -msgstr "YAML datoteku nije moguće pročitati ili dekodirati" - -#. module: cetmix_tower_yaml -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "" -"YAML file version is not supported. You may need to update the Cetmix Tower " -"Yaml module." -msgstr "" -"Verzija YAML datoteke nije podržana. Možda morate ažurirati Cetmix Tower " -"Yaml modul." - -#. module: cetmix_tower_yaml -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_mixin.py:0 -#: code:addons/cetmix_tower_yaml/tests/test_tower_yaml_mixin.py:0 -#, python-format -msgid "" -"YAML version is higher than version supported by your Cetmix Tower instance." -" %(code_version)s > %(tower_version)s" -msgstr "" -"YAML verzija je viša od verzije podržane na vašoj Cetmix Tower instanci. " -"%(code_version)s>%(tower_version)s" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_command__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_file_template__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_key__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_os__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan_line__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan_line_action__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_server_log__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_server_template__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_tag__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable_option__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable_value__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_mixin__yaml_code -msgid "Yaml Code" -msgstr "YAML kod" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__yaml_file -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__yaml_file -msgid "Yaml File" -msgstr "YAML datoteka" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__yaml_file_name -msgid "Yaml File Name" -msgstr "YAML naziv datoteke" - -#. module: cetmix_tower_yaml -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "Yaml file doesn't contain valid data" -msgstr "Yaml datoteka ne sadrži valjane podatke" - -#. module: cetmix_tower_yaml -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_mixin.py:0 -#, python-format -msgid "You are not allowed to create records from YAML" -msgstr "Nije vam dozvoljeno kreiranje zapisa pomoću YAML datoteka" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_command_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_file_template_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_plan_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_server_template_view_form -msgid "You must be a member of the \"YAML/Export\" group to export data as YAML." -msgstr "Morate bit član \"YAML/Izvoz\" grupe za izvoz podataka u YAML." diff --git a/addons/cetmix_tower_yaml/i18n/it.po b/addons/cetmix_tower_yaml/i18n/it.po deleted file mode 100644 index 7442838..0000000 --- a/addons/cetmix_tower_yaml/i18n/it.po +++ /dev/null @@ -1,1069 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * cetmix_tower_yaml -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 16.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: \n" -"PO-Revision-Date: 2025-11-14 09:22+0100\n" -"Last-Translator: \n" -"Language-Team: Italian \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: it\n" -"Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Poedit 2.3\n" - -#. module: cetmix_tower_yaml -#: model:res.groups,comment:cetmix_tower_yaml.group_export -msgid "" -"\n" -" Export data to YAML.\n" -" " -msgstr "" -"\n" -" Esporta dati a YAML.\n" -" " - -#. module: cetmix_tower_yaml -#: model:res.groups,comment:cetmix_tower_yaml.group_import -msgid "" -"\n" -" Import data from YAML.\n" -" " -msgstr "" -"\n" -" Importa dati da YAML.\n" -" " - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "'%s' is not a valid model" -msgstr "'%s' non è un modello valido" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#, python-format -msgid "'invalid_model' is not a valid model" -msgstr "'invalid_model' non è un modello valido" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "" -"Important: To maintain data consistency, the following\n" -" model records will always be updated if they exist in Odoo:" -msgstr "Importante: per mantenere la consistenza dei dati, i recod del modello seguenti verranno sempre aggiornati se esistono in Odoo:" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__add_manifest -msgid "Add Manifest" -msgstr "Aggiungi manifest" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__explode_child_records -msgid "Add entire child record definitions to the exported YAML file. Otherwise only references to child records will be added." -msgstr "Aggiungere le definizioni di tutti i record figli allo YAML esportato. Altrimenti solo i riferimenti ai record figli verranno aggiunti." - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__file_prefix -msgid "Add prefix to the exported YAML file name when this template is selected" -msgstr "Aggiungi prefisso al nome file YAML esportato quando è selezionato questo modello" - -#. module: cetmix_tower_yaml -#: model:res.groups,name:cetmix_tower_yaml.group_export -#: model:res.groups,name:cetmix_tower_yaml.group_import -msgid "Allow" -msgstr "Consenti" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_author_string -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Author" -msgstr "Autore" - -#. module: cetmix_tower_yaml -#: model:ir.model.constraint,message:cetmix_tower_yaml.constraint_cx_tower_yaml_manifest_author_yaml_manifest_author_name_uniq -msgid "Author name must be unique." -msgstr "il nome autore deve essere univoco." - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_author_ids -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__author_ids -msgid "Authors" -msgstr "Autori" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_command -msgid "Cetmix Tower Command" -msgstr "Comando Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_file -msgid "Cetmix Tower File" -msgstr "File Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_file_template -msgid "Cetmix Tower File Template" -msgstr "Modello file Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_plan -msgid "Cetmix Tower Flight Plan" -msgstr "Piano di volo Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_plan_line -msgid "Cetmix Tower Flight Plan Line" -msgstr "Riga piano di volo Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_plan_line_action -msgid "Cetmix Tower Flight Plan Line Action" -msgstr "Azione riga piano di volo Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_key -msgid "Cetmix Tower Key/Secret Storage" -msgstr "Archivio chiave/segreto Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_os -msgid "Cetmix Tower Operating System" -msgstr "Sistema operativo Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_key_value -msgid "Cetmix Tower Secret Value Storage" -msgstr "Archivio valore segreto Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_server -msgid "Cetmix Tower Server" -msgstr "Server Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_server_log -msgid "Cetmix Tower Server Log" -msgstr "Registro server Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_server_template -msgid "Cetmix Tower Server Template" -msgstr "Modello server Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_shortcut -msgid "Cetmix Tower Shortcut" -msgstr "Scorciatoia Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_tag -msgid "Cetmix Tower Tag" -msgstr "Etichetta Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_variable -msgid "Cetmix Tower Variable" -msgstr "Variabile Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_variable_option -msgid "Cetmix Tower Variable Options" -msgstr "Opzioni variabile Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_variable_value -msgid "Cetmix Tower Variable Values" -msgstr "Valori variabile Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_export_wiz_download -msgid "Cetmix Tower YAML Export File Download" -msgstr "Scarico file esportazione YAML Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_export_wiz -msgid "Cetmix Tower YAML Export Wizard" -msgstr "Procedura guidata esportazione YAML Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_import_wiz -msgid "Cetmix Tower YAML Import Wizard" -msgstr "Procedura guidata importazione YAML Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_import_wiz_upload -msgid "Cetmix Tower YAML Import Wizard Upload" -msgstr "Aggiornamento procedura guidata importazione YAML Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_mixin -msgid "Cetmix Tower YAML rendering mixin" -msgstr "Mixin compilazione YAML Cetmix Tower" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_download_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_upload_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Close" -msgstr "Chiudi" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Code preview" -msgstr "Anteprima codice" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_author_string -msgid "Comma-separated list" -msgstr "Elenco separato da virgola" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields.selection,name:cetmix_tower_yaml.selection__cx_tower_yaml_import_wiz__if_record_exists__create -msgid "Create a new record" -msgstr "Crea un nuovo record" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__create_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__create_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__create_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__create_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_author__create_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__create_uid -msgid "Created by" -msgstr "Creato da" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__create_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__create_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__create_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__create_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_author__create_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__create_date -msgid "Created on" -msgstr "Creato il" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_currency -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_currency -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__currency -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Currency" -msgstr "Valuta" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__currency -msgid "Currency for pricing information." -msgstr "Valuta per le informazioni di prezzo." - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py:0 -#, python-format -msgid "Currency is required when price is specified" -msgstr "La valuta è richiesta quando è indicato il prezzo" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_template.py:0 -#, python-format -msgid "Custom" -msgstr "Personalizzato" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__license_text -msgid "Custom license text when license type is Custom." -msgstr "Testo licenza personalizzata quantdo il tipo licenza è personalizzato." - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_description -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_description -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Description" -msgstr "Descrizione" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "Detailed description (optional)" -msgstr "Descrizione dettagliata (opzionale)" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_author__display_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__display_name -msgid "Display Name" -msgstr "Nome visualizzato" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#, python-format -msgid "Error creating record '%(reference)s' in model '%(model)s': %(error)s" -msgstr "Errore durante la creazione del record '%(reference)s' nel modello '%(model)s': %(error)s" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#, python-format -msgid "Error updating record %(reference)s: %(error)s" -msgstr "Errore durante l'aggiornamento del record %(reference)s: %(error)s" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_template.py:0 -#, python-format -msgid "Euro" -msgstr "Euro" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "" -"Existing record will be updated with the new data. Related records, present in the YAML code, will be updated too.\n" -" If any of those related records doesn't exist, it will be created automatically." -msgstr "" -"Il record esistente verrà aggiornato con i dati sucessivi. Anche il record relativo, presente nel record YAML, verrà aggiornato.\n" -" Se uno dei record collegati non esiste, verrà creato automaticamente." - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__explode_child_records -msgid "Explode Child Records" -msgstr "Esplodi record figli" - -#. module: cetmix_tower_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_command_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_file_template_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_key_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_os_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_plan_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_scheduled_task_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_server_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_server_template_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_shortcut_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_tag_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_variable_export_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_variable_value_export_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_command_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_file_template_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_plan_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_server_template_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_server_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_shortcut_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.view_cx_tower_scheduled_task_view_form -msgid "Export YAML" -msgstr "Esporta YAML" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_mixin.py:0 -#, python-format -msgid "Failed to convert dictionary to YAML: %(error)s" -msgstr "Conversione dizionario in YAML fallita: %(error)s" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py:0 -#, python-format -msgid "Failed to encode YAML content. Please ensure all characters are UTF-8 compatible." -msgstr "Codifica contenuto YAML fallita. Assicurarsi che tutti i caratteri sia compatibili UTF-8." - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__file_name -msgid "File Name" -msgstr "Nome file" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "File is not a valid base64-encoded file" -msgstr "Il file non è un file codificato in base64 valido" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__file_prefix -msgid "File prefix" -msgstr "Prefisso file" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#, python-format -msgid "Following secrets are used in the code:
%(secrets)s" -msgstr "I seguenti segreti vengono utilizzati nel codice:
%(secrets)s" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "Generate YAML file" -msgstr "Genera file YAML" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_author__id -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__id -msgid "ID" -msgstr "ID" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__if_record_exists -msgid "If Record Exists" -msgstr "Se esiste il record" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Import" -msgstr "Importa" - -#. module: cetmix_tower_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_cx_tower_yaml_import_wiz_upload -#: model:ir.ui.menu,name:cetmix_tower_yaml.menu_cetmix_tower_yaml_import -msgid "Import YAML" -msgstr "Importa YAML" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#, python-format -msgid "Import result: %(model)s" -msgstr "Importa risultato: %(model)s" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Information" -msgstr "Informazione" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "Invalid YAML file" -msgstr "File YAML non valido" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Key/Secrets" -msgstr "Chiavi/segreti" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_author____last_update -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl____last_update -msgid "Last Modified on" -msgstr "Ultima modifica il" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__write_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__write_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__write_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__write_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_author__write_uid -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__write_uid -msgid "Last Updated by" -msgstr "Ultimo aggiornamento di" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__write_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__write_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__write_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__write_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_author__write_date -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__write_date -msgid "Last Updated on" -msgstr "Ultimo aggiornamento il" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_name -msgid "Leave this field blank if you don't want to create a manifest" -msgstr "Lasciare questo campo vuoto se non si vuole creare un manifest" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_license -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_license -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__license -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "License" -msgstr "Licenza" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_license_text -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__license_text -msgid "License Text" -msgstr "Testo licenza" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "License and pricing" -msgstr "Licenza e prezzo" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_license_text -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "License text" -msgstr "Testo licenza" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py:0 -#, python-format -msgid "License text is required for a custom license" -msgstr "Il testo licenza è richiesto per una licenza personalizzata" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__license -msgid "License used for the code snippet." -msgstr "Licenza usata per l'esempio di codice." - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__author_ids -msgid "List of author names to include in the YAML manifest." -msgstr "Elenco dei nomi degli autori da includere nel manifesto YAML." - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__secret_list -msgid "List of secrets present in the YAML file (formatted as HTML list)" -msgstr "Elenco dei segreti presenti nel file YAML (formattati come una elenco HTML)" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "Manifest" -msgstr "Manifest" - -#. module: cetmix_tower_yaml -#: model:ir.ui.menu,name:cetmix_tower_yaml.menu_yaml_manifest_author_action -msgid "Manifest Authors" -msgstr "Autori manifest" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_template_id -msgid "Manifest Template" -msgstr "Modello manifest" - -#. module: cetmix_tower_yaml -#: model:ir.ui.menu,name:cetmix_tower_yaml.menu_yaml_manifest_template -msgid "Manifest Templates" -msgstr "Modelli manifest" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "Model '%s' does not support YAML import" -msgstr "Il modello '%s' non supporta l'importazione YAML" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#, python-format -msgid "Model 'command_run_wizard' does not support YAML import" -msgstr "Il modello 'command_run_wizard' non supporta l'importazione YAML" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__model_names -msgid "Model Names" -msgstr "Nomi modello" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__model_names -msgid "Models to create records in" -msgstr "Modelli in cui creare i record" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_author__name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__name -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Name" -msgstr "Nome" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__name -msgid "Name of the manifest template." -msgstr "Nome del modello manifest." - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py:0 -#, python-format -msgid "No YAML code is present." -msgstr "Codice YAML non presente." - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py:0 -#, python-format -msgid "No model or records selected" -msgstr "Nessun modello o record selezionato" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#, python-format -msgid "No records were created or updated" -msgstr "Nessun record è stato creato o aggiornato" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py:0 -#, python-format -msgid "No valid records selected" -msgstr "Nessun record valido selezionato" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "OSs" -msgstr "SO" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__preview_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__preview_code -msgid "Preview Code" -msgstr "Anteprima codice" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "Preview code" -msgstr "Anteprima codice" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_price -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_price -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Price" -msgstr "Prezzo" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_upload_view_form -msgid "Process" -msgstr "Processo" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_template.py:0 -#, python-format -msgid "Provide Custom License Text when License is set to 'Custom'." -msgstr "Fornisce un testo licenza personalizzato quando la licenza è impostata a \"Personalizzata\"." - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#, python-format -msgid "Record Import" -msgstr "Importa record" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "Record model is missing for record %s" -msgstr "Manca il modello di record per il record %s" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#, python-format -msgid "Record reference is missing" -msgstr "Manca il riferimento al record" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#, python-format -msgid "Records of the following models were created or updated: %(models)s" -msgstr "Sono stati creati o aggiornati i record dei seguenti modelli: %(models)s" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__remove_empty_values -msgid "Remove Empty x2m Field Values" -msgstr "Rimozione dei valori campo x2m vuoti" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__remove_empty_values -msgid "Remove empty Many2one, Many2many and One2many field values from the exported YAML file." -msgstr "Rimozione dei valori campi Many2one, Many2many e One2many vuoti dal file YAML esportato." - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_scheduled_task -msgid "Scheduled Task" -msgstr "Lavoro schedulato" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__secret_list -msgid "Secret List" -msgstr "Elenco segreto" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "Select a pre-defined template" -msgstr "Seleziona un modello predefinito" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "Select a template to auto-populate manifest fields" -msgstr "Seleziona un modello per compilare automaticamente i campi del manifest" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_summary -msgid "Short summary that includes core information. 160 symbols max" -msgstr "Sommario breve che include le informazioni principali. Massimo 160 caratteri" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "Short summary, 160 symbols max" -msgstr "Sommario breve, massimo 160 caratteri" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields.selection,name:cetmix_tower_yaml.selection__cx_tower_yaml_import_wiz__if_record_exists__skip -msgid "Skip record" -msgstr "Salta record" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_name -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_name -msgid "Snippet Name" -msgstr "Nome snippet" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__yaml_file_name -msgid "Snippet file name without extension, eg 'my_snippet'" -msgstr "Nome del file dello snippet senza estensione, es. 'my_snippet'" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_summary -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_summary -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Summary" -msgstr "Sommario" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Tags" -msgstr "Etichette" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "This may overwrite existing records. Proceed?" -msgstr "Questo potrebbe sovrascrivere i record esistenti. Procedere?" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "" -"To create new entities instead of updating existing ones, remove or modify\n" -" the reference field in the YAML code for those entities." -msgstr "Per creare nuove entità anziché aggiornare le esistenti, rimuovere o modificare il campo reference nel codice YAML per quelle entità." - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__preview_code -msgid "Toggle to show or hide YAML code preview" -msgstr "Azionare per visualizzare o nascondere l'anteprima del codice YAML" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_template.py:0 -#, python-format -msgid "US Dollar" -msgstr "Dollaro USA" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields.selection,name:cetmix_tower_yaml.selection__cx_tower_yaml_import_wiz__if_record_exists__update -msgid "Update existing record" -msgstr "Aggiorna record esistente" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_version -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "Use the Major.Minor.Patch format, e.g. 1.2.3" -msgstr "Usare il formato Major.Minor.Patch, es. 1.2.3" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_mixin.py:0 -#: code:addons/cetmix_tower_yaml/tests/test_tower_yaml_mixin.py:0 -#, python-format -msgid "Values must be a dictionary" -msgstr "I valori devono essere un dizionario" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Variable Options" -msgstr "Opzioni variabile" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Variables" -msgstr "Variabili" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_version -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_version -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__version -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Version" -msgstr "Versione" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__version -msgid "Version in Major.Minor.Patch format, e.g. 1.0.0" -msgstr "Versione nel formato Major.Minor.Patch, es. 1.0.0" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_export_wiz.py:0 -#, python-format -msgid "Version must be in format Major.Minor.Patch, e.g. 1.2.3" -msgstr "La versione deve essere nel formato Major.Minor.Patch, es. 1.2.3" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_template.py:0 -#, python-format -msgid "Version must be in the Major.Minor.Patch format, e.g. 1.2.3" -msgstr "La versione deve essere nel formato Major.Minor.Patch, es. 1.2.3" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__manifest_website -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__manifest_website -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__website -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_import_wiz_view_form -msgid "Website" -msgstr "Sito web" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_manifest_tmpl__website -msgid "Website URL for the manifest." -msgstr "URL sito web per il manifest." - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,help:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__if_record_exists -msgid "What to do if record with the same reference already exists" -msgstr "Cosa fare se esiste già un record con lo stesso riferimento" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_mixin.py:0 -#: code:addons/cetmix_tower_yaml/tests/test_tower_yaml_mixin.py:0 -#, python-format -msgid "Wrong value for 'access_level' key: %(acv)s" -msgstr "Valore errato per la chiave 'access_level': %(acv)s" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_command_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_file_template_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_plan_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_server_template_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_server_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_shortcut_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.view_cx_tower_scheduled_task_view_form -msgid "YAML" -msgstr "YAML" - -#. module: cetmix_tower_yaml -#: model:ir.module.category,name:cetmix_tower_yaml.ir_module_category_tower_yaml_export -msgid "YAML Export" -msgstr "Esporta YAML" - -#. module: cetmix_tower_yaml -#: model:ir.ui.menu,name:cetmix_tower_yaml.menu_yaml_settings_root -msgid "YAML Export/Import" -msgstr "Esporta/Importa YAML" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__yaml_file_name -msgid "YAML File Name" -msgstr "Nome file YAML" - -#. module: cetmix_tower_yaml -#: model:ir.module.category,name:cetmix_tower_yaml.ir_module_category_tower_yaml_import -msgid "YAML Import" -msgstr "Importa YAML" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_manifest_author -msgid "YAML Manifest Author" -msgstr "Autore manifest YAML" - -#. module: cetmix_tower_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_yaml_manifest_author -msgid "YAML Manifest Authors" -msgstr "Autori manifest YAML" - -#. module: cetmix_tower_yaml -#: model:ir.model,name:cetmix_tower_yaml.model_cx_tower_yaml_manifest_tmpl -msgid "YAML Manifest Template" -msgstr "Modello manifest YAML" - -#. module: cetmix_tower_yaml -#: model:ir.actions.act_window,name:cetmix_tower_yaml.action_yaml_manifest_template -msgid "YAML Manifest Templates" -msgstr "Modelli manifest YAML" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "YAML file cannot be decoded properly" -msgstr "Il file YAML non può essere decodificato in modo corretto" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "YAML file doesn't contain any records" -msgstr "Il file YAML non contiene nessun record" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "YAML version is higher than version supported by your Cetmix Tower instance. %(code_version)s > %(tower_version)s" -msgstr "La versione YAML è successiva a quella supportata dalla tua istanza Cetmix Tower. %(code_version)s > %(tower_version)s" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_command__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_file__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_file_template__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_key__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_key_value__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_os__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan_line__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_plan_line_action__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_scheduled_task__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_server__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_server_log__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_server_template__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_shortcut__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_tag__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable_option__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_variable_value__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz__yaml_code -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_mixin__yaml_code -msgid "Yaml Code" -msgstr "Codice YAML" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__yaml_file -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_import_wiz_upload__yaml_file -msgid "Yaml File" -msgstr "File YAML" - -#. module: cetmix_tower_yaml -#: model:ir.model.fields,field_description:cetmix_tower_yaml.field_cx_tower_yaml_export_wiz_download__yaml_file_name -msgid "Yaml File Name" -msgstr "Nome file YAML" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py:0 -#: code:addons/cetmix_tower_yaml/wizards/cx_tower_yaml_import_wiz_upload.py:0 -#, python-format -msgid "Yaml file doesn't contain valid data" -msgstr "Il file YAML non contiene dati validi" - -#. module: cetmix_tower_yaml -#. odoo-python -#: code:addons/cetmix_tower_yaml/models/cx_tower_yaml_mixin.py:0 -#, python-format -msgid "You are not allowed to create records from YAML" -msgstr "Non si è autorizzati a creare record da YAML" - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_command_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_file_template_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_plan_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_server_template_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_server_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_shortcut_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.view_cx_tower_scheduled_task_view_form -msgid "You must be a member of the \"YAML/Export\" group to export data as YAML." -msgstr "Bisogna appartenere al gruppo \"YAML/Export\" per esportare dati in YAML." - -#. module: cetmix_tower_yaml -#: model_terms:ir.ui.view,arch_db:cetmix_tower_yaml.cx_tower_yaml_export_wiz_view_form -msgid "my_snippet.yaml" -msgstr "my_snippet.yaml" - -#~ msgid "" -#~ "After import, please check and provide secret values if needed for the " -#~ "following secrets: %(secrets)s" -#~ msgstr "" -#~ "Dopo l'importazione, controllare e fornire i valori segreti, se " -#~ "necessario, per i seguenti segreti: %(secrets)s" - -#~ msgid "Comment" -#~ msgstr "Commento" - -#~ msgid "Comment to be added to the beginning of exported YAML file" -#~ msgstr "Commento da aggiungere all'inizio del file YAML esportato" - -#~ msgid "Cetmix Tower YAML" -#~ msgstr "YAML Cetmix Tower" - -#~ msgid "Cetmix Tower private key storage" -#~ msgstr "Deposito chiave privata Cetmix Tower" - -#~ msgid "" -#~ "If enabled, existing records will be updated with the new data. " -#~ "Otherwise, new records will be created." -#~ msgstr "" -#~ "Se abilitata, i record esistenti verranno aggiornati con i nuovi dati. " -#~ "altrimenti, verranno creati nuovi record." - -#~ msgid "Invalid model specified in the YAML file" -#~ msgstr "Modello non valido indicato nel file YAML" - -#~ msgid "Model" -#~ msgstr "Modello" - -#~ msgid "Open Existing Record" -#~ msgstr "Apri record esistente" - -#~ msgid "Record" -#~ msgstr "Record" - -#~ msgid "This will create a new record. Proceed?" -#~ msgstr "Questo creerà un nuovo record. Procedere?" - -#~ msgid "" -#~ "YAML file version is not supported. You may need to update the Cetmix " -#~ "Tower Yaml module." -#~ msgstr "" -#~ "La versione del file YAML non è supportata. Bisogna aggiornare il modulo " -#~ "YAML Cetmix Tower." - -#~ msgid "cx.tower.yaml.import.wiz" -#~ msgstr "cx.tower.yaml.import.wiz" - -#~ msgid "Add entire related record data instead of just a reference" -#~ msgstr "" -#~ "Aggiungere tutti i dati del record correlato invece di un solo riferimento" - -#~ msgid "Explode" -#~ msgstr "Esplodi" diff --git a/addons/cetmix_tower_yaml/migrations/16.0.1.4.1/post-migration.py b/addons/cetmix_tower_yaml/migrations/16.0.1.4.1/post-migration.py deleted file mode 100644 index 8238759..0000000 --- a/addons/cetmix_tower_yaml/migrations/16.0.1.4.1/post-migration.py +++ /dev/null @@ -1,19 +0,0 @@ -def migrate(cr, version): - """ - Normalize existing license values to lowercase. - Runs only on upgrade (version != False). - """ - if not version: - return - # Skip rows already lowercase for efficiency - cr.execute( - """ - UPDATE cx_tower_yaml_manifest_tmpl - SET license = LOWER(TRIM(license)) - WHERE license IS NOT NULL - AND ( - license <> LOWER(license) - OR license <> TRIM(license) - ) - """ - ) diff --git a/addons/cetmix_tower_yaml/models/__init__.py b/addons/cetmix_tower_yaml/models/__init__.py deleted file mode 100644 index 9d7745e..0000000 --- a/addons/cetmix_tower_yaml/models/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -from . import cx_tower_yaml_mixin -from . import cx_tower_command -from . import cx_tower_file_template -from . import cx_tower_tag -from . import cx_tower_plan -from . import cx_tower_plan_line -from . import cx_tower_plan_line_action -from . import cx_tower_variable -from . import cx_tower_variable_option -from . import cx_tower_variable_value -from . import cx_tower_os -from . import cx_tower_server_template -from . import cx_tower_key -from . import cx_tower_key_value -from . import cx_tower_server_log -from . import cx_tower_shortcut -from . import cx_tower_scheduled_task -from . import cx_tower_file -from . import cx_tower_server -from . import cx_tower_yaml_manifest_template -from . import cx_tower_yaml_manifest_author diff --git a/addons/cetmix_tower_yaml/models/cx_tower_command.py b/addons/cetmix_tower_yaml/models/cx_tower_command.py deleted file mode 100644 index 7a02e39..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_command.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerCommand(models.Model): - _name = "cx.tower.command" - _inherit = ["cx.tower.command", "cx.tower.yaml.mixin"] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "access_level", - "name", - "action", - "allow_parallel_run", - "note", - "os_ids", - "tag_ids", - "path", - "file_template_id", - "flight_plan_id", - "code", - "server_status", - "variable_ids", - "secret_ids", - "no_split_for_sudo", - "if_file_exists", - "disconnect_file", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_file.py b/addons/cetmix_tower_yaml/models/cx_tower_file.py deleted file mode 100644 index 983fa40..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_file.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerFile(models.Model): - _name = "cx.tower.file" - _inherit = ["cx.tower.file", "cx.tower.yaml.mixin"] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "name", - "source", - "file_type", - "server_dir", - "code", - "file", - "variable_ids", - "secret_ids", - "template_id", - "keep_when_deleted", - "auto_sync", - "auto_sync_interval", - "sync_date_next", - "sync_date_last", - "server_response", - ] - return res - - def _post_create_write(self, op_type="write"): - # Do not pull/push files if they are being created from YAML - if self.env.context.get("from_yaml"): - return - super()._post_create_write(op_type) - - def _prepare_record_for_yaml(self): - """ - Override to drop file `code` when the source is 'server'. - """ - record_dict = super()._prepare_record_for_yaml() - - if record_dict.get("source") == "server": - record_dict["code"] = False - - return record_dict diff --git a/addons/cetmix_tower_yaml/models/cx_tower_file_template.py b/addons/cetmix_tower_yaml/models/cx_tower_file_template.py deleted file mode 100644 index 12572df..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_file_template.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerFileTemplate(models.Model): - _name = "cx.tower.file.template" - _inherit = ["cx.tower.file.template", "cx.tower.yaml.mixin"] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "name", - "source", - "file_type", - "server_dir", - "file_name", - "keep_when_deleted", - "tag_ids", - "note", - "code", - "variable_ids", - "secret_ids", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_jet_action.py b/addons/cetmix_tower_yaml/models/cx_tower_jet_action.py deleted file mode 100644 index 2af9459..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_jet_action.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerJetAction(models.Model): - _name = "cx.tower.jet.action" - _inherit = [ - "cx.tower.jet.action", - "cx.tower.yaml.mixin", - ] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "name", - "note", - "priority", - "access_level", - "state_from_id", - "state_transit_id", - "state_to_id", - "state_error_id", - "plan_id", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_jet_state.py b/addons/cetmix_tower_yaml/models/cx_tower_jet_state.py deleted file mode 100644 index f4b6801..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_jet_state.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerJetState(models.Model): - _name = "cx.tower.jet.state" - _inherit = [ - "cx.tower.jet.state", - "cx.tower.yaml.mixin", - ] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "name", - "sequence", - "access_level", - "color", - "note", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_jet_template.py b/addons/cetmix_tower_yaml/models/cx_tower_jet_template.py deleted file mode 100644 index 3dca470..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_jet_template.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerJetTemplate(models.Model): - _name = "cx.tower.jet.template" - _inherit = [ - "cx.tower.jet.template", - "cx.tower.yaml.mixin", - ] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "name", - "note", - "tag_ids", - "limit_per_server", - "show_in_create_wizard", - "plan_install_id", - "plan_uninstall_id", - "plan_clone_same_server_id", - "plan_clone_different_server_id", - "variable_value_ids", - "action_ids", - "template_requires_ids", - "waypoint_template_ids", - "server_log_ids", - "scheduled_task_ids", - ] - return res - - def _get_deferred_x2m_import_fields(self): - """Return x2m child records resolved after the main import pass.""" - return { - "template_requires_ids": { - "child_model": "cx.tower.jet.template.dependency", - "deferred_field": "template_required_id", - "target_model": "cx.tower.jet.template", - } - } diff --git a/addons/cetmix_tower_yaml/models/cx_tower_jet_template_dependency.py b/addons/cetmix_tower_yaml/models/cx_tower_jet_template_dependency.py deleted file mode 100644 index da00652..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_jet_template_dependency.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerJetTemplateDependency(models.Model): - _name = "cx.tower.jet.template.dependency" - _inherit = [ - "cx.tower.jet.template.dependency", - "cx.tower.yaml.mixin", - ] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "template_required_id", - "state_required_id", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_jet_waypoint_template.py b/addons/cetmix_tower_yaml/models/cx_tower_jet_waypoint_template.py deleted file mode 100644 index f9dfd73..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_jet_waypoint_template.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (C) 2025 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerJetWaypointTemplate(models.Model): - _name = "cx.tower.jet.waypoint.template" - _inherit = [ - "cx.tower.jet.waypoint.template", - "cx.tower.yaml.mixin", - ] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "name", - "sequence", - "access_level", - "jet_template_id", - "plan_create_id", - "plan_arrive_id", - "plan_leave_id", - "plan_delete_id", - "note", - ] - return res - - def _get_deferred_m2o_import_fields(self): - """Return m2o waypoint-template fields resolved after import.""" - return { - "jet_template_id": "cx.tower.jet.template", - } diff --git a/addons/cetmix_tower_yaml/models/cx_tower_key.py b/addons/cetmix_tower_yaml/models/cx_tower_key.py deleted file mode 100644 index 80797f6..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_key.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerKey(models.Model): - _name = "cx.tower.key" - _inherit = [ - "cx.tower.key", - "cx.tower.yaml.mixin", - ] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "name", - "key_type", - "note", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_key_value.py b/addons/cetmix_tower_yaml/models/cx_tower_key_value.py deleted file mode 100644 index f2a6b91..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_key_value.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerKeyValue(models.Model): - _name = "cx.tower.key.value" - _inherit = [ - "cx.tower.key.value", - "cx.tower.yaml.mixin", - ] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "key_id", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_os.py b/addons/cetmix_tower_yaml/models/cx_tower_os.py deleted file mode 100644 index 5706768..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_os.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerOs(models.Model): - _name = "cx.tower.os" - _inherit = [ - "cx.tower.os", - "cx.tower.yaml.mixin", - ] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "name", - "color", - "parent_id", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_plan.py b/addons/cetmix_tower_yaml/models/cx_tower_plan.py deleted file mode 100644 index b2cd039..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_plan.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerPlan(models.Model): - _name = "cx.tower.plan" - _inherit = ["cx.tower.plan", "cx.tower.yaml.mixin"] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "name", - "access_level", - "allow_parallel_run", - "color", - "tag_ids", - "note", - "on_error_action", - "custom_exit_code", - "line_ids", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_plan_line.py b/addons/cetmix_tower_yaml/models/cx_tower_plan_line.py deleted file mode 100644 index b28a997..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_plan_line.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerPlanLine(models.Model): - _name = "cx.tower.plan.line" - _inherit = ["cx.tower.plan.line", "cx.tower.yaml.mixin"] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "sequence", - "condition", - "use_sudo", - "path", - "command_id", - "action_ids", - "variable_ids", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_plan_line_action.py b/addons/cetmix_tower_yaml/models/cx_tower_plan_line_action.py deleted file mode 100644 index ce3e36d..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_plan_line_action.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerPlanLineAction(models.Model): - _name = "cx.tower.plan.line.action" - _inherit = ["cx.tower.plan.line.action", "cx.tower.yaml.mixin"] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "sequence", - "condition", - "value_char", - "action", - "custom_exit_code", - "variable_value_ids", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_scheduled_task.py b/addons/cetmix_tower_yaml/models/cx_tower_scheduled_task.py deleted file mode 100644 index 9f7c820..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_scheduled_task.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (C) 2025 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerScheduledTask(models.Model): - _name = "cx.tower.scheduled.task" - _inherit = ["cx.tower.scheduled.task", "cx.tower.yaml.mixin"] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "name", - "sequence", - "action", - "command_id", - "plan_id", - "interval_number", - "interval_type", - "next_call", - "last_call", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_scheduled_task_cv.py b/addons/cetmix_tower_yaml/models/cx_tower_scheduled_task_cv.py deleted file mode 100644 index 688d752..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_scheduled_task_cv.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright (C) 2025 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerScheduledTaskCv(models.Model): - _name = "cx.tower.scheduled.task.cv" - _inherit = [ - "cx.tower.scheduled.task.cv", - "cx.tower.yaml.mixin", - "cx.tower.reference.mixin", - ] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += ["variable_value_id"] - return res - - def _post_process_yaml_dict_values(self, values): - """Populate required child fields from the linked variable value.""" - res = super()._post_process_yaml_dict_values(values) - variable_value_id = res.get("variable_value_id") - if variable_value_id: - variable_value = self.env["cx.tower.variable.value"].browse( - variable_value_id - ) - if variable_value.exists(): - res.update( - { - "name": variable_value.name, - "variable_id": variable_value.variable_id.id, - "option_id": variable_value.option_id.id or False, - "value_char": variable_value.value_char, - } - ) - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_server.py b/addons/cetmix_tower_yaml/models/cx_tower_server.py deleted file mode 100644 index 0633077..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_server.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerServer(models.Model): - _name = "cx.tower.server" - _inherit = [ - "cx.tower.server", - "cx.tower.yaml.mixin", - ] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "name", - "ip_v4_address", - "ip_v6_address", - "skip_host_key", - "color", - "os_id", - "tag_ids", - "url", - "note", - "ssh_port", - "ssh_username", - "ssh_key_id", - "ssh_auth_mode", - "use_sudo", - "variable_value_ids", - "secret_ids", - "server_log_ids", - "shortcut_ids", - "scheduled_task_ids", - "plan_delete_id", - "file_ids", - "command_ids", - "plan_ids", - ] - return res - - def _get_force_x2m_resolve_models(self): - res = super()._get_force_x2m_resolve_models() - - # This is useful to avoid duplicating existing plans - res += [ - "cx.tower.shortcut", - "cx.tower.scheduled.task", - "cx.tower.command", - "cx.tower.plan", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_server_log.py b/addons/cetmix_tower_yaml/models/cx_tower_server_log.py deleted file mode 100644 index 34ff785..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_server_log.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerServerLog(models.Model): - _name = "cx.tower.server.log" - _inherit = [ - "cx.tower.server.log", - "cx.tower.yaml.mixin", - ] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "name", - "log_type", - "command_id", - "use_sudo", - "file_template_id", - "file_id", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_server_template.py b/addons/cetmix_tower_yaml/models/cx_tower_server_template.py deleted file mode 100644 index 1390a06..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_server_template.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerServerTemplate(models.Model): - _name = "cx.tower.server.template" - _inherit = [ - "cx.tower.server.template", - "cx.tower.yaml.mixin", - ] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "name", - "color", - "os_id", - "tag_ids", - "note", - "ssh_port", - "ssh_username", - "ssh_key_id", - "ssh_auth_mode", - "use_sudo", - "variable_value_ids", - "server_log_ids", - "shortcut_ids", - "scheduled_task_ids", - "flight_plan_id", - "plan_delete_id", - ] - return res - - def _get_force_x2m_resolve_models(self): - res = super()._get_force_x2m_resolve_models() - - # Add Flight Plan in order to always try to use existing one - # This is useful to avoid duplicating existing plans - res += ["cx.tower.plan", "cx.tower.shortcut", "cx.tower.scheduled.task"] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_shortcut.py b/addons/cetmix_tower_yaml/models/cx_tower_shortcut.py deleted file mode 100644 index 51a2120..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_shortcut.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerShortcut(models.Model): - _name = "cx.tower.shortcut" - _inherit = ["cx.tower.shortcut", "cx.tower.yaml.mixin"] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "name", - "sequence", - "access_level", - "action", - "command_id", - "use_sudo", - "plan_id", - "note", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_tag.py b/addons/cetmix_tower_yaml/models/cx_tower_tag.py deleted file mode 100644 index d1fc446..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_tag.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerTag(models.Model): - _name = "cx.tower.tag" - _inherit = ["cx.tower.tag", "cx.tower.yaml.mixin"] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "name", - "color", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_variable.py b/addons/cetmix_tower_yaml/models/cx_tower_variable.py deleted file mode 100644 index 0a80468..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_variable.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerVariable(models.Model): - _name = "cx.tower.variable" - _inherit = ["cx.tower.variable", "cx.tower.yaml.mixin"] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "name", - "access_level", - "variable_type", - "option_ids", - "applied_expression", - "validation_pattern", - "validation_message", - "note", - "tag_ids", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_variable_option.py b/addons/cetmix_tower_yaml/models/cx_tower_variable_option.py deleted file mode 100644 index 81b3835..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_variable_option.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerVariableOption(models.Model): - _name = "cx.tower.variable.option" - _inherit = ["cx.tower.variable.option", "cx.tower.yaml.mixin"] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "sequence", - "access_level", - "name", - "value_char", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_variable_value.py b/addons/cetmix_tower_yaml/models/cx_tower_variable_value.py deleted file mode 100644 index 947d860..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_variable_value.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models - - -class CxTowerVariableValue(models.Model): - _name = "cx.tower.variable.value" - _inherit = ["cx.tower.variable.value", "cx.tower.yaml.mixin"] - - def _get_fields_for_yaml(self): - res = super()._get_fields_for_yaml() - res += [ - "sequence", - "access_level", - "variable_id", - "value_char", - "variable_ids", - "required", - ] - return res diff --git a/addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_author.py b/addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_author.py deleted file mode 100644 index e2dbbb5..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_author.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (C) 2025 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - - -from odoo import fields, models - - -class CxTowerYamlManifestAuthor(models.Model): - """Author of a YAML manifest (can be one or many).""" - - _name = "cx.tower.yaml.manifest.author" - - _sql_constraints = [ - ( - "yaml_manifest_author_name_uniq", - "unique(name)", - "Author name must be unique.", - ) - ] - _description = "YAML Manifest Author" - _order = "name" - - name = fields.Char(required=True, translate=False) diff --git a/addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_template.py b/addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_template.py deleted file mode 100644 index f0f3d57..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_yaml_manifest_template.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright (C) 2025 Cetmix OÜ -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). - -import re - -from odoo import _, api, fields, models -from odoo.exceptions import ValidationError - - -class CxTowerYamlManifestTemplate(models.Model): - """Pre-defined YAML manifest template storing common metadata - such as authors, website, license, and currency for reuse - during YAML exports.""" - - _name = "cx.tower.yaml.manifest.tmpl" - _description = "YAML Manifest Template" - _order = "name" - - name = fields.Char( - required=True, - help="Name of the manifest template.", - ) - website = fields.Char(help="Website URL for the manifest.") - - author_ids = fields.Many2many( - "cx.tower.yaml.manifest.author", - string="Authors", - help="List of author names to include in the YAML manifest.", - ) - - license = fields.Selection( - selection=lambda self: self._selection_license(), - help="License used for the code snippet.", - ) - license_text = fields.Text( - help="Custom license text when license type is Custom.", - ) - - currency = fields.Selection( - selection=lambda self: self._selection_currency(), - help="Currency for pricing information.", - ) - - version = fields.Char( - help="Version in Major.Minor.Patch format, e.g. 1.0.0", - default="1.0.0", - ) - - file_prefix = fields.Char( - string="File prefix", - help="Add prefix to the exported YAML file name when this template is selected", - ) - - @api.model - def _selection_license(self): - """Return available license options for manifest.""" - return [ - ("agpl-3", "AGPL-3"), - ("lgpl-3", "LGPL-3"), - ("mit", "MIT"), - ("custom", _("Custom")), - ] - - @api.model - def _selection_currency(self): - """Return available currency options for manifest pricing.""" - return [ - ("EUR", _("Euro")), - ("USD", _("US Dollar")), - ] - - @api.constrains("license", "license_text") - def _check_license_text_for_custom(self): - """Ensure that custom license text is provided when license is 'custom'.""" - for rec in self: - if rec.license == "custom" and not (rec.license_text or "").strip(): - raise ValidationError( - _("Provide Custom License Text when License is set to 'Custom'.") - ) - - @api.constrains("version") - def _check_version_format(self): - """Ensure the template version follows the x.y.z semantic format. - - The version must consist of three non-negative integers (major, minor, patch) - separated by dots—for example, “1.2.3”. Raises a ValidationError otherwise. - """ - semver = re.compile(r"^\d+\.\d+\.\d+$") - for rec in self: - if rec.version and not semver.match(rec.version): - raise ValidationError( - _("Version must be in the Major.Minor.Patch format, e.g. 1.2.3") - ) diff --git a/addons/cetmix_tower_yaml/models/cx_tower_yaml_mixin.py b/addons/cetmix_tower_yaml/models/cx_tower_yaml_mixin.py deleted file mode 100644 index c089e83..0000000 --- a/addons/cetmix_tower_yaml/models/cx_tower_yaml_mixin.py +++ /dev/null @@ -1,577 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -import logging - -import yaml - -from odoo import _, api, fields, models -from odoo.exceptions import AccessError, ValidationError - -_logger = logging.getLogger(__name__) - - -class CustomDumper(yaml.Dumper): - """Custom dumper to ensures code - is properly dumped in YAML - """ - - def represent_scalar(self, tag, value, style=None): - if isinstance(value, str) and "\n" in value: - style = "|" - return super().represent_scalar(tag, value, style) - - -class YamlExportCollector: - """ - Collector for YAML export. - Tracks unique records by their (model_name, reference) tuple to avoid duplicates. - """ - - def __init__(self): - """ - Initialize the collector. - """ - self.added_references = set() - - def add(self, key): - """ - Add a record to the collector if its reference is unique. - :param key: tuple, key of the record - """ - if key and key not in self.added_references: - self.added_references.add(key) - - def is_added(self, key): - """ - Check by (model, reference) tuple. - :param key: tuple, key of the record - :return: bool - """ - return key in self.added_references - - -class CxTowerYamlMixin(models.AbstractModel): - """Used to implement YAML rendering functions. - Inherit in your model in case you want to YAML instance of the records. - """ - - _name = "cx.tower.yaml.mixin" - _description = "Cetmix Tower YAML rendering mixin" - - # File format version in order to track compatibility - CETMIX_TOWER_YAML_VERSION = 1 - - # TO_YAML_* used to convert from Odoo field values to YAML - TO_YAML_ACCESS_LEVEL = {"1": "user", "2": "manager", "3": "root"} - - # TO_TOWER_* used to convert from YAML field values to Tower ones - TO_TOWER_ACCESS_LEVEL = {"user": "1", "manager": "2", "root": "3"} - - yaml_code = fields.Text( - compute="_compute_yaml_code", - inverse="_inverse_yaml_code", - groups="cetmix_tower_yaml.group_export,cetmix_tower_yaml.group_import", - ) - - def _compute_yaml_code(self): - """Compute YAML code based on model record data""" - - # This is used for the file name. - # Eg cx.tower.command record will have 'command_' prefix. - for record in self: - # We are reading field list for each record - # because list of fields can differ from record to record - record.yaml_code = self._convert_dict_to_yaml( - record._prepare_record_for_yaml() - ) - - def _inverse_yaml_code(self): - """Compose record based on provided YAML""" - for record in self: - if record.yaml_code: - record_yaml_dict = yaml.safe_load(record.yaml_code) - record_vals = record._post_process_yaml_dict_values(record_yaml_dict) - record.update(record_vals) - - @api.constrains("yaml_code") - def _check_yaml_code_write_access(self): - """ - Check if user has access to create records from YAML. - This is checked only when user already has access to export YAML. - Otherwise, the field is not accessible due to security group. - """ - if self.env.user.has_group("cetmix_tower_yaml.group_export") and ( - not self.env.user.has_group("cetmix_tower_yaml.group_import") - and not self.env.user._is_superuser() - ): - raise AccessError(_("You are not allowed to create records from YAML")) - - @api.model_create_multi - def create(self, vals_list): - # Handle validation error when field values are not valid - try: - return super().create(vals_list) - except ValueError as e: - raise ValidationError(str(e)) from e - - def write(self, vals): - # Handle validation error when field values are not valid - try: - return super().write(vals) - except ValueError as e: - raise ValidationError(str(e)) from e - - def action_open_yaml_export_wizard(self): - """Open YAML export wizard""" - - return { - "type": "ir.actions.act_window", - "res_model": "cx.tower.yaml.export.wiz", - "view_mode": "form", - "target": "new", - } - - def _convert_dict_to_yaml(self, values): - """Converts Python dictionary to YAML string. - - This is a helper function that is designed to be used - by any models that need to convert a dictionary to YAML. - - Args: - values (Dict): Dictionary containing data - to be converted to YAML format - Returns: - Text: YAML string - Raises: - ValidationError: If values is not a dictionary - or YAML conversion fails - """ - if not isinstance(values, dict): - raise ValidationError(_("Values must be a dictionary")) - try: - yaml_code = yaml.dump( - values, - Dumper=CustomDumper, - default_flow_style=False, - sort_keys=False, - ) - return yaml_code - except (yaml.YAMLError, UnicodeEncodeError) as e: - raise ValidationError( - _( - "Failed to convert dictionary" " to YAML: %(error)s", - error=str(e), - ) - ) from e - - def _prepare_record_for_yaml(self): - """Reads and processes current record before converting it to YAML - - Returns: - dict: values ready for YAML conversion - """ - self.ensure_one() - yaml_keys = self._get_fields_for_yaml() - record_dict = self.read(fields=yaml_keys)[0] - return self._post_process_record_values(record_dict) - - def _get_fields_for_yaml(self): - """Get ist of field to be present in YAML - - Set 'no_yaml_service_fields' context key to skip - service fields creation (cetmix_tower_yaml_version, cetmix_tower_model) - - Returns: - list(): list of fields to be used as YAML keys - """ - return ["reference"] - - def _get_force_x2m_resolve_models(self): - """List of models that will always try to be resolved - when referenced in x2m related fields. - - This is useful for models that should always use existing records - instead of creating new ones when referenced in x2m related fields. - Such as variables or tags. - - Returns: - List: list of models that will always try to be resolved - """ - return [ - "cx.tower.variable", - "cx.tower.variable.option", - "cx.tower.tag", - "cx.tower.os", - "cx.tower.key", - ] - - def _post_process_record_values(self, values): - """Post process record values - before converting them to YAML - - Args: - values (dict): values returned by 'read' method - - Context: - explode_related_record: if set will return entire record dictionary - not just a reference - remove_empty_values: if set will remove empty values from the record - - Returns: - dict(): processed values - """ - collector = self._context.get("yaml_collector") - ref = values.get("reference") - collector_key = (self._name, ref) if ref else None - - if collector and collector_key and collector.is_added(collector_key): - return {"reference": ref} - - # We don't need id because we are not using it - values.pop("id", None) - - # Add YAML format version and model - if not self._context.get("no_yaml_service_fields"): - model_name = self._name.replace("cx.tower.", "").replace(".", "_") - model_values = { - "cetmix_tower_model": model_name, - } - else: - model_values = {} - - # Parse access level - access_level = values.pop("access_level", None) - if access_level: - model_values.update( - {"access_level": self.TO_YAML_ACCESS_LEVEL[access_level]} - ) - - values = {**model_values, **values} - # Copy values to avoid modifying the original values - new_values = values.copy() - - # Check if we need to return a record dict or just a reference - # Use context value first, revert to the record setting if not defined - explode_related_record = self._context.get("explode_related_record") - - # Check if we need to remove empty values - # Currently only x2m fields are supported - remove_empty_values = self._context.get("remove_empty_values") - - # Post process m2o and x2m fields - for key, value in values.items(): - # IMPORTANT: Odoo naming patterns must be followed for related fields. - # This is why we are checking for the field name ending here. - # Further checks for the field type are done - # in _process_relation_field_value() - if key.endswith("_id") or key.endswith("_ids"): - if not value and remove_empty_values: - del new_values[key] - else: - processed_value = self.with_context( - explode_related_record=explode_related_record - )._process_relation_field_value(key, value, record_mode=True) - new_values.update({key: processed_value}) - - if collector and collector_key: - collector.add(collector_key) - - return new_values - - def _post_process_yaml_dict_values(self, values): - """Post process dictionary values generated from YAML code - - Args: - values (dict): Dictionary generated from YAML - - Returns: - dict(): Post-processed values - """ - - # Remove model data because it is not a field - if "cetmix_tower_model" in values: - values.pop("cetmix_tower_model") - - # Parse access level - if "access_level" in values: - values_access_level = values["access_level"] - access_level = self.TO_TOWER_ACCESS_LEVEL.get(values_access_level) - if access_level: - values.update({"access_level": access_level}) - else: - raise ValidationError( - _( - "Wrong value for 'access_level' key: %(acv)s", - acv=values_access_level, - ) - ) - - # Leave supported keys only - supported_keys = self._get_fields_for_yaml() - filtered_values = {k: v for k, v in values.items() if k in supported_keys} - - # Post process m2o fields - for key, value in filtered_values.items(): - # IMPORTANT: Odoo naming patterns must be followed for related fields. - # This is why we are checking for the field name ending here. - # Further checks for the field type are done - # in _process_relation_field_value() - if key.endswith("_id") or key.endswith("_ids"): - processed_value = self.with_context( - explode_related_record=True - )._process_relation_field_value(key, value, record_mode=False) - filtered_values.update({key: processed_value}) - - return filtered_values - - def _process_relation_field_value(self, field, value, record_mode=False): - """Post process One2many, Many2many or Many2one value - - Args: - field (Char): Field the value belongs to - value (Char): Value to process - record_mode (Bool): If True process value as a record value - else process value as a YAML value - Context: - explode_related_record: if set will return entire record dictionary - not just a reference - Returns: - dict() or Char: record dictionary if fetch_record else reference - """ - # Step 1: Return False if the value is not set or the field is not found - if not value: - return False - - field_obj = self._fields.get(field) - if not field_obj: - return False - - # Step 2: Return False if the field type doesn't match - # or comodel is not defined - field_type = field_obj.type - if ( - field_type not in ["one2many", "many2many", "many2one"] - or not field_obj.comodel_name - ): - return False - - comodel = self.env[field_obj.comodel_name] - explode_related_record = self._context.get("explode_related_record") - - # Step 3: process value based on the field type - if field_type == "many2one": - return self._process_m2o_value( - comodel, value, explode_related_record, record_mode - ) - if field_type in ["one2many", "many2many"]: - return self._process_x2m_values( - comodel, field_type, value, explode_related_record, record_mode - ) - - # Step 4: fall back if field type is not supported - return False - - def _process_m2o_value( - self, comodel, value, explode_related_record, record_mode=False - ): - """Post process many2one value - Args: - comodel (BaseClass): Model the value belongs to - value (Char): Value to process - explode_related_record (Bool): If True return entire record dict - instead of a reference - record_mode (Bool): If True process value as a record value - else process value as a YAML value - - Returns: - dict() or Char: record dictionary if fetch_record else reference - """ - - # -- (Record -> YAML) - if record_mode: - # Retrieve the record based on the ID provided in the value - record = comodel.browse(value[0]) - - # If the context specifies to explode the related record, - # return its dictionary representation - if explode_related_record: - return ( - record.with_context( - no_yaml_service_fields=True - )._prepare_record_for_yaml() - if record - else False - ) - - # Otherwise, return just the reference (or False if record does not exist) - return record.reference if record else False - - # -- (YAML -> Record) - # Step 1: Process value in normal mode - record = False - - # If the value is a string, it is treated as a reference - if isinstance(value, str): - reference = value - - # If the value is a dictionary, extract the reference from it - elif isinstance(value, dict): - reference = value.get("reference") - - record = self._update_or_create_related_record( - comodel, reference, value, create_immediately=True - ) - else: - return False - - # Step 2: Final fallback: attempt to retrieve the record by reference if set, - # return its ID or False - if not record and reference: - record = comodel.get_by_reference(reference) - return record.id if record else False - - def _process_x2m_values( - self, comodel, field_type, values, explode_related_record, record_mode=False - ): - """Post process many2many value - Args: - comodel (BaseClass): Model the value belongs to - field_type (Char): Field type - values (list()): Values to process - explode_related_record (Bool): If True return entire record dict - instead of a reference - record_mode (Bool): If True process value as a record value - else process value as a YAML value - - Returns: - dict() or Char: record dictionary if fetch_record else reference - """ - - # -- (Record -> YAML) - if record_mode: - record_list = [] - for value in values: - # Retrieve the record based on the ID provided in the value - record = comodel.browse(value) - - # If the context specifies to explode the related record, - # return its dictionary representation - if explode_related_record: - record_list.append( - record.with_context( - no_yaml_service_fields=True - )._prepare_record_for_yaml() - if record - else False - ) - - # Otherwise, return just the reference - # (or False if record does not exist) - else: - record_list.append(record.reference if record else False) - - return record_list - - # -- (YAML -> Record) - # Step 1: Process value in normal mode - record_ids = [] - - for value in values: - record = False - # If the value is a string, it is treated as a reference - if isinstance(value, str): - reference = value - - # If the value is a dictionary, extract the reference from it - elif isinstance(value, dict): - reference = value.get("reference") - record = self._update_or_create_related_record( - comodel, - reference, - value, - create_immediately=field_type == "many2many", - ) - - # Step 2: Final fallback: attempt to retrieve the record by reference - # Return record ID or False if reference is not defined - if not record and reference: - record = comodel.get_by_reference(reference) - - # Save record data - if record: - record_ids.append( - record if isinstance(record, tuple) else (4, record.id) - ) - - return record_ids - - def _update_or_create_related_record( - self, model, reference, values, create_immediately=False - ): - """Update related record with provided values or create a new one - - Args: - model (BaseModel): Related record model - values (dict()): Values to update existing/create new record - reference (Char): Record reference - create_immediately (Bool): If True create a new record immediately. - Used for Many2one fields. - - Context: - force_create_related_record (Bool): If True, create a new record - even if reference is provided. - - Returns: - record: Existing record or new record tuple - """ - - # If reference is found, retrieve the corresponding record - if reference and ( - model._name in self._get_force_x2m_resolve_models() - or not self._context.get("force_create_related_record") - ): - record = model.get_by_reference(reference) - # If the record exists, update it with the values from the dictionary - if record: - # Remove reference from values to avoid possible consequences - values.pop("reference", None) - record.with_context(from_yaml=True).write( - record._post_process_yaml_dict_values(values) - ) - - # If the record does not exist, create a new one - else: - if create_immediately: - record = model.with_context(from_yaml=True).create( - model._post_process_yaml_dict_values(values) - ) - else: - # Use "Create" service command tuple - record = (0, 0, model._post_process_yaml_dict_values(values)) - - # If there's no reference but value is a dict, create a new record - else: - if create_immediately: - # Only 'reference' provided, no other data: do not create, - # just log warning - if set(values.keys()) == {"reference"}: - _logger.warning( - "Attempted to import a record for model '%s' with reference " - "'%s', but only the 'reference' field was provided. " - "It is possible that this record has already been imported. " - "Creation will be skipped.", - model._name, - reference, - ) - return False - - record = model.with_context(from_yaml=True).create( - model._post_process_yaml_dict_values(values) - ) - else: - # Use "Create" service command tuple - record = (0, 0, model._post_process_yaml_dict_values(values)) - - # Return the record's ID if it exists, otherwise return False - return record or False diff --git a/addons/cetmix_tower_yaml/pyproject.toml b/addons/cetmix_tower_yaml/pyproject.toml deleted file mode 100644 index 4231d0c..0000000 --- a/addons/cetmix_tower_yaml/pyproject.toml +++ /dev/null @@ -1,3 +0,0 @@ -[build-system] -requires = ["whool"] -build-backend = "whool.buildapi" diff --git a/addons/cetmix_tower_yaml/readme/CONFIGURE.md b/addons/cetmix_tower_yaml/readme/CONFIGURE.md deleted file mode 100644 index 8c717e5..0000000 --- a/addons/cetmix_tower_yaml/readme/CONFIGURE.md +++ /dev/null @@ -1 +0,0 @@ -Please refer to the [official documentation](https://cetmix.com/tower) for detailed configuration instructions. diff --git a/addons/cetmix_tower_yaml/readme/DESCRIPTION.md b/addons/cetmix_tower_yaml/readme/DESCRIPTION.md deleted file mode 100644 index 2f07eba..0000000 --- a/addons/cetmix_tower_yaml/readme/DESCRIPTION.md +++ /dev/null @@ -1,3 +0,0 @@ -This module implements YAML format data import/export for [Cetmix Tower](https://cetmix.com/tower). - -Please refer to the [official documentation](https://cetmix.com/tower) for detailed information. diff --git a/addons/cetmix_tower_yaml/readme/HISTORY.md b/addons/cetmix_tower_yaml/readme/HISTORY.md deleted file mode 100644 index a9e2000..0000000 --- a/addons/cetmix_tower_yaml/readme/HISTORY.md +++ /dev/null @@ -1,69 +0,0 @@ -## 16.0.2.0.1 (2025-10-29) - -- Features: Improve the way secrets are listed in the YAML import widget. (5010) - - -## 16.0.1.4.2 (2025-10-06) - -- Bugfixes: Add the missing 'create' function decorator (4980) - - -## 16.0.1.4.1 (2025-08-26) - -- Bugfixes: Make selection values lowercase to simplify their management. (4896) - - -## 16.0.1.3.0 (2025-07-30) - -- Features: Optional behaviour when file uploaded by command already exists on the server. (4740) - - -## 16.0.1.1.4 (2025-07-08) - -- Bugfixes: Fix missing model names in YAML exports when exporting multiple commands with flight plans (4820) - - -## 16.0.1.1.3 (2025-07-07) - -- Bugfixes: Import servers with `Password` ssh authentication mode (4812) - - -## 16.0.1.1.1 (2025-06-23) - -- Features: YAML code optimisation (4728) - - -## 16.0.1.1.0 (2025-06-20) - -- Features: Export/import scheduled tasks to/from YAML. (4650) - - -## 16.0.1.0.5 (2025-05-21) - -- Features: Export/import secret values related to Server. (4696) - - -## 16.0.1.0.4 (2025-05-16) - -- Features: Export/import servers and files to/from YAML. (4670) - - -## 16.0.1.0.3 (2025-05-09) - -- Bugfixes: Non-critical issues and performance improvements. (4663) - - -## 16.0.1.0.2 (2025-04-30) - -- Features: User groups are visible without developer mode. (4642) - - -## 16.0.1.0.1 (2025-04-21) - -- Features: Export additional fields for shortcuts, variables and options. - Add action menu to export keys/secrets. (4602) - - -## 16.0.1.0.0 - -Release for Odoo 16.0 diff --git a/addons/cetmix_tower_yaml/readme/USAGE.md b/addons/cetmix_tower_yaml/readme/USAGE.md deleted file mode 100644 index 901f5a6..0000000 --- a/addons/cetmix_tower_yaml/readme/USAGE.md +++ /dev/null @@ -1 +0,0 @@ -Please refer to the [official documentation](https://cetmix.com/tower) for detailed usage instructions. diff --git a/addons/cetmix_tower_yaml/readme/newsfragments/.gitkeep b/addons/cetmix_tower_yaml/readme/newsfragments/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/addons/cetmix_tower_yaml/security/cetmix_tower_yaml_groups.xml b/addons/cetmix_tower_yaml/security/cetmix_tower_yaml_groups.xml deleted file mode 100644 index 3ff6ff0..0000000 --- a/addons/cetmix_tower_yaml/security/cetmix_tower_yaml_groups.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - YAML Export - - - - - YAML Import - - - - Allow - - - Export data to YAML. - - - - - Allow - - - Import data from YAML. - - - - diff --git a/addons/cetmix_tower_yaml/security/cx_tower_yaml_wizard_access_rules.xml b/addons/cetmix_tower_yaml/security/cx_tower_yaml_wizard_access_rules.xml deleted file mode 100644 index 97c3308..0000000 --- a/addons/cetmix_tower_yaml/security/cx_tower_yaml_wizard_access_rules.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - Creator only - - - [('create_uid', '=', user.id)] - - - - - Creator only - - - [('create_uid', '=', user.id)] - - - - - Creator only - - - [('create_uid', '=', user.id)] - - - - - Creator only - - - [('create_uid', '=', user.id)] - - - diff --git a/addons/cetmix_tower_yaml/security/ir.model.access.csv b/addons/cetmix_tower_yaml/security/ir.model.access.csv deleted file mode 100644 index bb6e5dd..0000000 --- a/addons/cetmix_tower_yaml/security/ir.model.access.csv +++ /dev/null @@ -1,9 +0,0 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_yaml_export_wizard,Export YAML,model_cx_tower_yaml_export_wiz,group_export,1,1,1,1 -access_yaml_export_wizard_download,Export YAML File,model_cx_tower_yaml_export_wiz_download,group_export,1,1,1,1 -access_yaml_import_wizard_upload,Import YAML,model_cx_tower_yaml_import_wiz_upload,group_import,1,1,1,1 -access_yaml_import_wizard,Import YAML,model_cx_tower_yaml_import_wiz,group_import,1,1,1,1 -access_manifest_tmpl_read_export,Manifest tmpl read (export),model_cx_tower_yaml_manifest_tmpl,cetmix_tower_yaml.group_export,1,0,0,0 -access_manifest_tmpl_admin,Manifest tmpl admin,model_cx_tower_yaml_manifest_tmpl,cetmix_tower_server.group_root,1,1,1,1 -access_manifest_author_read_export,Manifest author read (export),model_cx_tower_yaml_manifest_author,cetmix_tower_yaml.group_export,1,0,0,0 -access_manifest_author_admin,Manifest author admin,model_cx_tower_yaml_manifest_author,cetmix_tower_server.group_root,1,1,1,1 diff --git a/addons/cetmix_tower_yaml/static/description/icon.png b/addons/cetmix_tower_yaml/static/description/icon.png deleted file mode 100644 index 2507f553896c442455b02ed5fa06b72ab398a990..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22128 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 F{{#JqH_ZS5 diff --git a/addons/cetmix_tower_yaml/static/description/index.html b/addons/cetmix_tower_yaml/static/description/index.html deleted file mode 100644 index e12b94a..0000000 --- a/addons/cetmix_tower_yaml/static/description/index.html +++ /dev/null @@ -1,534 +0,0 @@ - - - - - -Cetmix Tower YAML - - - -
-

Cetmix Tower YAML

- - -

Beta License: AGPL-3 cetmix/cetmix-tower

-

This module implements YAML format data import/export for Cetmix -Tower.

-

Please refer to the official -documentation for detailed information.

-

Table of contents

- -
-

Configuration

-

Please refer to the official -documentation for detailed configuration -instructions.

-
-
-

Usage

-

Please refer to the official -documentation for detailed usage -instructions.

-
-
-

Changelog

-
-

16.0.2.0.1 (2025-10-29)

-
    -
  • Features: Improve the way secrets are listed in the YAML import -widget. (5010)
  • -
-
-
-

16.0.1.4.2 (2025-10-06)

-
    -
  • Bugfixes: Add the missing ‘create’ function decorator (4980)
  • -
-
-
-

16.0.1.4.1 (2025-08-26)

-
    -
  • Bugfixes: Make selection values lowercase to simplify their -management. (4896)
  • -
-
-
-

16.0.1.3.0 (2025-07-30)

-
    -
  • Features: Optional behaviour when file uploaded by command already -exists on the server. (4740)
  • -
-
-
-

16.0.1.1.4 (2025-07-08)

-
    -
  • Bugfixes: Fix missing model names in YAML exports when exporting -multiple commands with flight plans (4820)
  • -
-
-
-

16.0.1.1.3 (2025-07-07)

-
    -
  • Bugfixes: Import servers with Password ssh authentication mode -(4812)
  • -
-
-
-

16.0.1.1.1 (2025-06-23)

-
    -
  • Features: YAML code optimisation (4728)
  • -
-
-
-

16.0.1.1.0 (2025-06-20)

-
    -
  • Features: Export/import scheduled tasks to/from YAML. (4650)
  • -
-
-
-

16.0.1.0.5 (2025-05-21)

-
    -
  • Features: Export/import secret values related to Server. (4696)
  • -
-
-
-

16.0.1.0.4 (2025-05-16)

-
    -
  • Features: Export/import servers and files to/from YAML. (4670)
  • -
-
-
-

16.0.1.0.3 (2025-05-09)

-
    -
  • Bugfixes: Non-critical issues and performance improvements. (4663)
  • -
-
-
-

16.0.1.0.2 (2025-04-30)

-
    -
  • Features: User groups are visible without developer mode. (4642)
  • -
-
-
-

16.0.1.0.1 (2025-04-21)

-
    -
  • Features: Export additional fields for shortcuts, variables and -options. Add action menu to export keys/secrets. (4602)
  • -
-
-
-

16.0.1.0.0

-

Release for Odoo 16.0

-
-
-
-

Bug Tracker

-

Bugs are tracked on GitHub Issues. -In case of trouble, please check there if your issue has already been reported. -If you spotted it first, help us to smash it by providing a detailed and welcomed -feedback.

-

Do not contact contributors directly about support or help with technical issues.

-
-
-

Credits

-
-

Authors

-
    -
  • Cetmix
  • -
-
-
-

Maintainers

-

This module is part of the cetmix/cetmix-tower project on GitHub.

-

You are welcome to contribute.

-
-
-
- - diff --git a/addons/cetmix_tower_yaml/tests/__init__.py b/addons/cetmix_tower_yaml/tests/__init__.py deleted file mode 100644 index b5e1e10..0000000 --- a/addons/cetmix_tower_yaml/tests/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from . import test_command -from . import test_tower_yaml_mixin -from . import test_file_template -from . import test_plan -from . import test_yaml_export_wizard -from . import test_yaml_import_wizard -from . import test_server_log -from . import test_server_yaml diff --git a/addons/cetmix_tower_yaml/tests/test_command.py b/addons/cetmix_tower_yaml/tests/test_command.py deleted file mode 100644 index bb4257f..0000000 --- a/addons/cetmix_tower_yaml/tests/test_command.py +++ /dev/null @@ -1,347 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -import yaml - -from odoo.exceptions import ValidationError -from odoo.tests import TransactionCase - - -class TestTowerCommand(TransactionCase): - @classmethod - def setUpClass(cls, *args, **kwargs): - super().setUpClass(*args, **kwargs) - - cls.Command = cls.env["cx.tower.command"] - - # Expected YAML content of the test command - cls.command_test_yaml = """cetmix_tower_model: command -access_level: manager -reference: test_yaml_in_tests -name: Test YAML -action: ssh_command -allow_parallel_run: false -note: |- - Test YAML command conversion. - Ensure all fields are rendered properly. -os_ids: false -tag_ids: false -path: false -file_template_id: false -flight_plan_id: false -code: |- - cd /home/{{ tower.server.ssh_username }} \\ - && ls -lha -server_status: false -variable_ids: false -secret_ids: false -no_split_for_sudo: false -if_file_exists: skip -disconnect_file: false -""" - - # YAML content translated into Python dict - cls.command_test_yaml_dict = yaml.safe_load(cls.command_test_yaml) - - def test_yaml_from_command(self): - """Test if YAML is generated properly from a command""" - - # -- 0 -- - # Create test command - # Test command - command_test = self.Command.create( - { - "name": "Test YAML", - "reference": "test_yaml_in_tests", - "action": "ssh_command", - "code": """cd /home/{{ tower.server.ssh_username }} \\ -&& ls -lha""", - "note": """Test YAML command conversion. -Ensure all fields are rendered properly.""", - } - ) - - # -- 1 -- - # Check it YAML generated by the command matches - # YAML from the template file - self.assertEqual( - command_test.yaml_code, - self.command_test_yaml, - "YAML generated from command doesn't match template file one", - ) - - # -- 2 -- - # Check if YAML key values match Cetmix Tower ones - - self.assertEqual( - command_test.access_level, - self.Command.TO_TOWER_ACCESS_LEVEL[ - self.command_test_yaml_dict["access_level"] - ], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command_test.action, - self.command_test_yaml_dict["action"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command_test.allow_parallel_run, - self.command_test_yaml_dict["allow_parallel_run"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command_test.code, - self.command_test_yaml_dict["code"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command_test.name, - self.command_test_yaml_dict["name"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command_test.note, - self.command_test_yaml_dict["note"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command_test.path, - self.command_test_yaml_dict["path"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command_test.reference, - self.command_test_yaml_dict["reference"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command_test.if_file_exists, - self.command_test_yaml_dict["if_file_exists"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command_test.disconnect_file, - self.command_test_yaml_dict["disconnect_file"], - "YAML value doesn't match Cetmix Tower one", - ) - - def test_command_from_yaml(self): - """Test if YAML is generated properly from a command""" - - def test_yaml(command): - """Checks if yaml values are inserted correctly - - Args: - command(cx.tower.command): _description_ - """ - self.assertEqual( - command.access_level, - self.Command.TO_TOWER_ACCESS_LEVEL[ - self.command_test_yaml_dict["access_level"] - ], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command.action, - self.command_test_yaml_dict["action"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command.allow_parallel_run, - self.command_test_yaml_dict["allow_parallel_run"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command.code, - self.command_test_yaml_dict["code"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command.name, - self.command_test_yaml_dict["name"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command.note, - self.command_test_yaml_dict["note"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command.path, - self.command_test_yaml_dict["path"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command.reference, - self.command_test_yaml_dict["reference"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command.if_file_exists, - self.command_test_yaml_dict["if_file_exists"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - command.disconnect_file, - self.command_test_yaml_dict["disconnect_file"], - "YAML value doesn't match Cetmix Tower one", - ) - - # Create test command - command_test = self.Command.create( - {"name": "New Command", "action": "python_code"} - ) - - # -- 1 -- - # Insert YAML into the command and - # check if YAML key values match Cetmix Tower ones - command_test.yaml_code = self.command_test_yaml - test_yaml(command_test) - - # -- 2 -- - # Insert some non supported keys and ensure nothing bad happens - yaml_with_non_supported_keys = """access_level: manager -action: ssh_command -doge: wow -memes: much nice! -allow_parallel_run: false -cetmix_tower_model: command -code: |- - cd /home/{{ tower.server.ssh_username }} \\ - && ls -lha -file_template_id: false -flight_plan_id: false -name: Test YAML -note: |- - Test YAML command conversion. - Ensure all fields are rendered properly. -path: false -reference: test_yaml_in_tests -tag_ids: false -""" - command_test.yaml_code = yaml_with_non_supported_keys - test_yaml(command_test) - - # -- 3 -- - # Insert non existing selection field value and exception is raised - yaml_with_non_supported_keys = """access_level: manager -action: non_existing_action -doge: wow -memes: much nice! -allow_parallel_run: false -cetmix_tower_model: command -code: |- - cd /home/{{ tower.server.ssh_username }} \\ - && ls -lha -file_template_id: false -flight_plan_id: false -name: Test YAML -note: |- - Test YAML command conversion. - Ensure all fields are rendered properly. -path: false -reference: test_yaml_in_tests -tag_ids: false -""" - with self.assertRaises(ValidationError) as e: - command_test.yaml_code = yaml_with_non_supported_keys - self.assertIn("non_existing_action", str(e.exception)) - self.assertEqual( - str(e), - "Wrong value for cx.tower.command.action: 'non_existing_action'", - "Exception message doesn't match", - ) - - def test_command_with_action_file_template(self): - """Test command with 'File from template' action""" - yaml_with_reference = """cetmix_tower_model: command -access_level: manager -reference: such_much_test_command -name: Such Much Command -action: file_using_template -allow_parallel_run: false -note: Just a note -os_ids: false -tag_ids: false -path: false -file_template_id: my_custom_test_template -flight_plan_id: false -code: false -server_status: false -variable_ids: false -secret_ids: false -no_split_for_sudo: false -if_file_exists: skip -disconnect_file: false -""" - # Add file template - file_template = self.env["cx.tower.file.template"].create( - { - "name": "Such much demo", - "reference": "my_custom_test_template", - "file_name": "much_logs.txt", - "server_dir": "/var/log/my/files", - "source": "tower", - "file_type": "text", - "note": "Hey!", - "keep_when_deleted": False, - } - ) - command_with_template = self.Command.create( - { - "name": "Such Much Command", - "reference": "such_much_test_command", - "action": "file_using_template", - "note": "Just a note", - "file_template_id": file_template.id, - } - ) - - # -- 1 -- - # Check if final YAML composed correctly - self.assertEqual( - command_with_template.yaml_code, - yaml_with_reference, - "YAML is not composed correctly", - ) - - # -- 2 -- - # Explode related record and check the YAML - yaml_with_reference_exploded = """cetmix_tower_model: command -access_level: manager -reference: such_much_test_command -name: Such Much Command -action: file_using_template -allow_parallel_run: false -note: Just a note -os_ids: false -tag_ids: false -path: false -file_template_id: - reference: my_custom_test_template - name: Such much demo - source: tower - file_type: text - server_dir: /var/log/my/files - file_name: much_logs.txt - keep_when_deleted: false - tag_ids: false - note: Hey! - code: false - variable_ids: false - secret_ids: false -flight_plan_id: false -code: false -server_status: false -variable_ids: false -secret_ids: false -no_split_for_sudo: false -if_file_exists: skip -disconnect_file: false -""" - command_with_template.invalidate_recordset(["yaml_code"]) - self.assertEqual( - command_with_template.with_context(explode_related_record=True).yaml_code, - yaml_with_reference_exploded, - "YAML is not composed correctly", - ) diff --git a/addons/cetmix_tower_yaml/tests/test_file_template.py b/addons/cetmix_tower_yaml/tests/test_file_template.py deleted file mode 100644 index 097cb76..0000000 --- a/addons/cetmix_tower_yaml/tests/test_file_template.py +++ /dev/null @@ -1,320 +0,0 @@ -import yaml - -from odoo.tests import TransactionCase - - -class TestTowerFileTemplate(TransactionCase): - @classmethod - def setUpClass(cls, *args, **kwargs): - super().setUpClass(*args, **kwargs) - - cls.FileTemplate = cls.env["cx.tower.file.template"] - - # Expected YAML content of the test file template - cls.file_template_test_yaml = """cetmix_tower_model: file_template -reference: dockerfile_unit_test -name: Dockerfile Test -source: tower -file_type: text -server_dir: /opt -file_name: Dockerfile -keep_when_deleted: true -tag_ids: false -note: |- - Used to build Odoo addons image. - Depends on Odoo core image. -code: |- - FROM odoo:{{ odoo_test_version }} - # Install git-aggregator and tools for requirements generation - RUN pip3 install --upgrade pip && pip install manifestoo setuptools-odoo git-aggregator - # Let's go! - USER odoo -variable_ids: false -secret_ids: false -""" # noqa - - # Expected YAML content of the test file template - # without empty x2mvalues - cls.file_template_test_yaml_no_empty_values = """cetmix_tower_model: file_template -reference: dockerfile_unit_test -name: Dockerfile Test -source: tower -file_type: text -server_dir: /opt -file_name: Dockerfile -keep_when_deleted: true -note: |- - Used to build Odoo addons image. - Depends on Odoo core image. -code: |- - FROM odoo:{{ odoo_test_version }} - # Install git-aggregator and tools for requirements generation - RUN pip3 install --upgrade pip && pip install manifestoo setuptools-odoo git-aggregator - # Let's go! - USER odoo -""" # noqa - - # YAML content translated into Python dict - cls.file_template_test_yaml_dict = yaml.safe_load(cls.file_template_test_yaml) - cls.file_template_test_yaml_dict_no_empty_values = yaml.safe_load( - cls.file_template_test_yaml_no_empty_values - ) - - def test_yaml_from_file_template(self): - """Test if YAML is generated properly from a file""" - - # -- 0 -- - # Create test file - # Test file - file_template_test = self.FileTemplate.create( - { - "name": "Dockerfile Test", - "reference": "dockerfile_unit_test", - "file_name": "Dockerfile", - "server_dir": "/opt", - "source": "tower", - "keep_when_deleted": True, - "file_type": "text", - "code": """FROM odoo:{{ odoo_test_version }} -# Install git-aggregator and tools for requirements generation -RUN pip3 install --upgrade pip && pip install manifestoo setuptools-odoo git-aggregator -# Let's go! -USER odoo""", - "note": """Used to build Odoo addons image. -Depends on Odoo core image.""", - } - ) - - # -- 1 -- - # Check it YAML generated by the file matches - # YAML from the template file - - self.assertEqual( - file_template_test.yaml_code, - self.file_template_test_yaml, - "YAML generated from file doesn't match template file one", - ) - - # -- 2 -- - # Check if YAML key values match Cetmix Tower ones - - self.assertEqual( - file_template_test.source, - self.file_template_test_yaml_dict["source"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template_test.file_name, - self.file_template_test_yaml_dict["file_name"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template_test.code, - self.file_template_test_yaml_dict["code"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template_test.name, - self.file_template_test_yaml_dict["name"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template_test.note, - self.file_template_test_yaml_dict["note"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template_test.server_dir, - self.file_template_test_yaml_dict["server_dir"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template_test.reference, - self.file_template_test_yaml_dict["reference"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template_test.file_type, - self.file_template_test_yaml_dict["file_type"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template_test.keep_when_deleted, - self.file_template_test_yaml_dict["keep_when_deleted"], - "YAML value doesn't match Cetmix Tower one", - ) - - def test_yaml_from_file_template_no_empty_values(self): - """Test if YAML is generated properly from a file""" - - # -- 0 -- - # Create test file - # Test file - file_template_test = self.FileTemplate.with_context( - remove_empty_values=True - ).create( - { - "name": "Dockerfile Test", - "reference": "dockerfile_unit_test", - "file_name": "Dockerfile", - "server_dir": "/opt", - "source": "tower", - "keep_when_deleted": True, - "file_type": "text", - "code": """FROM odoo:{{ odoo_test_version }} -# Install git-aggregator and tools for requirements generation -RUN pip3 install --upgrade pip && pip install manifestoo setuptools-odoo git-aggregator -# Let's go! -USER odoo""", - "note": """Used to build Odoo addons image. -Depends on Odoo core image.""", - } - ) - - # -- 1 -- - # Check it YAML generated by the file matches - # YAML from the template file - - self.assertEqual( - file_template_test.yaml_code, - self.file_template_test_yaml_no_empty_values, - "YAML generated from file doesn't match template file one", - ) - - # -- 2 -- - # Check if YAML key values match Cetmix Tower ones - - self.assertEqual( - file_template_test.source, - self.file_template_test_yaml_dict_no_empty_values["source"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template_test.file_name, - self.file_template_test_yaml_dict_no_empty_values["file_name"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template_test.code, - self.file_template_test_yaml_dict_no_empty_values["code"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template_test.name, - self.file_template_test_yaml_dict_no_empty_values["name"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template_test.note, - self.file_template_test_yaml_dict_no_empty_values["note"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template_test.server_dir, - self.file_template_test_yaml_dict_no_empty_values["server_dir"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template_test.reference, - self.file_template_test_yaml_dict_no_empty_values["reference"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template_test.file_type, - self.file_template_test_yaml_dict_no_empty_values["file_type"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template_test.keep_when_deleted, - self.file_template_test_yaml_dict_no_empty_values["keep_when_deleted"], - "YAML value doesn't match Cetmix Tower one", - ) - - def test_file_template_from_yaml(self): - """Test if YAML is generated properly from a file""" - - def test_yaml(file_template): - """Checks if yaml values are inserted correctly - - Args: - file_template (cx.tower.file.template): File template - """ - self.assertEqual( - file_template.source, - self.file_template_test_yaml_dict["source"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template.file_name, - self.file_template_test_yaml_dict["file_name"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template.code, - self.file_template_test_yaml_dict["code"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template.name, - self.file_template_test_yaml_dict["name"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template.note, - self.file_template_test_yaml_dict["note"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template.server_dir, - self.file_template_test_yaml_dict["server_dir"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template.reference, - self.file_template_test_yaml_dict["reference"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template.file_type, - self.file_template_test_yaml_dict["file_type"], - "YAML value doesn't match Cetmix Tower one", - ) - self.assertEqual( - file_template.keep_when_deleted, - self.file_template_test_yaml_dict["keep_when_deleted"], - "YAML value doesn't match Cetmix Tower one", - ) - - # Create test file template - file_template_test = self.FileTemplate.create({"name": "New file template"}) - - # -- 1 -- - # Insert YAML into the file and - # check if YAML key values match Cetmix Tower ones - file_template_test.yaml_code = self.file_template_test_yaml - test_yaml(file_template_test) - - # -- 2 -- - # Insert some non supported keys and ensure nothing bad happens - yaml_with_non_supported_keys = """cetmix_tower_model: file_template -code: |- - FROM odoo:{{ odoo_test_version }} - # Install git-aggregator and tools for requirements generation - RUN pip3 install --upgrade pip && pip install manifestoo setuptools-odoo git-aggregator - # Let's go! - USER odoo -doge: SoMuch style! -file_name: Dockerfile -file_type: text -keep_when_deleted: true -name: Dockerfile Test -note: |- - Used to build Odoo addons image. - Depends on Odoo core image. -reference: dockerfile_unit_test -server_dir: /opt -source: tower -tag_ids: false -""" # noqa - file_template_test.yaml_code = yaml_with_non_supported_keys - test_yaml(file_template_test) diff --git a/addons/cetmix_tower_yaml/tests/test_plan.py b/addons/cetmix_tower_yaml/tests/test_plan.py deleted file mode 100644 index 4d9ec43..0000000 --- a/addons/cetmix_tower_yaml/tests/test_plan.py +++ /dev/null @@ -1,179 +0,0 @@ -from odoo.tests import TransactionCase - - -class TestTowerPlan(TransactionCase): - @classmethod - def setUpClass(cls, *args, **kwargs): - super().setUpClass(*args, **kwargs) - - cls.Plan = cls.env["cx.tower.plan"] - - def test_plan_create_from_yaml(self): - """Test plan creation from YAML.""" - - plan_yaml = """cetmix_tower_model: plan -access_level: manager -reference: test_plan_from_yaml -name: 'Test Plan From Yaml' -allow_parallel_run: false -color: 0 -tag_ids: -- reference: doge_test_plan_tag - name: Doge Test Plan Tag - color: 1 -on_error_action: e -custom_exit_code: 0 -line_ids: -- sequence: 5 - condition: false - use_sudo: false - path: /such/much/{{ test_plan_dir }} - command_id: - access_level: manager - reference: very_much_command_test - name: Very much command - action: ssh_command - allow_parallel_run: false - note: false - code: Such much code - variable_ids: - - cetmix_tower_model: variable - reference: test_plan_dir - name: Test Plan Directory - action_ids: - - sequence: 1 - condition: == - value_char: '0' - action: n - custom_exit_code: 0 - variable_value_ids: - - cetmix_tower_model: variable_value - variable_id: - cetmix_tower_yaml_version: 1 - cetmix_tower_model: variable - reference: test_plan_branch - name: Test Plan Branch - value_char: production - - cetmix_tower_model: variable_value - variable_id: - cetmix_tower_yaml_version: 1 - cetmix_tower_model: variable - reference: test_plan_some_unique_variable - name: Test Plan Some Unique Variable - value_char: 'Final Value' - - cetmix_tower_model: plan_line_action - access_level: manager - sequence: 2 - condition: '>' - value_char: '0' - action: ec - custom_exit_code: 255 - variable_value_ids: false - variable_ids: false -""" - # -- 1 -- - # Create plan from YAML - plan_form_yaml = self.Plan.create( - {"name": "Name Placeholder", "yaml_code": plan_yaml} - ) - self.assertEqual( - plan_form_yaml.reference, - "test_plan_from_yaml", - "Reference is not set from YAML", - ) - # Name should be set from YAML - self.assertEqual( - plan_form_yaml.name, "Test Plan From Yaml", "Name is not set from YAML" - ) - - # -- 2 -- - # Check plan tags - plan_tags = plan_form_yaml.tag_ids - self.assertEqual(len(plan_tags), 1) - self.assertEqual(plan_tags.name, "Doge Test Plan Tag") - - # -- 3 -- - # Check plan lines - plan_lines = plan_form_yaml.line_ids - self.assertEqual(len(plan_lines), 1, "Line count is not 1") - self.assertFalse(plan_lines.condition, "Condition is not false") - self.assertEqual( - plan_lines.path, - "/such/much/{{ test_plan_dir }}", - "Path is not set from YAML", - ) - self.assertEqual( - plan_lines.command_id.reference, - "very_much_command_test", - "Command reference is not set from YAML", - ) - self.assertEqual( - plan_lines.command_id.name, - "Very much command", - "Command name is not set from YAML", - ) - self.assertEqual( - plan_lines.command_id.action, - "ssh_command", - "Command action is not set from YAML", - ) - self.assertFalse( - plan_lines.command_id.allow_parallel_run, - "Command allow parallel run is not set from YAML", - ) - self.assertFalse( - plan_lines.command_id.note, "Command note is not set from YAML" - ) - self.assertEqual( - plan_lines.command_id.variable_ids.mapped("reference"), - ["test_plan_dir"], - "Command variable ids is not set from YAML", - ) - self.assertEqual( - plan_lines.command_id.access_level, - "2", - "Command access level is not set from YAML", - ) - - # -- 4 -- - # Check plan line actions - plan_actions = plan_form_yaml.line_ids.action_ids - self.assertEqual(len(plan_actions), 2, "Action count is not 2") - self.assertEqual( - plan_actions[0].condition, "==", "First action condition is not equal" - ) - self.assertEqual( - plan_actions[0].value_char, "0", "First action value char is not 0" - ) - self.assertEqual(plan_actions[0].action, "n", "First action action is not n") - self.assertEqual( - plan_actions[0].custom_exit_code, - 0, - "First action custom exit code is not 0", - ) - self.assertEqual( - len(plan_actions[0].variable_value_ids), - 2, - "Number of variable value ids is not correct", - ) - self.assertEqual( - plan_actions[0].variable_value_ids.mapped("value_char"), - ["production", "Final Value"], - "Variable value chars are not correct", - ) - self.assertEqual( - plan_actions[1].condition, ">", "Second action condition is not greater" - ) - self.assertEqual( - plan_actions[1].value_char, "0", "Second action value char is not 0" - ) - self.assertEqual(plan_actions[1].action, "ec", "Second action action is not ec") - self.assertEqual( - plan_actions[1].custom_exit_code, - 255, - "Second action custom exit code is not 255", - ) - self.assertFalse( - plan_actions[1].variable_value_ids, - "Second action variable value ids is not false", - ) diff --git a/addons/cetmix_tower_yaml/tests/test_server_log.py b/addons/cetmix_tower_yaml/tests/test_server_log.py deleted file mode 100644 index 4849332..0000000 --- a/addons/cetmix_tower_yaml/tests/test_server_log.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright (C) 2025 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -""" -Tests for the cx.tower.server.log model YAML export/import. - -Covers: -1. YAML export of a file-type log must include `file_id` and allow suffixes. -2. A full round-trip (export → delete → import) preserves the `file_id` relation. -3. Exporting a non-file log must include a falsy `file_id`. -4. Importing YAML with a bogus `file_id` reference raises ValidationError. -""" - -import yaml - -from odoo.tests import TransactionCase, tagged - - -@tagged("post_install", "-at_install") -class TestServerLog(TransactionCase): - """YAML export/import tests for cx.tower.server.log.""" - - @classmethod - def setUpClass(cls): - super().setUpClass() - env = cls.env - cls.File = env["cx.tower.file"] - cls.Server = env["cx.tower.server"] - cls.ServerLog = env["cx.tower.server.log"] - - # Create a file to reference from the log - cls.file = cls.File.create( - { - "name": "repos.yaml", - "reference": "reposyaml", - "source": "tower", - "file_type": "text", - "server_dir": "/tmp", - "code": "# Example\nHello, Tower!", - } - ) - - # Create a server (use password auth to satisfy constraints) - cls.server = cls.Server.create( - { - "name": "Srv-YAML-Test", - "reference": "srv_yaml_test", - "ip_v4_address": "127.0.0.1", - "ssh_username": "admin", - "ssh_port": 22, - "ssh_auth_mode": "p", - "ssh_password": "dummy", - "use_sudo": False, - } - ) - - # Create a file-type log linked to the file above - cls.log = cls.ServerLog.create( - { - "name": "Log from file", - "reference": "log_from_file", - "log_type": "file", - "file_id": cls.file.id, - "server_id": cls.server.id, - "use_sudo": False, - } - ) - - def test_yaml_export_contains_file_id(self): - """Exported YAML must include a file_id starting with the file's reference.""" - data = yaml.safe_load(self.log.yaml_code) - # Ensure file_id is present - self.assertIn("file_id", data, "`file_id` is missing from YAML export") - # Allow for auto-appended suffixes, so only check prefix - self.assertTrue( - data["file_id"].startswith(self.file.reference), - f"`file_id` value '{data['file_id']}' should start with " - f"'{self.file.reference}'", - ) - - def test_yaml_roundtrip_restores_file_id(self): - """A full export→delete→import cycle must restore the file_id relation.""" - yaml_dict = yaml.safe_load(self.log.yaml_code) - # Remove the original log - self.log.unlink() - # Recreate from YAML - vals = self.ServerLog._post_process_yaml_dict_values(yaml_dict) - restored = self.ServerLog.with_context(from_yaml=True).create(vals) - # Verify relation restored - self.assertEqual( - restored.file_id.id, - self.file.id, - "`file_id` was not restored after round-trip", - ) - - def test_yaml_export_without_file_id(self): - """Logs of non-file type should not include file_id in YAML.""" - cmd_log = self.ServerLog.create( - { - "name": "Log no file", - "reference": "log_no_file", - "log_type": "command", - "server_id": self.server.id, - "use_sudo": False, - } - ) - data = yaml.safe_load(cmd_log.yaml_code) - # key is present, but must be falsy - self.assertIn("file_id", data, "`file_id` key is missing") - self.assertFalse( - data["file_id"], - "`file_id` for non-file log must be False/empty", - ) - - def test_yaml_import_with_missing_file_reference(self): - """Missing file reference is accepted, but file_id stays empty.""" - yaml_dict = yaml.safe_load(self.log.yaml_code) - yaml_dict["file_id"] = "does_not_exist" - - vals = self.ServerLog._post_process_yaml_dict_values(yaml_dict) - new_log = self.ServerLog.with_context(from_yaml=True).create(vals) - - # Log is created, but the relation is not resolved - self.assertFalse( - new_log.file_id, - "file_id should be empty when reference cannot be resolved", - ) diff --git a/addons/cetmix_tower_yaml/tests/test_server_yaml.py b/addons/cetmix_tower_yaml/tests/test_server_yaml.py deleted file mode 100644 index 2592f39..0000000 --- a/addons/cetmix_tower_yaml/tests/test_server_yaml.py +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright (C) 2025 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -""" -Tests for cx.tower.server YAML export/import covering command_ids and plan_ids. -""" -import yaml - -from odoo.tests import TransactionCase, tagged - - -@tagged("post_install", "-at_install") -class TestServerYAML(TransactionCase): - """YAML export/import tests for cx.tower.server with commands and plans.""" - - @classmethod - def setUpClass(cls): - super().setUpClass() - env = cls.env - cls.Server = env["cx.tower.server"] - cls.Command = env["cx.tower.command"] - cls.Plan = env["cx.tower.plan"] - - # Create a command to attach (use defaults for access_level) - cls.command = cls.Command.create( - { - "name": "Test Command", - "reference": "test_command", - "action": "ssh_command", - "allow_parallel_run": False, - } - ) - - # Create a flight plan to attach - cls.plan = cls.Plan.create( - { - "name": "Test Flight Plan", - "reference": "test_plan", - "allow_parallel_run": False, - "color": 0, - } - ) - - # Create server and link command and plan - cls.server = cls.Server.create( - { - "name": "Server YAML Test", - "reference": "srv_yaml_test", - "ip_v4_address": "127.0.0.1", - "ssh_username": "admin", - "ssh_port": 22, - "ssh_auth_mode": "p", - "ssh_password": "dummy", - "use_sudo": False, - # Link the m2m fields - "command_ids": [(6, 0, [cls.command.id])], - "plan_ids": [(6, 0, [cls.plan.id])], - } - ) - - def test_yaml_export_contains_command_and_plan(self): - """Exported YAML include command_ids and plan_ids with correct references.""" - data = yaml.safe_load(self.server.yaml_code) - # Check command_ids - self.assertIn( - "command_ids", - data, - "`command_ids` is missing from YAML export", - ) - self.assertIsInstance( - data["command_ids"], list, "`command_ids` should be a list in YAML" - ) - self.assertTrue( - data["command_ids"], - "`command_ids` list should not be empty", - ) - # Only reference should be exported - self.assertEqual( - data["command_ids"][0], - self.command.reference, - "Exported command reference does not match", - ) - - # Check plan_ids - self.assertIn( - "plan_ids", - data, - "`plan_ids` is missing from YAML export", - ) - self.assertIsInstance( - data["plan_ids"], list, "`plan_ids` should be a list in YAML" - ) - self.assertTrue( - data["plan_ids"], - "`plan_ids` list should not be empty", - ) - self.assertEqual( - data["plan_ids"][0], - self.plan.reference, - "Exported plan reference does not match", - ) - - def test_yaml_roundtrip_restores_command_and_plan(self): - """A full export→delete→import cycle must restore the m2m relations.""" - yaml_dict = yaml.safe_load(self.server.yaml_code) - # Remove original server - self.server.unlink() - # Prepare values and import - vals = self.Server._post_process_yaml_dict_values(yaml_dict) - restored = self.Server.with_context( - from_yaml=True, skip_ssh_settings_check=True - ).create(vals) - - # Verify m2m links restored - self.assertEqual( - restored.command_ids.ids, - [self.command.id], - "`command_ids` were not restored correctly", - ) - self.assertEqual( - restored.plan_ids.ids, - [self.plan.id], - "`plan_ids` were not restored correctly", - ) diff --git a/addons/cetmix_tower_yaml/tests/test_tower_yaml_mixin.py b/addons/cetmix_tower_yaml/tests/test_tower_yaml_mixin.py deleted file mode 100644 index bf456eb..0000000 --- a/addons/cetmix_tower_yaml/tests/test_tower_yaml_mixin.py +++ /dev/null @@ -1,525 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - - -from odoo import _ -from odoo.exceptions import AccessError, ValidationError -from odoo.tests import TransactionCase, tagged - - -class TestTowerYamlMixin(TransactionCase): - @classmethod - def setUpClass(cls, *args, **kwargs): - super().setUpClass(*args, **kwargs) - cls.Users = cls.env["res.users"].with_context(no_reset_password=True) - cls.YamlMixin = cls.env["cx.tower.yaml.mixin"] - TowerTag = cls.env["cx.tower.tag"] - cls.tag_doge = TowerTag.create({"name": "Doge", "reference": "doge"}) - cls.tag_pepe = TowerTag.create({"name": "Pepe", "reference": "pepe"}) - - def test_convert_dict_to_yaml(self): - # -- 1 -- - # Test regular flow - self.assertEqual( - self.YamlMixin._convert_dict_to_yaml({"a": 1, "b": 2}), - "a: 1\nb: 2\n", - "Dictionary was not converted to YAML correctly", - ) - - # -- 2 -- - # Test flow with exception due to wrong values - with self.assertRaises(ValidationError) as e: - self.YamlMixin._convert_dict_to_yaml("not_a_dict") - self.assertEqual( - str(e.exception), - _("Values must be a dictionary"), - "Exception message doesn't match", - ) - - def test_yaml_field_access(self): - # Create Root user with no access to the 'yaml_code field - user_root = self.Users.create( - { - "name": "Root User", - "login": "root@example.com", - "groups_id": [ - (4, self.env.ref("base.group_user").id), - (4, self.env.ref("cetmix_tower_server.group_root").id), - ], - } - ) - with self.assertRaises(AccessError): - self.tag_doge.with_user(user_root).read(["yaml_code"]) - - # Add user to the 'cetmix_tower_yaml.group_export' group - # and check if access is granted - user_root.write( - {"groups_id": [(4, self.env.ref("cetmix_tower_yaml.group_export").id)]} - ) - yaml_code = ( - self.tag_doge.with_user(user_root).read(["yaml_code"])[0].get("yaml_code") - ) - - # Modify YAML code and check if it's saved - yaml_code = yaml_code.replace("Doge", "WowDoge") - with self.assertRaises(AccessError): - self.tag_doge.with_user(user_root).write({"yaml_code": yaml_code}) - - # Add user to the 'cetmix_tower_yaml.group_import' group - # and check if access is granted - user_root.write( - {"groups_id": [(4, self.env.ref("cetmix_tower_yaml.group_import").id)]} - ) - self.tag_doge.with_user(user_root).write({"yaml_code": yaml_code}) - self.assertEqual( - self.tag_doge.with_user(user_root).yaml_code, - yaml_code, - "YAML code was not saved", - ) - - def test_post_process_record_values(self): - """Test value post processing. - We test common fields only because this method can be overridden - in models inheriting this mixin. - """ - - # Patch method to return "access_level" field too - def _get_fields_for_yaml(self): - return ["access_level", "name", "reference"] - - self.YamlMixin._patch_method("_get_fields_for_yaml", _get_fields_for_yaml) - - source_values = { - "access_level": "3", - "id": 22332, - "name": "Doge Much Like", - "reference": "such_much_doge", - } - - result_values = self.YamlMixin._post_process_record_values(source_values.copy()) - - self.assertNotIn("id", result_values, "ID must be removed") - self.assertEqual( - result_values["access_level"], - self.YamlMixin.TO_YAML_ACCESS_LEVEL[source_values["access_level"]], - "Access level is not parsed correctly", - ) - self.assertEqual( - result_values["name"], - source_values["name"], - "Other values should remain unchanged", - ) - self.assertEqual( - result_values["reference"], - source_values["reference"], - "Other values should remain unchanged", - ) - - # Restore original method - self.YamlMixin._revert_method("_get_fields_for_yaml") - - def test_post_process_yaml_dict_values(self): - """Test YAML dict value post processing. - We test common fields only because this method can be overridden - in models inheriting this mixin. - """ - - # Patch method to return "access_level" field too - def _get_fields_for_yaml(self): - return ["access_level", "name", "reference"] - - self.YamlMixin._patch_method("_get_fields_for_yaml", _get_fields_for_yaml) - - # -- 1 -- - # Test regular flow - source_values = { - "access_level": "user", - "name": "Doge Much Like", - "reference": "such_much_doge", - "some_doge_field": "some_meme", - } - - result_values = self.YamlMixin._post_process_yaml_dict_values( - source_values.copy() - ) - self.assertNotIn( - "some_doge_field", result_values, "Non listed fields must be removed" - ) - self.assertEqual( - result_values["access_level"], - self.YamlMixin.TO_TOWER_ACCESS_LEVEL[source_values["access_level"]], - "Access level is not parsed correctly", - ) - self.assertEqual( - result_values["name"], - source_values["name"], - "Other values should remain unchanged", - ) - self.assertEqual( - result_values["reference"], - source_values["reference"], - "Other values should remain unchanged", - ) - - # -- Test 2 -- - # Submit wrong value for access level - source_values.update( - { - "access_level": "doge", - } - ) - with self.assertRaises(ValidationError) as e: - result_values = self.YamlMixin._post_process_yaml_dict_values( - source_values.copy() - ) - self.assertEqual( - str(e.exception), - _( - "Wrong value for 'access_level' key: %(acv)s", - acv="doge", - ), - "Exception message doesn't match", - ) - - # Restore original method - self.YamlMixin._revert_method("_get_fields_for_yaml") - - def test_process_relation_field_value_no_explode(self): - """Test non exploded related field values. - Non exploded values represent related record with reference only. - - Covers the following child functions: - - _process_m2o_value(..) - - _process_x2m_values(..) - """ - - # We are using command with file template for that - file_template = self.env["cx.tower.file.template"].create( - {"name": "Test m2o", "reference": "test_m2o"} - ) - command = self.env["cx.tower.command"].create( - { - "name": "Command test m2o", - "action": "file_using_template", - "file_template_id": file_template.id, - "tag_ids": [(4, self.tag_doge.id), (4, self.tag_pepe.id)], - } - ) - - # -- 1 -- - # Record -> Yaml - - # -- 1.1 -- - # Many2one - result = command._process_relation_field_value( - field="file_template_id", - value=(command.file_template_id.id, command.file_template_id.name), - record_mode=True, - ) - self.assertEqual( - result, file_template.reference, "Reference was not resolved correctly" - ) - # -- 1.2 -- - # Many2many - result = command._process_relation_field_value( - field="tag_ids", - value=[self.tag_doge.id, self.tag_pepe.id], - record_mode=True, - ) - - self.assertEqual(len(result), 2, "Must be 2 references") - self.assertIn( - self.tag_doge.reference, result, "Reference was not resolved correctly" - ) - self.assertIn( - self.tag_pepe.reference, result, "Reference was not resolved correctly" - ) - - # -- 2 -- - # Yaml -> Record - - # -- 2.1. -- - # Many2one - result = command._process_relation_field_value( - field="file_template_id", value=file_template.reference, record_mode=False - ) - self.assertEqual( - result, file_template.id, "Record ID was not resolved correctly" - ) - - # -- 2.2 -- - # Many2many - result = command._process_relation_field_value( - field="tag_ids", - value=[self.tag_doge.reference, self.tag_pepe.reference], - record_mode=False, - ) - self.assertEqual(len(result), 2, "Must be 2 records") - self.assertIn( - (4, self.tag_doge.id), result, "Record ID was not resolved correctly" - ) - self.assertIn( - (4, self.tag_pepe.id), result, "Record ID was not resolved correctly" - ) - - # -- 3 -- - # Yaml with non existing reference -> Record - result = command._process_relation_field_value( - field="file_template_id", value="such_much_not_reference", record_mode=False - ) - self.assertFalse(result, "Must be 'False'") - - # -- 4 -- - # No record -> Yaml - result = command._process_relation_field_value( - field="file_template_id", - value=self.env["cx.tower.file.template"], - record_mode=True, - ) - self.assertFalse(result, "Result must be 'False'") - - def test_process_relation_field_value_explode(self): - """Test exploded related field values. - Exploded values represent related record with a child YAML structure. - - Covers the following child functions: - - _process_m2o_value(..) - - _process_x2m_values(..) - """ - - # We are using command with file template for that - file_template = self.env["cx.tower.file.template"].create( - {"name": "Test m2o", "reference": "test_m2o"} - ) - file_template_values = file_template.with_context( - no_yaml_service_fields=True - )._prepare_record_for_yaml() - tag_doge_values = self.tag_doge.with_context( - no_yaml_service_fields=True - )._prepare_record_for_yaml() - tag_pepe_values = self.tag_pepe.with_context( - no_yaml_service_fields=True - )._prepare_record_for_yaml() - command = ( - self.env["cx.tower.command"] - .create( - { - "name": "Command test m2o", - "action": "file_using_template", - "file_template_id": file_template.id, - "tag_ids": [(4, self.tag_doge.id), (4, self.tag_pepe.id)], - } - ) - .with_context(explode_related_record=True) - ) # and this is the actual trigger - - # -- 1 -- - # Record -> Yaml - - # -- 1.1 -- - # Many2one - result = command._process_relation_field_value( - field="file_template_id", - value=(command.file_template_id.id, command.file_template_id.name), - record_mode=True, - ) - self.assertEqual( - result, file_template_values, "Reference was not resolved correctly" - ) - - # -- 1.2 -- - # Many2many - result = command._process_relation_field_value( - field="tag_ids", - value=[self.tag_doge.id, self.tag_pepe.id], - record_mode=True, - ) - self.assertEqual(len(result), 2, "Must be 2 records") - self.assertIn(tag_doge_values, result, "Record ID was not resolved correctly") - self.assertIn(tag_pepe_values, result, "Record ID was not resolved correctly") - - # -- 2 -- - # Yaml -> Record - - # -- 2.1 -- - # Many2one - result = command._process_relation_field_value( - field="file_template_id", value=file_template_values, record_mode=False - ) - self.assertEqual( - result, file_template.id, "Record ID was not resolved correctly" - ) - - # -- 2.2 -- - # Many2many - result = command._process_relation_field_value( - field="tag_ids", value=[tag_doge_values, tag_pepe_values], record_mode=False - ) - self.assertEqual(len(result), 2, "Must be 2 records") - self.assertIn( - (4, self.tag_doge.id), result, "Record ID was not resolved correctly" - ) - self.assertIn( - (4, self.tag_pepe.id), result, "Record ID was not resolved correctly" - ) - # -- 3 -- - # Yaml with non existing reference -> Record - file_template_values.update( - { - "name": "Very new name", - "reference": "such_much_not_reference", - "source": "server", - "file_type": "binary", - } - ) - result = command._process_relation_field_value( - field="file_template_id", value=file_template_values, record_mode=False - ) - - # New record must be created - record = self.env["cx.tower.file.template"].browse(result) - self.assertEqual( - record.name, file_template_values["name"], "New record value doesn't match" - ) - self.assertEqual( - record.reference, - file_template_values["reference"], - "New record value doesn't match", - ) - self.assertEqual( - record.source, - file_template_values["source"], - "New record value doesn't match", - ) - self.assertEqual( - record.file_type, - file_template_values["file_type"], - "New record value doesn't match", - ) - - # -- 4 -- - # Yaml with no reference at all -> Record - values_with_no_references = { - "name": "Sorry no reference here", - "source": "tower", - "file_type": "binary", - } - result = command._process_relation_field_value( - field="file_template_id", value=values_with_no_references, record_mode=False - ) - - # New record must be created - record = self.env["cx.tower.file.template"].browse(result) - - self.assertEqual( - record.name, - values_with_no_references["name"], - "New record value doesn't match", - ) - self.assertEqual( - record.source, - values_with_no_references["source"], - "New record value doesn't match", - ) - self.assertEqual( - record.file_type, - values_with_no_references["file_type"], - "New record value doesn't match", - ) - - # -- 5 -- - # No record -> Yaml - result = command._process_relation_field_value( - field="file_template_id", - value=self.env["cx.tower.file.template"], - record_mode=True, - ) - self.assertFalse(result, "Result must be 'False'") - - def test_update_or_create_related_record(self): - """Test if related record is updated or created correctly""" - - # -- 1 -- - # Update existing values - # We are using file template for that - FileTemplateModel = self.env["cx.tower.file.template"] - file_template = self.env["cx.tower.file.template"].create( - {"name": "Test m2o", "reference": "test_m2o"} - ) - values_to_update = {"name": "Much new name"} - record = FileTemplateModel._update_or_create_related_record( - model=FileTemplateModel, - reference=file_template.reference, - values=values_to_update, - ) - self.assertEqual( - record.name, values_to_update["name"], "Value was not updated properly" - ) - self.assertEqual(record.id, file_template.id, "Same record must be updated") - - # -- 2 -- - # Reference not found. Must create a new record - values_to_update = {"name": "Doge file"} - record = FileTemplateModel._update_or_create_related_record( - model=FileTemplateModel, - reference="doge_file", - values=values_to_update, - create_immediately=True, - ) - self.assertEqual( - record.name, values_to_update["name"], "Value was not updated properly" - ) - self.assertNotEqual(record.id, file_template.id, "New record must be created") - - # -- 2 -- - # Reference not provided. Must create a new record - values_to_update = {"name": "Doge file"} - record = FileTemplateModel._update_or_create_related_record( - model=FileTemplateModel, - reference=False, - values=values_to_update, - create_immediately=True, - ) - self.assertEqual( - record.name, values_to_update["name"], "Value was not updated properly" - ) - self.assertNotEqual(record.id, file_template.id, "New record must be created") - - @tagged("post_install", "-at_install") - def test_prepare_record_truncates_code_for_server_files(self): - """Mixin must set code=False for cx.tower.file when source=='server'.""" - File = self.env["cx.tower.file"] - srv_file = File.create( - { - "name": "srv.log", - "reference": "srvlog", - "source": "server", - "file_type": "text", - "server_dir": "/tmp", - "code": "BIG DATA", - } - ) - rec = srv_file._prepare_record_for_yaml() - self.assertIn("code", rec) - self.assertFalse(rec["code"], "Expected code=False for server-sourced files") - - @tagged("post_install", "-at_install") - def test_prepare_record_keeps_code_for_tower_files(self): - """Mixin must keep code for cx.tower.file when source=='tower'.""" - File = self.env["cx.tower.file"] - tw_file = File.create( - { - "name": "local.txt", - "reference": "localtxt", - "source": "tower", - "file_type": "text", - "server_dir": "/etc", - "code": "SMALL DATA", - } - ) - rec = tw_file._prepare_record_for_yaml() - self.assertEqual( - rec["code"], - "SMALL DATA", - "Expected original code for tower-sourced files", - ) diff --git a/addons/cetmix_tower_yaml/tests/test_yaml_export_wizard.py b/addons/cetmix_tower_yaml/tests/test_yaml_export_wizard.py deleted file mode 100644 index c757a3a..0000000 --- a/addons/cetmix_tower_yaml/tests/test_yaml_export_wizard.py +++ /dev/null @@ -1,375 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -import base64 - -import yaml - -from odoo.exceptions import AccessError, ValidationError - -from odoo.addons.base.tests.common import BaseCommon - - -class TestYamlExportWizard(BaseCommon): - @classmethod - def setUpClass(cls, *args, **kwargs): - super().setUpClass(*args, **kwargs) - - # Used to ensure that the file header - # is present in the YAML code - cls.file_header = """ -# This file is generated with Cetmix Tower. -# Details and documentation: https://cetmix.com/tower -""" - # Create a command - cls.TowerCommand = cls.env["cx.tower.command"] - cls.command_test_wizard = cls.TowerCommand.create( - { - "reference": "test_command_from_yaml", - "name": "Test Command From Yaml", - "code": "echo 'Test Command From Yaml'", - } - ) - cls.command_test_wizard_2 = cls.TowerCommand.create( - { - "reference": "test_command_from_yaml_2", - "name": "Test Command From Yaml 2", - "code": "echo 'Test Command From Yaml 2'", - } - ) - - # Create a flight plan - cls.FlightPlan = cls.env["cx.tower.plan"] - cls.flight_plan_test_wizard = cls.FlightPlan.create( - { - "name": "Test Flight Plan From Yaml", - "line_ids": [ - ( - 0, - 0, - { - "command_id": cls.command_test_wizard.id, - }, - ) - ], - } - ) - - # Create a server template - cls.ServerTemplate = cls.env["cx.tower.server.template"] - cls.server_template_test_wizard = cls.ServerTemplate.create( - { - "name": "Test Server Template From Yaml", - "flight_plan_id": cls.flight_plan_test_wizard.id, - } - ) - - # Create a wizard and trigger onchange - cls.YamlExportWizard = cls.env["cx.tower.yaml.export.wiz"] - cls.test_wizard = cls.YamlExportWizard.with_context( - active_model="cx.tower.server.template", - active_ids=[cls.server_template_test_wizard.id], - ).create({}) - cls.test_wizard.onchange_explode_child_records() - - def test_user_without_export_group_cannot_export(self): - """Test if user without export group cannot export""" - - # Tower manager user without export group - self.user_yaml_export = self.env["res.users"].create( - { - "name": "No Yaml Export User", - "login": "no_yaml_export_user", - "groups_id": [ - (4, self.env.ref("cetmix_tower_server.group_manager").id) - ], - } - ) - with self.assertRaises(AccessError): - self.test_wizard.with_user(self.user_yaml_export).read([]) - - def test_yaml_export_wizard_yaml_generation(self): - """Test code generation of YAML export wizard.""" - - wizard_yaml = """ -# This file is generated with Cetmix Tower. -# Details and documentation: https://cetmix.com/tower -cetmix_tower_yaml_version: 1 -records: -- cetmix_tower_model: command - access_level: manager - reference: test_command_from_yaml - name: Test Command From Yaml - action: ssh_command - allow_parallel_run: false - note: false - path: false - code: echo 'Test Command From Yaml' - server_status: false - no_split_for_sudo: false - if_file_exists: skip - disconnect_file: false -- cetmix_tower_model: command - access_level: manager - reference: test_command_from_yaml_2 - name: Test Command From Yaml 2 - action: ssh_command - allow_parallel_run: false - note: false - path: false - code: echo 'Test Command From Yaml 2' - server_status: false - no_split_for_sudo: false - if_file_exists: skip - disconnect_file: false -""" - - # -- 1 -- - # Test with two commands - context = { - "default_explode_child_records": True, - "default_remove_empty_values": True, - "active_model": "cx.tower.command", - "active_ids": [self.command_test_wizard.id, self.command_test_wizard_2.id], - } - wizard = self.YamlExportWizard.with_context(context).create({}) # pylint: disable=context-overridden # new need a new clean context - wizard.onchange_explode_child_records() - self.assertEqual(wizard.yaml_code, wizard_yaml) - - def test_yaml_export_wizard(self): - """Test the YAML export wizard.""" - - # -- 1 -- - # Test wizard action - result = self.test_wizard.action_generate_yaml_file() - self.assertEqual( - result["type"], "ir.actions.act_window", "Action should be a window" - ) - self.assertEqual( - result["res_model"], - "cx.tower.yaml.export.wiz.download", - "Result model should be the download wizard", - ) - self.assertTrue(result["res_id"], "Wizard should have been created") - - # -- 2 -- - # Ensure download wizard file name is generated - # based on the record reference - download_wizard = self.env["cx.tower.yaml.export.wiz.download"].browse( - result["res_id"] - ) - self.assertEqual( - download_wizard.yaml_file_name, - f"server_template_{self.server_template_test_wizard.reference}.yaml", - "YAML file name should be generated based on record reference", - ) - - # -- 3 -- - # Decode YAML file and check if it's valid - yaml_file_content = base64.decodebytes(download_wizard.yaml_file).decode( - "utf-8" - ) - self.assertEqual( - yaml_file_content, - self.test_wizard.yaml_code, - "YAML file content should be the same as the original YAML code", - ) - - # -- 4 -- - # Test if empty YAML code is handled correctly - self.test_wizard.yaml_code = "" - with self.assertRaises(ValidationError): - self.test_wizard.action_generate_yaml_file() - - def test_reference_object_uniqueness(self): - """ - Ensure each reference is exported as a full object only once - (other times only as ref). - """ - - # Prepare YAML export for flight_plan with two same commands - self.flight_plan_test_wizard.line_ids = [ - (0, 0, {"command_id": self.command_test_wizard.id}), - (0, 0, {"command_id": self.command_test_wizard.id}), - ] - - # Prepare YAML code - self.test_wizard.onchange_explode_child_records() - yaml_data = yaml.safe_load(self.test_wizard.yaml_code) - - # reference counters - ref_full = set() - ref_refs = set() - - # Recursively walk through the YAML data and count references - def walk(obj): - if isinstance(obj, dict): - ref = obj.get("reference") - # dict only with "reference" = ref, otherwise — full object - if ref: - if list(obj.keys()) == ["reference"]: - ref_refs.add(ref) - else: - ref_full.add(ref) - for v in obj.values(): - walk(v) - elif isinstance(obj, list): - for v in obj: - walk(v) - - # Walk through the YAML data - walk(yaml_data["records"]) - - # Each reference as a full object — only once - for ref in ref_full: - self.assertEqual( - list(ref_full).count(ref), - 1, - f"Reference '{ref}' appears as a full object more than once", - ) - # Check that no full objects appear more than once - self.assertEqual( - len(ref_full), - len(set(ref_full)), - "Some full objects appear more than once", - ) - - # Check that for each ref there is no only reference, but no full object - for ref in ref_refs: - self.assertIn( - ref, - ref_full, - f"Reference '{ref}' is used only as a reference, " - "but no full object present", - ) - - def test_export_required_model_name_in_yaml(self): - """ - Test that the model name is required in the YAML file for each record - """ - # create a command to run flight plan - command_run_flight_plan = self.TowerCommand.create( - { - "name": "Run Flight Plan", - "action": "plan", - "flight_plan_id": self.flight_plan_test_wizard.id, - } - ) - # export 2 commands: command_run_flight_plan and command_test_wizard - wizard = self.YamlExportWizard.with_context( - active_model="cx.tower.command", - active_ids=[command_run_flight_plan.id, self.command_test_wizard.id], - ).create({}) - - wizard.onchange_explode_child_records() - - yaml_data = yaml.safe_load(wizard.yaml_code) - - # check that the model name is present in the YAML file for each record - for record in yaml_data["records"]: - self.assertIn("cetmix_tower_model", record) - - def test_default_yaml_file_name_is_used(self): - """ - Wizard should pre-fill `yaml_file_name` with the auto-generated - value that ends with '.yaml' and contains the model prefix. - """ - wiz = self.YamlExportWizard.with_context( - active_model="cx.tower.command", - active_ids=[self.command_test_wizard.id], - ).create({}) - - default_name = wiz.yaml_file_name - - self.assertFalse( - default_name.endswith(".yaml"), - "Default file name must NO have .yaml suffix", - ) - self.assertIn( - "command_", - default_name, - "Default file name should include model prefix", - ) - - def test_yaml_file_name_is_auto_fixed(self): - """ - When the user assigns an invalid name, wizard should auto-sanitise - it to a safe *basename* (lowercase, underscores, no extension). - """ - wiz = self.YamlExportWizard.with_context( - active_model="cx.tower.command", - active_ids=[self.command_test_wizard.id], - ).create({}) - - # user enters a 'dirty' name with spaces, capitals, symbols - wiz.write({"yaml_file_name": "My File!@# .YAML"}) - - # write() override strips to a basename WITHOUT '.yaml' - self.assertEqual( - wiz.yaml_file_name, - "my_file", - "Wizard field must hold only the cleaned basename, without extension", - ) - - def test_action_generate_appends_extension(self): - """ - When generating the download record, the system must append - the `.yaml` extension to the sanitized basename. - """ - wiz = self.YamlExportWizard.with_context( - active_model="cx.tower.command", - active_ids=[self.command_test_wizard.id], - ).create({}) - wiz.onchange_explode_child_records() - act = wiz.action_generate_yaml_file() - download = self.env["cx.tower.yaml.export.wiz.download"].browse(act["res_id"]) - self.assertTrue(download.yaml_file_name.endswith(".yaml")) - - def test_custom_requires_text(self): - """Creating a template with license 'custom' but no text must fail""" - with self.assertRaises(ValidationError): - self.env["cx.tower.yaml.manifest.tmpl"].create( - { - "name": "Bad Manifest", - "license": "custom", - } - ) - - tmpl_ok = self.env["cx.tower.yaml.manifest.tmpl"].create( - { - "name": "Good Manifest", - "license": "custom", - "license_text": "Custom license terms", - } - ) - self.assertEqual(tmpl_ok.license, "custom") - self.assertEqual(tmpl_ok.license_text, "Custom license terms") - - with self.assertRaises(ValidationError): - self.env["cx.tower.yaml.manifest.tmpl"].create( - { - "name": "Bad Manifest 2", - "license": "custom", - "license_text": " ", - } - ) - - def test_wizard_resets_price_on_license_change(self): - """Wizard must reset price/currency when license changes away from 'custom'""" - wiz = self.YamlExportWizard.new( - { - "manifest_license": "custom", - "manifest_price": 42.0, - "manifest_currency": "EUR", - } - ) - wiz.manifest_license = "agpl-3" - wiz._onchange_manifest_license() - self.assertEqual(wiz.manifest_price, 0.0) - self.assertFalse(wiz.manifest_currency) - - wiz.manifest_price = 7.5 - wiz.manifest_currency = "USD" - wiz.manifest_license = "custom" - wiz._onchange_manifest_license() - self.assertEqual(wiz.manifest_price, 7.5) - self.assertEqual(wiz.manifest_currency, "USD") diff --git a/addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py b/addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py deleted file mode 100644 index 9441ca3..0000000 --- a/addons/cetmix_tower_yaml/tests/test_yaml_import_wizard.py +++ /dev/null @@ -1,703 +0,0 @@ -# Copyright (C) 2024 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - - -import base64 - -import yaml - -from odoo import _ -from odoo.exceptions import ValidationError -from odoo.tests import TransactionCase -from odoo.tools import mute_logger - - -class TestTowerYamlImportWizUpload(TransactionCase): - """Test Tower YAML Import Wizard Upload""" - - @classmethod - def setUpClass(cls): - super().setUpClass() - - # Variables - cls.Variable = cls.env["cx.tower.variable"] - cls.variable_yaml_test = cls.Variable.create( - {"name": "YAML Test", "reference": "yaml_test"} - ) - cls.variable_yaml_url = cls.Variable.create( - {"name": "YAML URL", "reference": "yaml_url"} - ) - - # Tags - cls.Tag = cls.env["cx.tower.tag"] - cls.tag_yaml_test = cls.Tag.create( - {"name": "YAML Test", "reference": "yaml_test"} - ) - cls.tag_another_yaml_test = cls.Tag.create( - {"name": "Another YAML Test", "reference": "another_yaml_test"} - ) - - # Commands - cls.Command = cls.env["cx.tower.command"] - cls.command_yaml_test = cls.Command.create( - {"name": "Test Yaml Command", "reference": "test_yaml_command"} - ) - - # Flight Plan - cls.FlightPlan = cls.env["cx.tower.plan"] - cls.flight_plan_yaml_test = cls.FlightPlan.create( - { - "name": "Test Yaml Flight Plan", - "reference": "test_yaml_flight_plan", - "line_ids": [ - ( - 0, - 0, - { - "condition": False, - "use_sudo": False, - "command_id": cls.command_yaml_test.id, - }, - ), - ], - } - ) - - # Create Server Template used for testing - cls.server_template_yaml_test = cls.env["cx.tower.server.template"].create( - { - "name": "Test Server Template", - "tag_ids": [ - (4, cls.tag_yaml_test.id), - (4, cls.tag_another_yaml_test.id), - ], - "variable_value_ids": [ - ( - 0, - 0, - { - "variable_id": cls.variable_yaml_test.id, - "value_char": "Some Test Value", - }, - ), - ( - 0, - 0, - { - "variable_id": cls.variable_yaml_url.id, - "value_char": "https://cetmix.com", - }, - ), - ], - "flight_plan_id": cls.flight_plan_yaml_test.id, - } - ) - - # Server Logs - cls.ServerLog = cls.env["cx.tower.server.log"] - cls.server_log_yaml_test = cls.ServerLog.create( - { - "name": "Test Server Log", - "reference": "test_server_log", - "command_id": cls.command_yaml_test.id, - "log_type": "command", - "server_template_id": cls.server_template_yaml_test.id, - } - ) - - # Create an export wizard and generate YAML code - context = { - "active_model": "cx.tower.server.template", - "active_ids": [cls.server_template_yaml_test.id], - } - cls.export_wizard = ( - cls.env["cx.tower.yaml.export.wiz"].with_context(context).create({}) # pylint: disable=context-overridden # new need a new clean context - ) - cls.export_wizard.onchange_explode_child_records() - cls.export_wizard.action_generate_yaml_file() - cls.yaml_code = cls.export_wizard.yaml_code - cls.yaml_file = base64.b64encode(cls.yaml_code.encode("utf-8")) - - # YAML import upload wizard - cls.YamlImportWizUpload = cls.env["cx.tower.yaml.import.wiz.upload"] - cls.yaml_upload_wizard = cls.YamlImportWizUpload.create( - {"yaml_file": cls.yaml_file, "file_name": "test_yaml_file.yaml"} - ) - - # YAML import wizard - cls.import_wizard_action = cls.yaml_upload_wizard.action_import_yaml() - cls.import_wizard = cls.env[cls.import_wizard_action["res_model"]].browse( - cls.import_wizard_action["res_id"] - ) - cls.import_wizard.if_record_exists = "update" - - def test_extract_yaml_data(self): - """Test extract YAML data from file""" - - # -- 1 -- - # Test if YAML file is valid - extracted_yaml_data = self.yaml_upload_wizard._extract_yaml_data() - self.assertEqual( - extracted_yaml_data, - self.yaml_code, - "YAML code is not extracted correctly", - ) - - # -- 2 -- - # Test if invalid model is handled properly - # Replace model name with invalid model - self.invalid_yaml_code = self.yaml_code.replace( - "server_template", "invalid_model" - ) - self.invalid_yaml_file = base64.b64encode( - self.invalid_yaml_code.encode("utf-8") - ) - self.yaml_upload_wizard.yaml_file = self.invalid_yaml_file - with self.assertRaises(ValidationError) as e: - self.yaml_upload_wizard._extract_yaml_data() - self.assertEqual( - str(e.exception), - _("'invalid_model' is not a valid model"), - "Exception message does not match", - ) - # -- 3 -- - # Test if non YAML supported model is handled properly - # Replace model name with non YAML supported model - self.non_yaml_supported_yaml_code = self.yaml_code.replace( - "server_template", "command_run_wizard" - ) - self.non_yaml_supported_yaml_file = base64.b64encode( - self.non_yaml_supported_yaml_code.encode("utf-8") - ) - self.yaml_upload_wizard.yaml_file = self.non_yaml_supported_yaml_file - with self.assertRaises(ValidationError) as e: - self.yaml_upload_wizard._extract_yaml_data() - self.assertEqual( - str(e.exception), - _("Model 'command_run_wizard' does not support YAML import"), - "Exception message does not match", - ) - - # -- 4 -- - # Test if YAML that is not a dictionary is handled properly - self.invalid_yaml_file = base64.b64encode(b"Invalid YAML file") - self.yaml_upload_wizard.yaml_file = self.invalid_yaml_file - with self.assertRaises(ValidationError) as e: - self.yaml_upload_wizard._extract_yaml_data() - self.assertEqual( - str(e.exception), - _("Yaml file doesn't contain valid data"), - "Exception message does not match", - ) - - # -- 5 -- - # Test if TypeError is handled properly - self.non_unicode_yaml_file = base64.b64encode(b"\x80") - self.yaml_upload_wizard.yaml_file = self.non_unicode_yaml_file - with self.assertRaises(ValidationError) as e: - self.yaml_upload_wizard._extract_yaml_data() - self.assertEqual( - str(e.exception), - _("YAML file cannot be decoded properly"), - "Exception message does not match", - ) - - # -- 6 -- - # Test if YAML file is empty - self.empty_yaml_file = "" - self.yaml_upload_wizard.yaml_file = self.empty_yaml_file - with self.assertRaises(ValidationError) as e: - self.yaml_upload_wizard._extract_yaml_data() - self.assertEqual( - str(e.exception), - _("File is empty"), - "Exception message does not match", - ) - - # -- 7 -- - # Test if YAML file with unsupported YAML version is handled properly - yaml_with_unsupported_version = self.yaml_code.replace( - f"cetmix_tower_yaml_version: {self.FlightPlan.CETMIX_TOWER_YAML_VERSION}", - f"cetmix_tower_yaml_version: {self.FlightPlan.CETMIX_TOWER_YAML_VERSION + 1}", # noqa: E501 - ) - self.unsupported_yaml_version_yaml_file = base64.b64encode( - yaml_with_unsupported_version.encode("utf-8") - ) - self.yaml_upload_wizard.yaml_file = self.unsupported_yaml_version_yaml_file - with self.assertRaises(ValidationError) as e: - self.yaml_upload_wizard._extract_yaml_data() - self.assertEqual( - str(e.exception), - _( - "YAML version is higher than version" - " supported by your Cetmix Tower instance." - " %(code_version)s > %(tower_version)s", - code_version=self.FlightPlan.CETMIX_TOWER_YAML_VERSION + 1, - tower_version=self.FlightPlan.CETMIX_TOWER_YAML_VERSION, - ), - "Exception message does not match", - ) - - # -- 8 -- - # Test YAML file with no records - self.import_wizard.yaml_code = "cetmix_tower_yaml_version: 1" - with self.assertRaises(ValidationError) as e: - self.import_wizard.action_import_yaml() - self.assertEqual( - str(e.exception), - _("YAML file doesn't contain any records"), - "Exception message does not match", - ) - - def test_action_import_yaml_skip_if_exists(self): - """Test YAML import wizard action when skipping an existing record""" - - self.import_wizard.if_record_exists = "skip" - - # Run import wizard action - import_wizard_result_action = self.import_wizard.action_import_yaml() - - # Test if action is composed properly - self.assertEqual( - import_wizard_result_action["type"], - "ir.actions.client", - "Import wizard action type is not correct", - ) - self.assertEqual( - import_wizard_result_action["tag"], - "display_notification", - "Import wizard action tag is not correct", - ) - self.assertEqual( - import_wizard_result_action["params"]["title"], - _("Record Import"), - "Import wizard action title is not correct", - ) - self.assertEqual( - import_wizard_result_action["params"]["message"], - _("No records were created or updated"), - "Import wizard action message is not correct", - ) - self.assertEqual( - import_wizard_result_action["params"]["sticky"], - True, - "Import wizard action sticky is not correct", - ) - self.assertEqual( - import_wizard_result_action["params"]["type"], - "warning", - "Import wizard action type is not correct", - ) - - def test_action_import_yaml_update_existing_record(self): - """Test YAML import wizard action when updating an existing record""" - - # -- 1 -- - # Test if new import wizard record is created properly - self.assertEqual( - self.import_wizard_action["res_model"], - "cx.tower.yaml.import.wiz", - "Import wizard action model is not correct", - ) - self.assertEqual( - self.import_wizard_action["view_mode"], - "form", - "Import wizard action view mode is not correct", - ) - - # -- 2 -- - # Modify Server Template name and variable value - self.import_wizard.yaml_code = self.import_wizard.yaml_code.replace( - "name: Test Server Template", - "name: Updated Test Server Template", - ).replace( - "value_char: Some Test Value", - "value_char: Updated Test Value", - ) - variable_value_to_update = ( - self.server_template_yaml_test.variable_value_ids.filtered( - lambda v: v.value_char == "Some Test Value" - ) - ) - - # Run import wizard action another time - import_wizard_result_action = self.import_wizard.action_import_yaml() - - # -- 3 -- - # Test if record is updated properly - self.assertEqual( - import_wizard_result_action["res_model"], - "cx.tower.server.template", - "Import wizard action model is not correct", - ) - self.assertEqual( - import_wizard_result_action["domain"], - [("id", "in", self.server_template_yaml_test.ids)], - "ID must match existing record ID", - ) - self.assertEqual( - self.server_template_yaml_test.name, - "Updated Test Server Template", - "Record is not updated properly", - ) - self.assertEqual( - variable_value_to_update.value_char, - "Updated Test Value", - "Variable value is not updated properly", - ) - - # -- 4 -- - # Test if server log remains the same - self.assertEqual( - len(self.server_template_yaml_test.server_log_ids), - 1, - "Server Log must remain the same", - ) - self.assertEqual( - self.server_log_yaml_test.id, - self.server_template_yaml_test.server_log_ids.id, - "Server Log must remain the same", - ) - - def test_action_import_yaml_create_new_record(self): - """Test YAML import wizard action when creating a new record""" - self.import_wizard.if_record_exists = "create" - with mute_logger("odoo.addons.cetmix_tower_yaml.models.cx_tower_yaml_mixin"): - import_wizard_result_action = self.import_wizard.action_import_yaml() - - # -- 1 -- - # Test if new record is created instead of updating existing one - self.assertEqual( - import_wizard_result_action["res_model"], - "cx.tower.server.template", - "Import wizard action model is not correct", - ) - self.assertNotEqual( - import_wizard_result_action["domain"], - f"[('id', '=', {self.server_template_yaml_test.ids})]", - "ID must not match existing record ID", - ) - - # -- 2 -- - # Ensure that existing flight plan is used instead of creating a new one - new_server_template = self.env[import_wizard_result_action["res_model"]].search( - import_wizard_result_action["domain"] - ) - self.assertEqual( - new_server_template.flight_plan_id, - self.flight_plan_yaml_test, - "Existing flight plan must be used", - ) - - # -- 3 -- - # Ensure that existing tags are used instead of creating new ones - for tag in self.server_template_yaml_test.tag_ids: - self.assertIn( - tag, - new_server_template.tag_ids, - "Existing tag must be used", - ) - - # -- 4 -- - # Ensure that new variable values are created - for variable_value in self.server_template_yaml_test.variable_value_ids: - self.assertNotIn( - variable_value, - new_server_template.variable_value_ids, - "New variable value must be created instead of updating existing one", - ) - - # -- 5 -- - # Test if server log is created instead of updated - for server_log in self.server_template_yaml_test.server_log_ids: - self.assertNotIn( - server_log, - new_server_template.server_log_ids, - "New Server Log must be created instead of updating existing one", - ) - - def test_extract_secret_names(self): - """Test extract secret names from YAML data""" - - # NB: this is not a real model, it's just for testing - yaml_code = """cetmix_tower_yaml_version: 1 -records: -- cetmix_tower_model: test_model - access_level: manager - reference: such_much_test_record - name: Such Much Command - action: file_using_template - allow_parallel_run: false - note: Just a note - os_ids: false - tag_ids: false - path: false - file_template_id: false - flight_plan_id: false - code: false - variable_ids: false - secret_ids: false - ssh_key_id: - reference: test_ssh_key - name: Test SSH Key - key_type: k - note: false -- cetmix_tower_model: another_test_model - reference: such_much_test_record_2 - name: Such Much Test Record 2 - note: Just a note 2 - ssh_key_id: - reference: test_ssh_key - name: Test SSH Key - key_type: k - note: false - secret_ids: - - reference: secret_2 - name: Secret 2 - key_type: s - note: false - - reference: secret_3 - name: Secret 3 - key_type: s - note: false -- cetmix_tower_model: another_test_model - reference: such_much_test_record_3 - name: Such Much Test Record 3 - note: Just a note 3 - ssh_key_id: - reference: another_ssh_key - name: Another SSH Key - sub_record: - reference: such_much_test_record_4 - name: Such Much Test Record 4 - note: Just a note 4 - secret_ids: - - reference: secret_1 - name: Secret 3 - key_type: s - note: false - - reference: secret_2 - name: Secret 4 - key_type: s - note: false - file_template_id: - reference: my_custom_test_template - name: Such much demo - source: tower - file_type: text - server_dir: /var/log/my/files - file_name: much_logs.txt - keep_when_deleted: false - tag_ids: false - note: Hey! - code: false - variable_ids: false - secret_ids: false - flight_plan_id: false - code: false - variable_ids: false - secret_ids: - - reference: secret_1 - name: Secret 1 - key_type: s - note: false - - reference: secret_2 - name: Secret 2 - key_type: s - note: false -""" - secret_list = self.env["cx.tower.yaml.import.wiz"]._extract_secret_names( - yaml.safe_load(yaml_code) - ) - # We expect 6 secrets in the list: - # 2 keys: 'Test SSH Key', 'Another SSH Key' - # 4 secrets: 'Secret 3', 'Secret 4', 'Secret 1', 'Secret 2' - self.assertEqual(len(secret_list), 6, "Secret list length is not correct") - self.assertIn("Test SSH Key", secret_list, "Key is not in the list") - self.assertIn("Another SSH Key", secret_list, "Key is not in the list") - self.assertIn("Secret 3", secret_list, "Key is not in the list") - self.assertIn("Secret 4", secret_list, "Key is not in the list") - self.assertIn("Secret 1", secret_list, "Key is not in the list") - self.assertIn("Secret 2", secret_list, "Key is not in the list") - - def test_extract_secret_names_with_key_id(self): - """Test extract secret names when secrets are nested under key_id""" - yaml_code = """cetmix_tower_yaml_version: 1 -records: -- cetmix_tower_model: test_model - reference: rec_1 - name: Test Record - secret_ids: - - key_id: - reference: secret_1 - name: Nested Secret 1 - - key_id: - reference: secret_2 - name: Nested Secret 2 - ssh_key_id: - name: SSH Key Nested -""" - secret_list = self.env["cx.tower.yaml.import.wiz"]._extract_secret_names( - yaml.safe_load(yaml_code) - ) - - # We expect 3 secrets total: - # - SSH Key Nested (from ssh_key_id) - # - Nested Secret 1 - # - Nested Secret 2 - self.assertCountEqual( - secret_list, - ["Nested Secret 1", "Nested Secret 2", "SSH Key Nested"], - "Unexpected secrets extracted for nested structure", - ) - - def test_create_records_different_models(self): - """Test create records with different models""" - - yaml_code = """cetmix_tower_yaml_version: 1 -records: -- cetmix_tower_model: command - access_level: manager - reference: much_much_command - name: Much Much Command - action: file_using_template - allow_parallel_run: false - note: Just a note - os_ids: false - tag_ids: false - path: false - file_template_id: false - flight_plan_id: false - code: false - variable_ids: false - secret_ids: false - ssh_key_id: - reference: test_ssh_key - name: Test SSH Key - key_type: k - note: false -- cetmix_tower_model: server_template - reference: wow_much_server_template - name: Wow Much Server Template - note: Just a note 2 -- cetmix_tower_model: tag - reference: such_much_tag - name: Such Much Tag -""" - # Create a new command record - self.import_wizard.if_record_exists = "update" - self.import_wizard.yaml_code = yaml_code - - action = self.import_wizard.action_import_yaml() - - # Check if action is composed properly - self.assertEqual( - action["type"], - "ir.actions.client", - "Import wizard action type is not correct", - ) - self.assertEqual( - action["tag"], - "display_notification", - "Import wizard action tag is not correct", - ) - self.assertEqual( - action["params"]["title"], - _("Record Import"), - "Import wizard action title is not correct", - ) - self.assertEqual( - action["params"]["type"], - "success", - "Import wizard action type is not correct", - ) - self.assertEqual( - action["params"]["sticky"], - True, - "Import wizard action sticky is not correct", - ) - - # Check command - self.assertTrue( - self.Command.get_by_reference("much_much_command"), - "Command must be created", - ) - - # Check server template - self.assertTrue( - self.env["cx.tower.server.template"].get_by_reference( - "wow_much_server_template" - ), - "Server template must be created", - ) - - # Check tag - self.assertTrue( - self.Tag.get_by_reference("such_much_tag"), "Tag must be created" - ) - - def test_yaml_import_server_without_password(self): - """Wizard should import server without ssh_password.""" - yaml_code = ( - "cetmix_tower_yaml_version: 1\n" - "records:\n" - "- reference: srv_nopass\n" - " cetmix_tower_model: server\n" - " name: YAML NoPass\n" - " ssh_auth_mode: p\n" - " ssh_username: root\n" - " ip_v4_address: 10.0.0.3\n" - ) - wiz = self.env["cx.tower.yaml.import.wiz"].create( - { - "yaml_code": yaml_code, - "if_record_exists": "create", - } - ) - wiz.action_import_yaml() - - srv = self.env["cx.tower.server"].get_by_reference("srv_nopass") - self.assertTrue(srv, "Server was not created") - self.assertFalse( - srv._get_secret_value("ssh_password"), - "ssh_password must stay empty after import", - ) - - def test_orm_create_server_requires_password(self): - """Creating a server via ORM/UI must fail when ssh_password is missing.""" - with self.assertRaises(ValidationError) as err: - self.env["cx.tower.server"].create( - { - "reference": "srv_ui", - "name": "UI NoPass", - "ssh_auth_mode": "p", - "ssh_username": "root", - "ip_v4_address": "10.0.0.2", - } - ) - self.assertIn("Please provide SSH password", str(err.exception)) - - def test_yaml_import_server_with_skip_ssh_check(self): - """Explicit skip_ssh_settings_check also bypasses password validation.""" - yaml_code = ( - "cetmix_tower_yaml_version: 1\n" - "records:\n" - "- reference: srv_skip\n" - " cetmix_tower_model: server\n" - " name: YAML Skip Check\n" - " ssh_auth_mode: p\n" - " ssh_username: root\n" - " ip_v4_address: 10.0.0.4\n" - ) - wiz = self.env["cx.tower.yaml.import.wiz"].create( - { - "yaml_code": yaml_code, - "if_record_exists": "create", - } - ) - wiz.with_context(skip_ssh_settings_check=True).action_import_yaml() - - srv = self.env["cx.tower.server"].get_by_reference("srv_skip") - self.assertTrue( - srv, "Server must be created when skip_ssh_settings_check is set" - ) diff --git a/addons/cetmix_tower_yaml/views/cx_tower_command_view.xml b/addons/cetmix_tower_yaml/views/cx_tower_command_view.xml deleted file mode 100644 index 08dece7..0000000 --- a/addons/cetmix_tower_yaml/views/cx_tower_command_view.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - cx.tower.command.yaml.view.form - cx.tower.command - - - - -
-

You must be a member of the "YAML/Export" group to export data as YAML.

-
-