diff --git a/.copier-answers.yml b/.copier-answers.yml index 6ab853db..290635ae 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -1,5 +1,5 @@ # Do NOT update manually; changes here will be overwritten by Copier -_commit: v1.7.0-262-ga2c21e9 +_commit: v1.7.0-266-gb1862bc _src_path: https://github.com/cetmix/cetmix-addons-repo-template.git additional_ruff_rules: [] ci: GitHub diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 13be940c..03e9d76e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -69,5 +69,5 @@ jobs: - name: Update .pot files run: oca_export_and_push_pot https://x-access-token:${{ secrets.GIT_PUSH_TOKEN }}@github.com/${{ github.repository }} - if: ${{ matrix.makepot == 'true' && github.event_name == 'push' && github.repository_owner == '{{ org_slug }}' }} + if: ${{ matrix.makepot == 'true' && github.event_name == 'push' }} diff --git a/.ruff.toml b/.ruff.toml index d75c6d97..fbf5ccdd 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -8,6 +8,7 @@ extend-select = [ "E501", # line too long (default 88) "I", # isort ] +extend-safe-fixes = ["UP008"] exclude = ["setup/*"] [format] diff --git a/README.md b/README.md index 8654ddde..62b484c6 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ Available addons ---------------- addon | version | maintainers | summary --- | --- | --- | --- -[cetmix_tower_server](cetmix_tower_server/) | 14.0.0.4.2 | | Flexible Server Management directly from Odoo +[cetmix_tower_server](cetmix_tower_server/) | 14.0.0.4.4 | | Flexible Server Management directly from Odoo [cetmix_tower_server_notify_backend](cetmix_tower_server_notify_backend/) | 14.0.1.0.0 | | Backend notifications for Cetmix Tower [cetmix_tower_server_queue](cetmix_tower_server_queue/) | 14.0.1.0.3 | | OCA Queue implementation for Cetmix Tower Server [cetmix_tower_yaml](cetmix_tower_yaml/) | 14.0.1.0.0 | | Cetmix Tower YAML export/import diff --git a/cetmix_tower_server/README.rst b/cetmix_tower_server/README.rst index 217ad553..a3a660f2 100644 --- a/cetmix_tower_server/README.rst +++ b/cetmix_tower_server/README.rst @@ -7,7 +7,7 @@ Cetmix Tower Server Management !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:46e220fd464cf2a9911e7720baa63defb7aefd08bb9c32e684b63cc00b9ddd0e + !! source digest: sha256:b7a9d72e69a49390595260c339932330ab5ecfb46e56b3513c54f5dd94316a34 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/cetmix_tower_server/__manifest__.py b/cetmix_tower_server/__manifest__.py index 2add4cb8..da345e23 100644 --- a/cetmix_tower_server/__manifest__.py +++ b/cetmix_tower_server/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Cetmix Tower Server Management", "summary": "Flexible Server Management directly from Odoo", - "version": "14.0.0.4.2", + "version": "14.0.0.4.4", "category": "Productivity", "website": "https://cetmix.com", "author": "Cetmix", @@ -42,7 +42,6 @@ "views/cx_tower_server_view.xml", "views/cx_tower_os_view.xml", "views/cx_tower_tag_view.xml", - "views/cx_tower_interpreter_view.xml", "views/cx_tower_variable_view.xml", "views/cx_tower_variable_value_view.xml", "views/cx_tower_command_view.xml", diff --git a/cetmix_tower_server/demo/demo_data.xml b/cetmix_tower_server/demo/demo_data.xml index e8d23c3e..1fc72805 100644 --- a/cetmix_tower_server/demo/demo_data.xml +++ b/cetmix_tower_server/demo/demo_data.xml @@ -42,6 +42,7 @@ Demo Server #1 1 + stopped localhost admin password @@ -59,6 +60,7 @@ 2 Demo Server #2 + running localhost admin password @@ -171,10 +173,15 @@ URL - Odoo Version + Odoo Version odoo__version o + + Language + language + o + Version @@ -185,11 +192,92 @@ Branch + + + + 14.0 + 14.0 + 10 + + + + 15.0 + 15.0 + 20 + + + + 16.0 + 16.0 + 30 + + + + 17.0 + 17.0 + 40 + + + + 18.0 + 18.0 + 50 + + + + + English (US) + en_us + 10 + + + + Italian + it + 20 + + + + Spanish (Mexican) + es_mx + 30 + + + + German + de + 40 + + + + German (Switzerland) + de_ch + 50 + + + + + + /home/{{ tower.server.username }}/tower/{{ branch }} + + + + + + + + + + + + - /opt/cetmix-tower + /opt/{{ tower.server.reference }}/cetmix-tower @@ -201,6 +289,17 @@ staging + + + + + + + + + + + prod @@ -350,6 +449,11 @@ else: production + + + + + 20 @@ -357,7 +461,7 @@ else: {{ branch }} == 'prod' and {{ odoo_version }} == "17.0" + >{{ tower.server.status }} == 'running' and {{ odoo_version }} == "17.0" @@ -467,13 +571,29 @@ else: - /opt/cetmix-tower + /opt/{{ tower.server.reference }}/cetmix-tower/{{ branch }} https://cetmix.com + + + + + + + + + + + Command Log for Server #1 @@ -569,30 +689,5 @@ else: final_value - - - - 14.0 - 10 - - - - 15.0 - 20 - - - - 16.0 - 30 - - - - 17.0 - 40 - - - - 18.0 - 50 - + diff --git a/cetmix_tower_server/i18n/cetmix_tower_server.pot b/cetmix_tower_server/i18n/cetmix_tower_server.pot index 1d93feb2..feac4862 100644 --- a/cetmix_tower_server/i18n/cetmix_tower_server.pot +++ b/cetmix_tower_server/i18n/cetmix_tower_server.pot @@ -46,6 +46,18 @@ msgid "" " " msgstr "" +#. module: cetmix_tower_server +#: code:addons/cetmix_tower_server/models/cx_tower_server_template.py:0 +#, python-format +msgid " - Empty values for variables: %(variables)s" +msgstr "" + +#. module: cetmix_tower_server +#: code:addons/cetmix_tower_server/models/cx_tower_server_template.py:0 +#, python-format +msgid " - Missing variables: %(variables)s" +msgstr "" + #. module: cetmix_tower_server #: code:addons/cetmix_tower_server/models/cx_tower_plan_line_action.py:0 #, python-format @@ -131,6 +143,22 @@ msgid "" " triggered" msgstr "" +#. module: cetmix_tower_server +#: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_command_view_form +msgid "" +"hashlib: Python 'hashlib' library.\n" +" Available methods: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'sha3_224', 'sha3_256',
\n" +" 'sha3_384', 'sha3_512', 'shake_128', 'shake_256', 'blake2b', 'blake2s', 'md5', 'new'" +msgstr "" + +#. module: cetmix_tower_server +#: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_command_view_form +msgid "" +"hmac: Python 'hmac' library. Use 'new' to create HMAC objects.
\n" +" Available methods on the HMAC *object*: 'update', 'copy', 'digest', 'hexdigest'.
\n" +" Module-level function: 'compare_digest'." +msgstr "" + #. module: cetmix_tower_server #: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_command_view_form msgid "json: Python 'json' library. Available methods: 'dumps'" @@ -332,6 +360,12 @@ msgstr "" msgid "Add a new file template" msgstr "" +#. module: cetmix_tower_server +#: code:addons/cetmix_tower_server/models/cetmix_tower.py:0 +#, python-format +msgid "All connection connection attempts have failed." +msgstr "" + #. module: cetmix_tower_server #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command__allow_parallel_run #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan__allow_parallel_run @@ -413,14 +447,12 @@ msgstr "" #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_server_template_create_wizard_line__variable_reference #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_tag__reference #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_variable__reference +#: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_variable_option__reference #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_variable_value__reference #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_variable_value__variable_reference -#: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_file_template_view_form #: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_os_view_form #: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_plan_line_view_form #: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_server_log_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_server_template_view_form -#: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_server_view_form #: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_tag_view_form msgid "" "Can contain English letters, digits and '_'. Leave blank to autogenerate" @@ -527,11 +559,6 @@ msgstr "" msgid "Cetmix Tower Flight Plan Log" msgstr "" -#. module: cetmix_tower_server -#: model:ir.model,name:cetmix_tower_server.model_cx_tower_interpreter -msgid "Cetmix Tower Interpreter" -msgstr "" - #. module: cetmix_tower_server #: model:ir.model,name:cetmix_tower_server.model_cx_tower_os msgid "Cetmix Tower Operating System" @@ -567,6 +594,11 @@ msgstr "" msgid "Cetmix Tower Variable" msgstr "" +#. module: cetmix_tower_server +#: model:ir.model,name:cetmix_tower_server.model_cx_tower_variable_option +msgid "Cetmix Tower Variable Options" +msgstr "" + #. module: cetmix_tower_server #: model:ir.model,name:cetmix_tower_server.model_cx_tower_variable_value msgid "Cetmix Tower Variable Values" @@ -617,7 +649,6 @@ msgid "Code On Server" msgstr "" #. module: cetmix_tower_server -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__color #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os__color #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan__color #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server__color @@ -708,11 +739,22 @@ msgstr "" msgid "Configuration" msgstr "" +#. module: cetmix_tower_server +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server_template_create_wizard__line_ids +msgid "Configuration Variables" +msgstr "" + #. module: cetmix_tower_server #: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_server_template_create_wizard_view_form msgid "Confirm" msgstr "" +#. module: cetmix_tower_server +#: code:addons/cetmix_tower_server/models/cetmix_tower.py:0 +#, python-format +msgid "Connection successful." +msgstr "" + #. module: cetmix_tower_server #: code:addons/cetmix_tower_server/models/cx_tower_server.py:0 #, python-format @@ -721,6 +763,12 @@ msgid "" "%(res)s" msgstr "" +#. module: cetmix_tower_server +#: code:addons/cetmix_tower_server/models/cetmix_tower.py:0 +#, python-format +msgid "Connection timed out after %(attempts)s attempts. Error: %(err)s" +msgstr "" + #. module: cetmix_tower_server #: code:addons/cetmix_tower_server/models/cx_tower_server_template.py:0 #: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_server_template_view_form @@ -745,7 +793,6 @@ msgstr "" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_log__create_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file__create_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template__create_uid -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__create_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key__create_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os__create_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan__create_uid @@ -760,6 +807,7 @@ msgstr "" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server_template_create_wizard_line__create_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_tag__create_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable__create_uid +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_option__create_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value__create_uid msgid "Created by" msgstr "" @@ -770,7 +818,6 @@ msgstr "" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_log__create_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file__create_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template__create_date -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__create_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key__create_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os__create_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan__create_date @@ -785,6 +832,7 @@ msgstr "" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server_template_create_wizard_line__create_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_tag__create_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable__create_date +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_option__create_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value__create_date msgid "Created on" msgstr "" @@ -850,7 +898,6 @@ msgstr "" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_log__display_name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file__display_name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template__display_name -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__display_name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key__display_name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key_mixin__display_name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os__display_name @@ -869,6 +916,7 @@ msgstr "" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_template_mixin__display_name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable__display_name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_mixin__display_name +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_option__display_name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value__display_name msgid "Display Name" msgstr "" @@ -996,6 +1044,12 @@ msgstr "" msgid "Failed" msgstr "" +#. module: cetmix_tower_server +#: code:addons/cetmix_tower_server/models/cetmix_tower.py:0 +#, python-format +msgid "Failed to connect after %(attempts)s attempts. Error: %(err)s" +msgstr "" + #. module: cetmix_tower_server #: code:addons/cetmix_tower_server/models/cx_tower_file.py:0 #: code:addons/cetmix_tower_server/models/cx_tower_file.py:0 @@ -1236,7 +1290,6 @@ msgid "Font awesome icon e.g. fa-tasks" msgstr "" #. module: cetmix_tower_server -#: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_interpreter__color #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_os__color #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_plan__color #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_server__color @@ -1283,6 +1336,11 @@ msgstr "" msgid "Group By" msgstr "" +#. module: cetmix_tower_server +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server_template_create_wizard__has_missing_required_values +msgid "Has Missing Required Values" +msgstr "" + #. module: cetmix_tower_server #: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_file_view_search msgid "Has Template" @@ -1306,7 +1364,6 @@ msgstr "" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_log__id #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file__id #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template__id -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__id #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key__id #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key_mixin__id #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os__id @@ -1325,6 +1382,7 @@ msgstr "" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_template_mixin__id #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable__id #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_mixin__id +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_option__id #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value__id msgid "ID" msgstr "" @@ -1405,14 +1463,8 @@ msgid "If exit code == 35 then Exit with command exit code" msgstr "" #. module: cetmix_tower_server -#: model:ir.actions.act_window,name:cetmix_tower_server.action_cx_tower_interpreter -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command__interpreter_id -msgid "Interpreter" -msgstr "" - -#. module: cetmix_tower_server -#: model:ir.ui.menu,name:cetmix_tower_server.menu_cx_tower_interpreter -msgid "Interpreters" +#: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_server_template_create_wizard_line__required +msgid "Indicates if this variable is mandatory for server creation" msgstr "" #. module: cetmix_tower_server @@ -1482,7 +1534,6 @@ msgstr "" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_log____last_update #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file____last_update #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template____last_update -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter____last_update #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key____last_update #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key_mixin____last_update #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os____last_update @@ -1501,6 +1552,7 @@ msgstr "" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_template_mixin____last_update #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable____last_update #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_mixin____last_update +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_option____last_update #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value____last_update msgid "Last Modified on" msgstr "" @@ -1516,7 +1568,6 @@ msgstr "" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_log__write_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file__write_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template__write_uid -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__write_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key__write_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os__write_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan__write_uid @@ -1531,6 +1582,7 @@ msgstr "" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server_template_create_wizard_line__write_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_tag__write_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable__write_uid +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_option__write_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value__write_uid msgid "Last Updated by" msgstr "" @@ -1541,7 +1593,6 @@ msgstr "" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_log__write_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file__write_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template__write_date -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__write_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key__write_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os__write_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan__write_date @@ -1556,6 +1607,7 @@ msgstr "" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server_template_create_wizard_line__write_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_tag__write_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable__write_date +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_option__write_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value__write_date msgid "Last Updated on" msgstr "" @@ -1582,7 +1634,6 @@ msgstr "" #. module: cetmix_tower_server #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan_line_action__line_id -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server_template_create_wizard__line_ids msgid "Line" msgstr "" @@ -1661,6 +1712,16 @@ msgstr "" msgid "Messages" msgstr "" +#. module: cetmix_tower_server +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server_template_create_wizard__missing_required_variables +msgid "Missing Required Variables" +msgstr "" + +#. module: cetmix_tower_server +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server_template_create_wizard__missing_required_variables_message +msgid "Missing Required Variables Message" +msgstr "" + #. module: cetmix_tower_server #: model:ir.model,name:cetmix_tower_server.model_cx_tower_key_mixin msgid "Mixin for managing secrets" @@ -1683,7 +1744,6 @@ msgstr "" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_log__name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file__name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template__name -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key__name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os__name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan__name @@ -1696,7 +1756,11 @@ msgstr "" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server_template__name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_tag__name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable__name +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_option__name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value__name +#: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_file_template_view_form +#: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_server_template_view_form +#: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_server_view_form msgid "Name" msgstr "" @@ -1751,6 +1815,12 @@ msgstr "" msgid "No runner found for command action '%(cmd_action)s'" msgstr "" +#. module: cetmix_tower_server +#: code:addons/cetmix_tower_server/models/cetmix_tower.py:0 +#, python-format +msgid "No server found for the provided reference." +msgstr "" + #. module: cetmix_tower_server #: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_command_execute_wizard_view_form msgid "No sudo" @@ -1861,6 +1931,31 @@ msgstr "" msgid "Operating System" msgstr "" +#. module: cetmix_tower_server +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server_template_create_wizard_line__option_id +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value__option_id +msgid "Option" +msgstr "" + +#. module: cetmix_tower_server +#: code:addons/cetmix_tower_server/models/cx_tower_variable_value.py:0 +#, python-format +msgid "Option '%(val)s' is not available for variable '%(var)s'" +msgstr "" + +#. module: cetmix_tower_server +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server_template_create_wizard_line__option_ids_domain +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value__option_ids_domain +msgid "Option Ids Domain" +msgstr "" + +#. module: cetmix_tower_server +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable__option_ids +#: model:ir.model.fields.selection,name:cetmix_tower_server.selection__cx_tower_variable__variable_type__o +#: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_variable_view_form +msgid "Options" +msgstr "" + #. module: cetmix_tower_server #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key__partner_id #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server__partner_id @@ -1877,7 +1972,6 @@ msgstr "" #. module: cetmix_tower_server #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_execute_wizard__path -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__path #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan_line__path msgid "Path" msgstr "" @@ -1939,6 +2033,20 @@ msgstr "" msgid "Please provide SSH password for %(srv)s" msgstr "" +#. module: cetmix_tower_server +#: code:addons/cetmix_tower_server/wizards/cx_tower_server_template_create_wizard.py:0 +#, python-format +msgid "" +"Please provide values for the following configuration variables: " +"%(variables)s" +msgstr "" + +#. module: cetmix_tower_server +#: code:addons/cetmix_tower_server/models/cx_tower_server_template.py:0 +#, python-format +msgid "Please resolve the following issues with configuration variables:" +msgstr "" + #. module: cetmix_tower_server #: code:addons/cetmix_tower_server/wizards/cx_tower_command_execute_wizard.py:0 #, python-format @@ -2019,8 +2127,8 @@ msgstr "" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server_template_create_wizard_line__variable_reference #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_tag__reference #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable__reference +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_option__reference #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value__reference -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value__variable_reference #: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_key_search_view msgid "Reference" msgstr "" @@ -2043,11 +2151,27 @@ msgstr "" #: model:ir.model.constraint,message:cetmix_tower_server.constraint_cx_tower_server_reference_unique #: model:ir.model.constraint,message:cetmix_tower_server.constraint_cx_tower_server_template_reference_unique #: model:ir.model.constraint,message:cetmix_tower_server.constraint_cx_tower_tag_reference_unique +#: model:ir.model.constraint,message:cetmix_tower_server.constraint_cx_tower_variable_option_reference_unique #: model:ir.model.constraint,message:cetmix_tower_server.constraint_cx_tower_variable_reference_unique #: model:ir.model.constraint,message:cetmix_tower_server.constraint_cx_tower_variable_value_reference_unique msgid "Reference must be unique" msgstr "" +#. module: cetmix_tower_server +#: code:addons/cetmix_tower_server/models/cx_tower_key.py:0 +#, python-format +msgid "Reference must be unique for the combination of partner and server" +msgstr "" + +#. module: cetmix_tower_server +#: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_file_template_view_form +#: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_server_template_view_form +#: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_server_view_form +msgid "" +"Reference. Can contain English letters, digits and '_'. Leave blank to " +"autogenerate" +msgstr "" + #. module: cetmix_tower_server #: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_file_view_form #: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_server_log_view_form @@ -2089,6 +2213,12 @@ msgstr "" msgid "Rendered Server Dir" msgstr "" +#. module: cetmix_tower_server +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server_template_create_wizard_line__required +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value__required +msgid "Required" +msgstr "" + #. module: cetmix_tower_server #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_log__command_response msgid "Response" @@ -2366,15 +2496,27 @@ msgstr "" #. module: cetmix_tower_server #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command__secret_ids #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file__secret_ids +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template__secret_ids #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key_mixin__secret_ids #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server__secret_ids #: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_server_view_form msgid "Secrets" msgstr "" +#. module: cetmix_tower_server +#: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_command_execute_wizard_view_form +msgid "Select tags to filter Commands" +msgstr "" + +#. module: cetmix_tower_server +#: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_plan_execute_wizard_view_form +msgid "Select tags to filter Flight Plans" +msgstr "" + #. module: cetmix_tower_server #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan_line__sequence #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan_line_action__sequence +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_option__sequence msgid "Sequence" msgstr "" @@ -2477,6 +2619,13 @@ msgstr "" msgid "Servers" msgstr "" +#. module: cetmix_tower_server +#: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_command__server_ids +msgid "" +"Servers on which the command will be executed.\n" +"If empty, command canbe executed on all servers" +msgstr "" + #. module: cetmix_tower_server #: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_plan_line_view_form msgid "Set Variable Values" @@ -2548,6 +2697,11 @@ msgid "" "Planned: Future activities." msgstr "" +#. module: cetmix_tower_server +#: model:ir.model.fields.selection,name:cetmix_tower_server.selection__cx_tower_variable__variable_type__s +msgid "String" +msgstr "" + #. module: cetmix_tower_server #: code:addons/cetmix_tower_server/models/cx_tower_file.py:0 #: code:addons/cetmix_tower_server/models/cx_tower_file.py:0 @@ -2609,11 +2763,6 @@ msgstr "" msgid "Template" msgstr "" -#. module: cetmix_tower_server -#: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_file_template_view_form -msgid "Template Name" -msgstr "" - #. module: cetmix_tower_server #: model:ir.actions.act_window,name:cetmix_tower_server.cx_tower_file_template_action #: model:ir.ui.menu,name:cetmix_tower_server.menu_cx_tower_file_template @@ -2641,6 +2790,11 @@ msgid "" "Please ensure that you want to allow those commands to be run anyway." msgstr "" +#. module: cetmix_tower_server +#: model:ir.model.constraint,message:cetmix_tower_server.constraint_cx_tower_variable_option_unique_variable_option +msgid "The combination of Name,Value and Variable must be unique." +msgstr "" + #. module: cetmix_tower_server #: code:addons/cetmix_tower_server/models/cx_tower_server.py:0 #, python-format @@ -2677,6 +2831,7 @@ msgstr "" #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_command__code #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_command_execute_wizard__code #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_file__code +#: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_file_template__code #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_plan_line__command_code #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_template_mixin__code msgid "This field will be rendered by default" @@ -2743,6 +2898,13 @@ msgstr "" msgid "Triggered Plan Log" msgstr "" +#. module: cetmix_tower_server +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server_template_create_wizard_line__variable_type +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable__variable_type +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value__variable_type +msgid "Type" +msgstr "" + #. module: cetmix_tower_server #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_file__activity_exception_decoration #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_server__activity_exception_decoration @@ -2826,6 +2988,7 @@ msgstr "" #. module: cetmix_tower_server #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server_template_create_wizard_line__value_char +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_option__value_char #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value__value_char #: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_key_view_form #: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_variable_value_search_view @@ -2845,6 +3008,7 @@ msgstr "" #. module: cetmix_tower_server #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server_template_create_wizard_line__variable_id +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_option__variable_id #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value__variable_id #: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_variable_value_search_view msgid "Variable" @@ -2859,7 +3023,7 @@ msgid "" msgstr "" #. module: cetmix_tower_server -#: model_terms:ir.ui.view,arch_db:cetmix_tower_server.cx_tower_plan_line_view_form +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value__variable_reference msgid "Variable Reference" msgstr "" @@ -2913,9 +3077,11 @@ msgstr "" #. module: cetmix_tower_server #: model:ir.actions.act_window,name:cetmix_tower_server.action_cx_tower_variable #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command__variable_ids +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_execute_wizard__variable_ids #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file__variable_ids #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template__variable_ids #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan_line__variable_ids +#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_template_mixin__variable_ids #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_variable_value__variable_ids #: model:ir.ui.menu,name:cetmix_tower_server.menu_cx_tower_variable msgid "Variables" diff --git a/cetmix_tower_server/i18n/it.po b/cetmix_tower_server/i18n/it.po index b4a45011..cc7822ca 100644 --- a/cetmix_tower_server/i18n/it.po +++ b/cetmix_tower_server/i18n/it.po @@ -597,11 +597,6 @@ msgstr "Azione riga piano di volo Cetmix Tower" msgid "Cetmix Tower Flight Plan Log" msgstr "Registro piano di volo Cetmix Tower" -#. module: cetmix_tower_server -#: model:ir.model,name:cetmix_tower_server.model_cx_tower_interpreter -msgid "Cetmix Tower Interpreter" -msgstr "Interprete Cetmix Towe" - #. module: cetmix_tower_server #: model:ir.model,name:cetmix_tower_server.model_cx_tower_os msgid "Cetmix Tower Operating System" @@ -687,7 +682,6 @@ msgid "Code On Server" msgstr "Codice sul server" #. module: cetmix_tower_server -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__color #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os__color #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan__color #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server__color @@ -821,7 +815,6 @@ msgstr "Crea nuovo server da variabili modello" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_log__create_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file__create_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template__create_uid -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__create_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key__create_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os__create_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan__create_uid @@ -846,7 +839,6 @@ msgstr "Creato da" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_log__create_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file__create_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template__create_date -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__create_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key__create_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os__create_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan__create_date @@ -927,7 +919,6 @@ msgstr "Cartella nel server" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_log__display_name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file__display_name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template__display_name -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__display_name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key__display_name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os__display_name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan__display_name @@ -1319,7 +1310,6 @@ msgid "Font awesome icon e.g. fa-tasks" msgstr "Font awesome icon es. fa-tasks" #. module: cetmix_tower_server -#: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_interpreter__color #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_os__color #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_plan__color #: model:ir.model.fields,help:cetmix_tower_server.field_cx_tower_server__color @@ -1389,7 +1379,6 @@ msgstr "Aiuto con le espressioni Python" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_log__id #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file__id #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template__id -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__id #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key__id #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os__id #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan__id @@ -1495,17 +1484,6 @@ msgid "If exit code == 35 then Exit with command exit code" msgstr "" "Se il codice di uscita == 35 allora esci con il comando codice di uscita" -#. module: cetmix_tower_server -#: model:ir.actions.act_window,name:cetmix_tower_server.action_cx_tower_interpreter -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command__interpreter_id -msgid "Interpreter" -msgstr "Interprete" - -#. module: cetmix_tower_server -#: model:ir.ui.menu,name:cetmix_tower_server.menu_cx_tower_interpreter -msgid "Interpreters" -msgstr "Interpreti" - #. module: cetmix_tower_server #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file__message_is_follower #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_server__message_is_follower @@ -1573,7 +1551,6 @@ msgstr "Etichettato" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_log____last_update #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file____last_update #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template____last_update -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter____last_update #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key____last_update #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os____last_update #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan____last_update @@ -1606,7 +1583,6 @@ msgstr "Ultima data sincronia" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_log__write_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file__write_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template__write_uid -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__write_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key__write_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os__write_uid #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan__write_uid @@ -1631,7 +1607,6 @@ msgstr "Ultimo aggiornamento di" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_log__write_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file__write_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template__write_date -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__write_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key__write_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os__write_date #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan__write_date @@ -1772,7 +1747,6 @@ msgstr "Scadenza mia attività" #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_log__name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file__name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_file_template__name -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_key__name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_os__name #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan__name @@ -1968,7 +1942,6 @@ msgstr "Password" #. module: cetmix_tower_server #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_command_execute_wizard__path -#: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_interpreter__path #: model:ir.model.fields,field_description:cetmix_tower_server.field_cx_tower_plan_line__path msgid "Path" msgstr "Percorso" diff --git a/cetmix_tower_server/models/__init__.py b/cetmix_tower_server/models/__init__.py index f3c632f5..460e4d7f 100644 --- a/cetmix_tower_server/models/__init__.py +++ b/cetmix_tower_server/models/__init__.py @@ -13,7 +13,6 @@ from . import cx_tower_os from . import cx_tower_tag from . import cx_tower_command -from . import cx_tower_interpreter from . import cx_tower_key from . import cx_tower_command_log from . import cx_tower_plan diff --git a/cetmix_tower_server/models/cetmix_tower.py b/cetmix_tower_server/models/cetmix_tower.py index 20722aa6..8aac248b 100644 --- a/cetmix_tower_server/models/cetmix_tower.py +++ b/cetmix_tower_server/models/cetmix_tower.py @@ -1,6 +1,10 @@ # Copyright (C) 2024 Cetmix OÜ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import _, api, models +from odoo.exceptions import ValidationError + +from .constants import SSH_CONNECTION_ERROR, SSH_CONNECTION_TIMEOUT +from .cx_tower_server import SSH class CetmixTower(models.AbstractModel): @@ -99,3 +103,86 @@ def server_get_variable_value( if not value and check_global: value = result.get("global") return value + + @api.model + def server_check_ssh_connection(self, server_reference, attempts=5, timeout=15): + """Check if SSH connection to the server is available. + + Args: + server_reference (Char): Server reference. + attempts (int): Number of attempts to try the connection. + Default is 5. + timeout (int): Timeout in seconds for each connection attempt. + Default is 15 seconds. + Raises: + ValidationError: + If the provided server reference is invalid or + the server cannot be found. + Returns: + dict: { + "code": int, + # 0 for success, + # 408 if the SSH connection timed out after all attempts, + # 503 if there was a generic SSH connection error. + "message": str # Description of the result + } + """ + server = self.env["cx.tower.server"].get_by_reference(server_reference) + if not server: + raise ValidationError(_("No server found for the provided reference.")) + + # Prepare SSH connection parameters + ssh_params = { + "host": server.ip_v4_address or server.ip_v6_address, + "username": server.ssh_username, + "port": int(server.ssh_port), + "timeout": timeout, + "mode": server.ssh_auth_mode, + } + + if server.ssh_auth_mode == "p": + ssh_params["password"] = server.ssh_password + elif server.ssh_auth_mode == "k": + ssh_params["ssh_key"] = server.ssh_key_id.sudo().secret_value + + # Initialize SSH connection instance + ssh_connection = SSH(**ssh_params) + + # Try connecting multiple times + for attempt in range(1, attempts + 1): + try: + ssh_connection.connection() + return { + "code": 0, + "message": _("Connection successful."), + } + except TimeoutError as e: + if attempt == attempts: + return { + "code": SSH_CONNECTION_TIMEOUT, + "message": _( + "Connection timed out after %(attempts)s attempts. " + "Error: %(err)s", + attempts=attempts, + err=str(e), + ), + } + except Exception as e: + if attempt == attempts: + return { + "code": SSH_CONNECTION_ERROR, + "message": _( + "Failed to connect after %(attempts)s attempts. " + "Error: %(err)s", + attempts=attempts, + err=str(e), + ), + } + finally: + ssh_connection.disconnect() + + # If all attempts fail + return { + "code": SSH_CONNECTION_ERROR, + "message": _("All connection connection attempts have failed."), + } diff --git a/cetmix_tower_server/models/constants.py b/cetmix_tower_server/models/constants.py index b3cb6700..944d21f9 100644 --- a/cetmix_tower_server/models/constants.py +++ b/cetmix_tower_server/models/constants.py @@ -32,3 +32,9 @@ # Returned when the command failed to execute due to a python code execution error PYTHON_COMMAND_ERROR = -24 + +# Returned when an SSH connection error occurs +SSH_CONNECTION_ERROR = 503 + +# Returned when the connection times out +SSH_CONNECTION_TIMEOUT = 408 diff --git a/cetmix_tower_server/models/cx_tower_access_mixin.py b/cetmix_tower_server/models/cx_tower_access_mixin.py index c14418d3..925baf3d 100644 --- a/cetmix_tower_server/models/cx_tower_access_mixin.py +++ b/cetmix_tower_server/models/cx_tower_access_mixin.py @@ -16,7 +16,6 @@ class CxTowerAccessMixin(models.AbstractModel): lambda self: self._selection_access_level(), string="Access Level", default=lambda self: self._default_access_level(), - groups="cetmix_tower_server.group_root,cetmix_tower_server.group_manager", required=True, ) @@ -39,3 +38,4 @@ def _default_access_level(self): Char: `access_level` field selection value """ return "2" + \ No newline at end of file diff --git a/cetmix_tower_server/models/cx_tower_command.py b/cetmix_tower_server/models/cx_tower_command.py index e5b6d928..b4b62cd4 100644 --- a/cetmix_tower_server/models/cx_tower_command.py +++ b/cetmix_tower_server/models/cx_tower_command.py @@ -9,7 +9,30 @@ requests = wrap_module(__import__("requests"), ["post", "get", "request"]) json = wrap_module(__import__("json"), ["dumps"]) - +hashlib = wrap_module( + __import__("hashlib"), + [ + "sha1", + "sha224", + "sha256", + "sha384", + "sha512", + "sha3_224", + "sha3_256", + "sha3_384", + "sha3_512", + "shake_128", + "shake_256", + "blake2b", + "blake2s", + "md5", + "new", + ], +) +hmac = wrap_module( + __import__("hmac"), + ["new", "compare_digest"], +) DEFAULT_PYTHON_CODE = """# Available variables: # - user: Current Odoo User @@ -19,6 +42,12 @@ # - time, datetime, dateutil, timezone: useful Python libraries # - requests: Python 'requests' library. Available methods: 'post', 'get', 'request' # - json: Python 'json' library. Available methods: 'dumps' +# - hashlib: Python 'hashlib' library. Available methods: 'sha1', 'sha224', 'sha256', +# 'sha384', 'sha512', 'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512', 'shake_128', +# 'shake_256', 'blake2b', 'blake2s', 'md5', 'new' +# - hmac: Python 'hmac' library. Use 'new' to create HMAC objects. +# Available methods on the HMAC *object*: 'update', 'copy', 'digest', 'hexdigest'. +# Module-level function: 'compare_digest'. # - float_compare: Odoo function to compare floats based on specific precisions # - UserError: Warning Exception to use with raise # @@ -67,9 +96,6 @@ def _selection_action(self): "while the same command is still running.\n" "Returns ANOTHER_COMMAND_RUNNING if execution is blocked" ) - interpreter_id = fields.Many2one( - comodel_name="cx.tower.interpreter", - ) server_ids = fields.Many2many( comodel_name="cx.tower.server", relation="cx_tower_server_command_rel", @@ -117,33 +143,36 @@ def _selection_action(self): flight_plan_id = fields.Many2one( comodel_name="cx.tower.plan", ) + server_status = fields.Selection( + selection=lambda self: self.env["cx.tower.server"]._selection_status(), + string="Server Status", + help="Set the following status if command is executed successfully. " + "Leave 'Undefined' if you don't need to update the status", + ) variable_ids = fields.Many2many( comodel_name="cx.tower.variable", relation="cx_tower_command_variable_rel", column1="command_id", column2="variable_id", - string="Variables", - compute="_compute_variable_ids", - store=True, ) - @api.depends("code", "path") - def _compute_variable_ids(self): - """ - Compute variable_ids based on code and path fields. + @classmethod + def _get_depends_fields(cls): """ - for record in self: - record.variable_ids = record._prepare_variable_commands(["code", "path"]) + Define dependent fields for computing `variable_ids` in command-related models. - # TODO: move this up - server_status = fields.Selection( - selection=lambda self: self.env["cx.tower.server"]._selection_status(), - string="Server Status", - help=( - "Set the following status if command is executed successfully." - " Leave 'Undefined' if you don't need to update the status" - ), - ) + This implementation specifies that the fields `code` and `path` + are used to determine the variables associated with a command. + + Returns: + list: A list of field names (str) representing the dependencies. + + Example: + The following fields trigger recomputation of `variable_ids`: + - `code`: The command's script or execution logic. + - `path`: The default execution path for the command. + """ + return ["code", "path"] # Depend on related servers and partners @api.depends( @@ -188,6 +217,8 @@ def _get_eval_context(self, server=None): "UserError": UserError, "server": server or self._context.get("active_server"), "tower": self.env["cetmix.tower"], + "hashlib": hashlib, + "hmac": hmac, } def name_get(self): diff --git a/cetmix_tower_server/models/cx_tower_file.py b/cetmix_tower_server/models/cx_tower_file.py index bcc3b90b..c945a1b4 100644 --- a/cetmix_tower_server/models/cx_tower_file.py +++ b/cetmix_tower_server/models/cx_tower_file.py @@ -135,20 +135,26 @@ class CxTowerFile(models.Model): relation="cx_tower_file_variable_rel", column1="file_id", column2="variable_id", - string="Variables", - compute="_compute_variable_ids", - store=True, ) - @api.depends("code", "server_dir", "name") - def _compute_variable_ids(self): + @classmethod + def _get_depends_fields(cls): """ - Compute variable_ids based on code, server_dir, and name fields. + Define dependent fields for computing `variable_ids` in file-related models. + + This implementation specifies that the fields `code`, `server_dir`, + and `name` are used to compute the variables associated with a file. + + Returns: + list: A list of field names (str) representing the dependencies. + + Example: + The following fields trigger recomputation of `variable_ids`: + - `code`: The content of the file. + - `server_dir`: The directory on the server where the file is located. + - `name`: The name of the file. """ - for record in self: - record.variable_ids = record._prepare_variable_commands( - ["code", "server_dir", "name"] - ) + return ["code", "server_dir", "name"] def _selection_file_type(self): """Available file types diff --git a/cetmix_tower_server/models/cx_tower_file_template.py b/cetmix_tower_server/models/cx_tower_file_template.py index 96a99b92..df49437e 100644 --- a/cetmix_tower_server/models/cx_tower_file_template.py +++ b/cetmix_tower_server/models/cx_tower_file_template.py @@ -1,7 +1,7 @@ # Copyright (C) 2024 Cetmix OÜ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import _, api, fields, models +from odoo import _, fields, models from odoo.exceptions import ValidationError from .cx_tower_file import TEMPLATE_FILE_FIELD_MAPPING @@ -9,7 +9,11 @@ class CxTowerFileTemplate(models.Model): _name = "cx.tower.file.template" - _inherit = ["cx.tower.reference.mixin", "cx.tower.key.mixin"] + _inherit = [ + "cx.tower.reference.mixin", + "cx.tower.key.mixin", + "cx.tower.template.mixin", + ] _description = "Cx Tower File Template" def _compute_file_count(self): @@ -53,27 +57,35 @@ def _compute_file_count(self): required=True, default="tower", ) - variable_ids = fields.Many2many( comodel_name="cx.tower.variable", relation="cx_tower_file_template_variable_rel", column1="file_template_id", column2="variable_id", - string="Variables", - compute="_compute_variable_ids", - store=True, ) - @api.depends("code", "server_dir", "file_name") - def _compute_variable_ids(self): + @classmethod + def _get_depends_fields(cls): """ - Compute variable_ids based on code, server_dir, and file_name fields. + Define dependent fields for computing + `variable_ids` in file template-related models. + + This implementation specifies that the fields `code`, `server_dir`, + and `file_name` are used to compute the + variables associated with a file template. + + Returns: + list: A list of field names (str) representing the dependencies. + + Example: + The following fields trigger recomputation + of `variable_ids`: + - `code`: The template content for the file. + - `server_dir`: The target directory on the + server where the template is applied. + - `file_name`: The name of the generated file. """ - template_mixin_obj = self.env["cx.tower.template.mixin"] - for record in self: - record.variable_ids = template_mixin_obj._prepare_variable_commands( - ["code", "server_dir", "file_name"], force_record=record - ) + return ["code", "server_dir", "file_name"] def write(self, vals): """ diff --git a/cetmix_tower_server/models/cx_tower_interpreter.py b/cetmix_tower_server/models/cx_tower_interpreter.py deleted file mode 100644 index 828c5e69..00000000 --- a/cetmix_tower_server/models/cx_tower_interpreter.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (C) 2022 Cetmix OÜ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import fields, models - - -class CxTowerInterpreter(models.Model): - _name = "cx.tower.interpreter" - _description = "Cetmix Tower Interpreter" - - name = fields.Char() - color = fields.Integer(help="For better visualization in views") - path = fields.Char() diff --git a/cetmix_tower_server/models/cx_tower_key.py b/cetmix_tower_server/models/cx_tower_key.py index 9898e6c9..0435fb44 100644 --- a/cetmix_tower_server/models/cx_tower_key.py +++ b/cetmix_tower_server/models/cx_tower_key.py @@ -309,6 +309,11 @@ def _parse_code_and_return_key_values(self, code, pythonic_mode=False, **kwargs) if pythonic_mode: # save key value as string in pythonic mode key_value = f'"{key_value}"' + # Escape newline characters to ensure the key value remains + # a valid single-line string. This prevents syntax errors + # when the string is used in contexts where unescaped + # newlines would break Python syntax or evaluation logic. + key_value = key_value.replace("\n", "\\n") code = code.replace(key_string, key_value) @@ -515,6 +520,8 @@ def _replace_with_spoiler(self, code, key_values): for key_value in key_values: # If key_value includes quotes, remove them for the replacement key_value = key_value.strip('"') + # If key_value contains an escaped line break replace then remove escaping + key_value = key_value.replace("\\n", "\n") # Replace key including key terminator code = code.replace(key_value, self.SECRET_VALUE_SPOILER) diff --git a/cetmix_tower_server/models/cx_tower_plan.py b/cetmix_tower_server/models/cx_tower_plan.py index 0efff2bb..b533f016 100644 --- a/cetmix_tower_server/models/cx_tower_plan.py +++ b/cetmix_tower_server/models/cx_tower_plan.py @@ -22,6 +22,7 @@ class CxTowerPlan(models.Model): "cx.tower.reference.mixin", "cx.tower.access.mixin", ] + _order = "name asc" active = fields.Boolean(default=True) allow_parallel_run = fields.Boolean( diff --git a/cetmix_tower_server/models/cx_tower_server_template.py b/cetmix_tower_server/models/cx_tower_server_template.py index 7b1fc6bd..54487437 100644 --- a/cetmix_tower_server/models/cx_tower_server_template.py +++ b/cetmix_tower_server/models/cx_tower_server_template.py @@ -114,6 +114,7 @@ def action_create_server(self): { "variable_id": line.variable_id.id, "value_char": line.value_char, + "option_id": line.option_id.id, "required": line.required, }, ) @@ -300,6 +301,7 @@ def _prepare_server_values(self, **kwargs): # custom specific variable values configuration_variables = kwargs.pop("configuration_variables", None) + line_ids_variables = kwargs.pop("line_ids_variables", None) if configuration_variables: # Validate required variables self._validate_required_variables(configuration_variables) @@ -320,14 +322,30 @@ def _prepare_server_values(self, **kwargs): "name": variable_reference, } ) + variable_option_id = variable_id = False + + if not variable_value and line_ids_variables: + val_found = next( + ( + v + for v in line_ids_variables.values() + if v.get("variable_reference") == variable_reference + ), + None, + ) + if val_found: + variable_value = val_found.get("value_char") + variable_option_id = val_found.get("option_id", False) + variable_id = val_found.get("variable_id", False) variable_vals_list.append( ( 0, 0, { - "variable_id": variable.id, - "value_char": variable_value, + "variable_id": variable.id or variable_id, + "value_char": variable_value or "", + "option_id": variable_option_id, }, ) ) diff --git a/cetmix_tower_server/models/cx_tower_template_mixin.py b/cetmix_tower_server/models/cx_tower_template_mixin.py index 64d9fc08..0cb1e9ca 100644 --- a/cetmix_tower_server/models/cx_tower_template_mixin.py +++ b/cetmix_tower_server/models/cx_tower_template_mixin.py @@ -3,7 +3,7 @@ from jinja2 import Environment, Template, meta from jinja2 import exceptions as jn_exceptions -from odoo import fields, models +from odoo import api, fields, models from odoo.exceptions import UserError @@ -16,6 +16,67 @@ class CxTowerTemplateMixin(models.AbstractModel): _description = "Cetmix Tower template rendering mixin" code = fields.Text(string="Code", help="This field will be rendered by default") + variable_ids = fields.Many2many( + string="Variables", + comodel_name="cx.tower.variable", + compute="_compute_variable_ids", + store=True, + ) + + @classmethod + def _get_depends_fields(cls): + """ + Define dependent fields for the `variable_ids` computation. + + This method should be overridden in inheriting models to provide + a list of fields that influence the computation of `variable_ids`. + These fields are used in the `@api.depends` decorator to trigger + recomputation when their values change. + + Returns: + list: A list of field names (str) that are dependencies for + the `variable_ids` computation. Default is an empty list. + + Example: + In a subclass, override as follows: + >>> @classmethod + >>> def _get_depends_fields(cls): + >>> return ["code", "path"] + """ + return [] + + @api.depends(lambda self: self._get_depends_fields()) + def _compute_variable_ids(self): + """ + Compute the values of the `variable_ids` + field based on model-specific dependencies. + + This method retrieves the dependent fields using `_get_depends_fields` + and dynamically calculates the values of `variable_ids` using the + `_prepare_variable_commands` method. + + If no dependent fields or relation parameters are defined, the field + is reset to an empty list. + + Example: + If dependent fields include `code` and `path`, and the model-specific + logic links them to variables, this method will update the `variable_ids` + field accordingly. + + Raises: + ValidationError: If the field metadata is incorrectly defined or + missing required attributes. + + Returns: + None: The field `variable_ids` is updated in-place for each record. + """ + depends_fields = self._get_depends_fields() + + for record in self: + if depends_fields: + record.variable_ids = record._prepare_variable_commands(depends_fields) + else: + record.variable_ids = [(5, 0, 0)] def get_variables(self): """Get the list of variables for templates diff --git a/cetmix_tower_server/models/cx_tower_variable_option.py b/cetmix_tower_server/models/cx_tower_variable_option.py index 534e035f..1961480e 100644 --- a/cetmix_tower_server/models/cx_tower_variable_option.py +++ b/cetmix_tower_server/models/cx_tower_variable_option.py @@ -1,7 +1,6 @@ # Copyright (C) 2022 Cetmix OÜ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - from odoo import fields, models @@ -27,9 +26,11 @@ class TowerVariableOption(models.Model): _name = "cx.tower.variable.option" _description = "Cetmix Tower Variable Options" + _inherit = "cx.tower.reference.mixin" _order = "sequence, name" - name = fields.Char(string="Option Value", required=True) + name = fields.Char(string="Name", required=True) + value_char = fields.Char(string="Value", required=True) variable_id = fields.Many2one( comodel_name="cx.tower.variable", required=True, @@ -42,7 +43,15 @@ class TowerVariableOption(models.Model): _sql_constraints = [ ( "unique_variable_option", - "unique (name, variable_id)", - "The combination of Name and Variable must be unique.", + "unique (name, value_char, variable_id)", + "The combination of Name,Value and Variable must be unique.", ) ] + + def _get_pre_populated_model_data(self): + """ + Define the model relationships for reference generation. + """ + res = super()._get_pre_populated_model_data() + res.update({"cx.tower.variable.option": ["cx.tower.variable", "variable_id"]}) + return res diff --git a/cetmix_tower_server/models/cx_tower_variable_value.py b/cetmix_tower_server/models/cx_tower_variable_value.py index 738519c7..0d35d726 100644 --- a/cetmix_tower_server/models/cx_tower_variable_value.py +++ b/cetmix_tower_server/models/cx_tower_variable_value.py @@ -25,7 +25,10 @@ class TowerVariableValue(models.Model): ) name = fields.Char(related="variable_id.name", readonly=True) variable_reference = fields.Char( - related="variable_id.reference", store=True, index=True + string="Variable Reference", + related="variable_id.reference", + store=True, + index=True, ) is_global = fields.Boolean( string="Global", @@ -36,7 +39,6 @@ class TowerVariableValue(models.Model): note = fields.Text(related="variable_id.note", readonly=True) active = fields.Boolean(default=True) variable_type = fields.Selection( - selection=[("s", "String"), ("o", "Options")], related="variable_id.variable_type", readonly=True, ) @@ -45,7 +47,11 @@ class TowerVariableValue(models.Model): ) option_ids_domain = fields.Binary(compute="_compute_option_ids_domain") value_char = fields.Char( - string="Value", compute="_compute_value_char", store=True, readonly=False + string="Value", + compute="_compute_value_char", + inverse="_inverse_value_char", + store=True, + readonly=False, ) # Direct model relations. @@ -121,7 +127,7 @@ def _compute_value_char(self): """ for rec in self: if rec.variable_id.option_ids and rec.option_id: - rec.value_char = rec.option_id.name + rec.value_char = rec.option_id.value_char elif not rec.variable_id.option_ids: rec.value_char = rec.value_char or "" rec.option_id = None @@ -213,6 +219,26 @@ def _check_access_level_consistency(self): ) ) + def _inverse_value_char(self): + """Set option_id based on value_char""" + for rec in self: + if rec.variable_type == "o" and ( + not rec.option_id or rec.option_id.value_char != rec.value_char + ): + option = rec.variable_id.option_ids.filtered( + lambda x, v=rec.value_char: x.value_char == v + ) + if option: + rec.option_id = option.id + else: + raise ValidationError( + _( + "Option '%(val)s' is not available for variable '%(var)s'", + val=rec.value_char, + var=rec.variable_id.name, + ) + ) + def _used_in_models(self): """Returns information about models which use this mixin. diff --git a/cetmix_tower_server/security/cx_tower_command_security.xml b/cetmix_tower_server/security/cx_tower_command_security.xml index 5f78b87b..2807609e 100644 --- a/cetmix_tower_server/security/cx_tower_command_security.xml +++ b/cetmix_tower_server/security/cx_tower_command_security.xml @@ -1,7 +1,6 @@ - Tower command: user access rule @@ -16,19 +15,13 @@ ('access_level', '=', '1'), ('server_ids.message_partner_ids', 'in', [user.partner_id.id]) ] - - - - - Tower command: manager access rule - [ '|', '&', @@ -38,18 +31,10 @@ ('access_level', '<=', '2'), ('server_ids.message_partner_ids', 'in', [user.partner_id.id]) ] - - - - - - - - Tower command: root access rule diff --git a/cetmix_tower_server/security/cx_tower_plan_line_action_security.xml b/cetmix_tower_server/security/cx_tower_plan_line_action_security.xml index 74068caf..d51f293e 100644 --- a/cetmix_tower_server/security/cx_tower_plan_line_action_security.xml +++ b/cetmix_tower_server/security/cx_tower_plan_line_action_security.xml @@ -1,25 +1,55 @@ - Tower plan line action: user access rule - [('access_level', '=', '1')] - - + + [ + ('access_level', '=', '1'), + '|', + ('line_id.plan_id.server_ids', '=', False), + ('line_id.plan_id.server_ids.message_partner_ids', 'in', [user.partner_id.id]) + ] + + - Tower plan line action: manager access rule + Tower plan line action: manager Read/Write access rule - [('access_level', '<=', '2')] + + [ + ('access_level', '<=', '2'), + '|', + ('line_id.plan_id.server_ids', '=', False), + ('line_id.plan_id.server_ids.message_partner_ids', 'in', [user.partner_id.id]) + ] + - - + + + Tower plan line action: manager delete own records + + + [ + ('create_uid', '=', user.id), + ('access_level', '<=', '2'), + '|', + ('line_id.plan_id.server_ids', '=', False), + ('line_id.plan_id.server_ids.message_partner_ids', 'in', [user.partner_id.id]) + ] + + + + + + Tower plan line action: root access rule diff --git a/cetmix_tower_server/security/cx_tower_plan_line_security.xml b/cetmix_tower_server/security/cx_tower_plan_line_security.xml index 0179fdf4..2bc8026a 100644 --- a/cetmix_tower_server/security/cx_tower_plan_line_security.xml +++ b/cetmix_tower_server/security/cx_tower_plan_line_security.xml @@ -1,25 +1,53 @@ - Tower plan line: user access rule - [('access_level', '=', '1')] - - + + [ + ('access_level', '=', '1'), + '|', + ('plan_id.server_ids', '=', False), + ('plan_id.server_ids.message_partner_ids', 'in', [user.partner_id.id]) + ] + + - Tower plan line: manager access rule + Tower plan line: manager Read/Write access rule - [('access_level', '<=', '2')] + + [ + ('access_level', '<=', '2'), + '|', + ('plan_id.server_ids', '=', False), + ('plan_id.server_ids.message_partner_ids', 'in', [user.partner_id.id]) + ] + - - + + + Tower plan line: manager delete own records + + + [ + ('create_uid', '=', user.id), + ('access_level', '<=', '2'), + '|', + ('plan_id.server_ids', '=', False), + ('plan_id.server_ids.message_partner_ids', 'in', [user.partner_id.id]) + ] + + + + + + Tower plan line: root access rule @@ -28,5 +56,4 @@ - diff --git a/cetmix_tower_server/security/cx_tower_variable_value_security.xml b/cetmix_tower_server/security/cx_tower_variable_value_security.xml index 161b21fb..cc83447e 100644 --- a/cetmix_tower_server/security/cx_tower_variable_value_security.xml +++ b/cetmix_tower_server/security/cx_tower_variable_value_security.xml @@ -1,36 +1,137 @@ - - - Tower Variable Value: User Access Rule - - - [ + + + Tower Variable Value: User Access Rule + + + [ ('access_level', '=', '1'), ('server_id.message_partner_ids', 'in', [user.partner_id.id]) - ] - - - - - - - Tower Variable Value: Manager Access Rule - - - ['|', - ('is_global', '=', True), - '&', - ('access_level', '<=', '2'), - ('server_id.message_partner_ids', 'in', [user.partner_id.id]) - ] - - - + ] + + + + + + + Tower Variable Value: Manager Access Rule + + + [ + '|', + ('is_global', '=', True), + '&', + ('access_level', '<=', '2'), + ('server_id.message_partner_ids', 'in', [user.partner_id.id]) + ] + + + + + + Tower variable Value: User Access to Variable Values in Plan Line Action + Rule + + + [ + ('plan_line_action_id.access_level', '=', '1'), + '|', + ('plan_line_action_id.line_id.plan_id.server_ids', '=', False), + ('plan_line_action_id.line_id.plan_id.server_ids.message_partner_ids', 'in', + [user.partner_id.id]) + ] + + + + + + + Tower Variable Value: Manager Access to Variable Values in Plan Line + Action Rule + + + [ + ('plan_line_action_id.access_level', '<=', '2'), + '|', + ('plan_line_action_id.line_id.plan_id.server_ids', '=', False), + ('plan_line_action_id.line_id.plan_id.server_ids.message_partner_ids', 'in', + [user.partner_id.id]) + ] + + + + + + + Tower Variable Value: Manager Delete own Variable Values in Plan Line + Action + + + [ + ('create_uid', '=', user.id), + ('plan_line_action_id.access_level', '<=', '2'), + '|', + ('plan_line_action_id.line_id.plan_id.server_ids', '=', False), + ('plan_line_action_id.line_id.plan_id.server_ids.message_partner_ids', 'in', + [user.partner_id.id]) + ] + + + + + + + + + Tower Variable Value: Manager Access to Variable Values in Server + Template Rule + + [ + ('server_template_id.message_partner_ids', 'in', [user.partner_id.id]), + ] + + + + + + Tower Variable Value: Manager Delete own Variable Values in Server + Template Rule + + + [ + ('server_template_id.message_partner_ids', 'in', [user.partner_id.id]), + ('create_uid', '=', user.id) + ] + + + + + + diff --git a/cetmix_tower_server/security/ir.model.access.csv b/cetmix_tower_server/security/ir.model.access.csv index 9ff67441..01f78da9 100644 --- a/cetmix_tower_server/security/ir.model.access.csv +++ b/cetmix_tower_server/security/ir.model.access.csv @@ -13,9 +13,6 @@ access_tag_root,Tag->Root,model_cx_tower_tag,group_root,1,1,1,1 access_server_user,Server->User,model_cx_tower_server,group_user,1,0,0,0 access_server_manager,Server->Manager,model_cx_tower_server,group_manager,1,1,1,0 access_server_root,Server->Root,model_cx_tower_server,group_root,1,1,1,1 -access_interpreter_user,Interpreter->User,model_cx_tower_interpreter,group_user,1,0,0,0 -access_interpreter_manager,Interpreter->Manager,model_cx_tower_interpreter,group_manager,1,1,1,0 -access_interpreter_root,Interpreter->Root,model_cx_tower_interpreter,group_root,1,1,1,1 access_command_user,Command->User,model_cx_tower_command,group_user,1,0,0,0 access_command_manager,Command->Manager,model_cx_tower_command,group_manager,1,1,1,0 access_command_root,Command->Root,model_cx_tower_command,group_root,1,1,1,1 @@ -30,10 +27,10 @@ access_plan_user,Plan->User,model_cx_tower_plan,group_user,1,0,0,0 access_plan_manager,Plan->Manager,model_cx_tower_plan,group_manager,1,1,1,0 access_plan_root,Plan->Root,model_cx_tower_plan,group_root,1,1,1,1 access_plan_line_user,Plan Line->User,model_cx_tower_plan_line,group_user,1,0,0,0 -access_plan_line_manager,Plan Line->Manager,model_cx_tower_plan_line,group_manager,1,1,1,0 +access_plan_line_manager,Plan Line->Manager,model_cx_tower_plan_line,group_manager,1,1,1,1 access_plan_line_root,Plan Line->Root,model_cx_tower_plan_line,group_root,1,1,1,1 access_plan_line_action_user,Plan Line Action->User,model_cx_tower_plan_line_action,group_user,1,0,0,0 -access_plan_line_action_manager,Plan Line Action->Manager,model_cx_tower_plan_line_action,group_manager,1,1,1,0 +access_plan_line_action_manager,Plan Line Action->Manager,model_cx_tower_plan_line_action,group_manager,1,1,1,1 access_plan_line_action_root,Plan Line Action->Root,model_cx_tower_plan_line_action,group_root,1,1,1,1 access_plan_log_user,Plan Log->User,model_cx_tower_plan_log,group_user,1,0,0,0 access_plan_log_root,Plan Log->User,model_cx_tower_plan_log,group_root,1,1,1,1 diff --git a/cetmix_tower_server/static/description/index.html b/cetmix_tower_server/static/description/index.html index 6145893a..c36d7327 100644 --- a/cetmix_tower_server/static/description/index.html +++ b/cetmix_tower_server/static/description/index.html @@ -367,7 +367,7 @@

Cetmix Tower Server Management

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:46e220fd464cf2a9911e7720baa63defb7aefd08bb9c32e684b63cc00b9ddd0e +!! source digest: sha256:b7a9d72e69a49390595260c339932330ab5ecfb46e56b3513c54f5dd94316a34 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 cetmix/cetmix-tower

Cetmix Tower offers a streamlined solution diff --git a/cetmix_tower_server/tests/common.py b/cetmix_tower_server/tests/common.py index abe46bcf..7415e1d5 100644 --- a/cetmix_tower_server/tests/common.py +++ b/cetmix_tower_server/tests/common.py @@ -65,6 +65,7 @@ def setUp(self, *args, **kwargs): # Variable self.Variable = self.env["cx.tower.variable"] self.VariableValue = self.env["cx.tower.variable.value"] + self.VariableOption = self.env["cx.tower.variable.option"] self.variable_path = self.Variable.create({"name": "test_path_"}) self.variable_dir = self.Variable.create({"name": "test_dir"}) diff --git a/cetmix_tower_server/tests/test_cetmix_tower.py b/cetmix_tower_server/tests/test_cetmix_tower.py index 61f60732..a8c8755b 100644 --- a/cetmix_tower_server/tests/test_cetmix_tower.py +++ b/cetmix_tower_server/tests/test_cetmix_tower.py @@ -1,6 +1,8 @@ # Copyright (C) 2024 Cetmix OÜ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from unittest.mock import patch +from ..models.constants import SSH_CONNECTION_ERROR, SSH_CONNECTION_TIMEOUT from .common import TestTowerCommon @@ -90,3 +92,70 @@ def test_server_get_variable_value(self): self.server_test_1.reference, variable_meme.reference ) self.assertEqual(value, server_value.value_char) + + def test_server_check_ssh_connection(self): + """ + Test SSH connection check with a mocked function that + either returns a dictionary or raises an exception. + """ + + def mock_server_check_ssh_connection( + this, server_reference, attempts=5, timeout=15 + ): + if server_reference == self.server_test_1.reference: + return { + "code": 0, + "message": "Mocked: SSH connection successful", + } + elif server_reference == "invalid_server": + raise ValueError("Mocked: Invalid server reference") + elif server_reference == "timeout_server": + raise TimeoutError("Mocked: SSH connection timed out") + elif server_reference == "max_attempts_timeout": + return { + "code": SSH_CONNECTION_TIMEOUT, + "message": "Mocked: SSH connection timeout on last attempt", + } + else: + return { + "code": SSH_CONNECTION_ERROR, + "message": "Mocked: Unknown server", + } + + with patch( + "odoo.addons.cetmix_tower_server.models.cetmix_tower.CetmixTower.server_check_ssh_connection", + mock_server_check_ssh_connection, + ): + # Test successful connection + result = self.env["cetmix.tower"].server_check_ssh_connection( + self.server_test_1.reference + ) + self.assertEqual(result["code"], 0, "SSH connection should be successful.") + + # Test invalid server + with self.assertRaises(ValueError): + self.env["cetmix.tower"].server_check_ssh_connection("invalid_server") + + # Test connection timeout + with self.assertRaises(TimeoutError): + self.env["cetmix.tower"].server_check_ssh_connection("timeout_server") + + # Test connection timeout after max attempts + result = self.env["cetmix.tower"].server_check_ssh_connection( + "max_attempts_timeout", attempts=5 + ) + self.assertEqual( + result["code"], + SSH_CONNECTION_TIMEOUT, + "SSH connection should timeout after maximum attempts.", + ) + + # Test unknown server + result = self.env["cetmix.tower"].server_check_ssh_connection( + "unknown_server" + ) + self.assertEqual( + result["code"], + SSH_CONNECTION_ERROR, + "Unknown server should return code 503.", + ) diff --git a/cetmix_tower_server/tests/test_command.py b/cetmix_tower_server/tests/test_command.py index 111a8a0a..7d094ae1 100644 --- a/cetmix_tower_server/tests/test_command.py +++ b/cetmix_tower_server/tests/test_command.py @@ -38,11 +38,17 @@ def setUp(self, *args, **kwargs): } ) + # secret value as multi line string self.python_ssh_key = self.Key.create( { "name": "Test Python SSH Key", + "reference": "test_python_ssh_key", "key_type": "k", - "secret_value": "Python much key", + "secret_value": """ + Python + much + key + """, } ) diff --git a/cetmix_tower_server/tests/test_plan.py b/cetmix_tower_server/tests/test_plan.py index 5892da7c..49a91e69 100644 --- a/cetmix_tower_server/tests/test_plan.py +++ b/cetmix_tower_server/tests/test_plan.py @@ -40,6 +40,40 @@ def setUp(self, *args, **kwargs): "command_id": self.command_create_dir.id, } ) + # Flight plan with access level 1 to test user access rights + self.plan_3 = self.Plan.create( + { + "name": "Test plan 3", + "note": "Test user access rights", + "access_level": "1", + "line_ids": [ + (0, 0, {"command_id": self.command_create_dir.id, "sequence": 1}), + ], + } + ) + # Create line for plan 3 + self.plan_3_line_1 = self.plan_line.create( + { + "plan_id": self.plan_3.id, + "command_id": self.command_create_dir.id, + "sequence": 10, + } + ) + self.plan_3_line_1_action = self.env["cx.tower.plan.line.action"].create( + { + "line_id": self.plan_3_line_1.id, + "condition": "==", + "value_char": "test", + "action": "e", + } + ) + self.variable_value = self.env["cx.tower.variable.value"].create( + { + "variable_id": self.variable_os.id, + "value_char": "Windows 2k", + "plan_line_action_id": self.plan_3_line_1_action.id, + } + ) def test_plan_line_action_name(self): """Test plan line action naming""" @@ -1271,3 +1305,390 @@ def test_plan_unlink(self): self.plan_line_action.search([("id", "in", plan_line_action_ids.ids)]), msg="Plan line action should be deleted when Plan line is deleted", ) + + def test_plan_lines_user_access_rights(self): + """ + Test user access rights for plan lines + """ + # Ensure that user without any group cannot access plan lines + test_plan_3_as_bob = self.plan_3.with_user(self.user_bob) + with self.assertRaises(AccessError): + plan_line_read_result = test_plan_3_as_bob.line_ids[0].read([]) + # Add user_bob to `group_user` and test plan.line access + self.add_to_group(self.user_bob, "cetmix_tower_server.group_user") + plan_line_read_result = test_plan_3_as_bob.line_ids[0].read([]) + self.assertEqual( + plan_line_read_result[0]["name"], + "Test create directory", + msg="User should access plan lines with access_level 1", + ) + # Test that user cannot write to plan lines + with self.assertRaises(AccessError): + test_plan_3_as_bob.line_ids[0].write({"sequence": 10}) + + # Test that user cannot unlink plan lines + with self.assertRaises(AccessError): + test_plan_3_as_bob.line_ids[0].unlink() + + def test_plan_lines_subscribed_user_access_rights(self): + """ + Test user access to the plan lines assigned to the server they are subscribed to + """ + self.add_to_group(self.user_bob, "cetmix_tower_server.group_user") + # Assign Plan_3 to the server_test_1 + self.write_and_invalidate( + self.plan_3, **{"server_ids": [(6, 0, [self.server_test_1.id])]} + ) + # Ensure that user not subscribed to the server cannot access plan lines + test_plan_3_as_bob = self.plan_3.with_user(self.user_bob) + with self.assertRaises(AccessError): + plan_line_read_result = test_plan_3_as_bob.line_ids[0].read([]) + # Subscribe user to the server + self.server_test_1.message_subscribe([self.user_bob.partner_id.id]) + # Check that user can access plan lines + plan_line_read_result = test_plan_3_as_bob.line_ids[0].read([]) + self.assertEqual( + plan_line_read_result[0]["name"], + "Test create directory", + msg="User should access plan lines assigned to the server " + "they are subscribed to", + ) + + def test_plan_lines_manager_access_rights(self): + """ + Test manager access rights for plan lines + """ + self.add_to_group(self.user_bob, "cetmix_tower_server.group_manager") + test_plan_3_as_bob = self.plan_3.with_user(self.user_bob) + # Test that manager can write to plan lines + test_plan_3_as_bob.line_ids[0].write({"sequence": 10}) + self.assertEqual( + test_plan_3_as_bob.line_ids[0].sequence, + 10, + msg="Manager should be able to update sequence", + ) + # Test that manager can not unlink plan lines they did not create + with self.assertRaises(AccessError): + test_plan_3_as_bob.line_ids[0].unlink() + # Test that manager can create plan lines + plan_line_as_bob = self.plan_line.with_user(self.user_bob).create( + { + "plan_id": test_plan_3_as_bob.id, + "command_id": self.command_create_dir.id, + "sequence": 11, + } + ) + self.assertTrue( + plan_line_as_bob.exists(), + msg="Manager should be able to create plan lines", + ) + # Test that manager can delete plan lines they created + plan_line_as_bob.unlink() + self.assertFalse( + plan_line_as_bob.exists(), + msg="Manager should be able to delete own plan lines", + ) + + def test_plan_lines_subscribed_manager_access_rights(self): + """ + Test manager access rights for plan lines assigned to the server they are + subscribed to + """ + self.add_to_group(self.user_bob, "cetmix_tower_server.group_manager") + # Assign Plan_3 to the server_test_1 + self.write_and_invalidate( + self.plan_3, **{"server_ids": [(6, 0, [self.server_test_1.id])]} + ) + # Ensure that manager without subscribing to the server cannot access plan lines + test_plan_3_as_bob = self.plan_3.with_user(self.user_bob) + with self.assertRaises(AccessError): + plan_line_read_result = test_plan_3_as_bob.line_ids[0].read([]) + # Subscribe manager to the server + self.server_test_1.message_subscribe([self.user_bob.partner_id.id]) + # Check that manager can access plan lines + plan_line_read_result = test_plan_3_as_bob.line_ids[0].read([]) + self.assertEqual( + plan_line_read_result[0]["name"], + "Test create directory", + msg="Manager should access plan lines assigned to the server " + "they are subscribed to", + ) + # Test that manager can create lines assigned to the server they are + # subscribed to + plan_line_as_bob = self.plan_line.with_user(self.user_bob).create( + { + "plan_id": test_plan_3_as_bob.id, + "command_id": self.command_create_dir.id, + "sequence": 12, + } + ) + self.assertTrue( + plan_line_as_bob.exists(), + msg="Manager should be able to create plan lines assigned to the server " + "they are subscribed to", + ) + # Test that manager has no access to lines assigned to the server they + # are not subscribed to + self.server_test_1.message_unsubscribe([self.user_bob.partner_id.id]) + with self.assertRaises(AccessError): + plan_line_read_result = test_plan_3_as_bob.read([]) + + def test_plan_line_action_user_access_rights(self): + """ + Test user access rights for plan line actions + """ + # Ensure user without any group cannot access plan line actions + test_action_as_bob = self.plan_3_line_1_action.with_user(self.user_bob) + with self.assertRaises(AccessError): + test_action_as_bob.read([]) + + # Add user to group_user and test access + self.add_to_group(self.user_bob, "cetmix_tower_server.group_user") + # User should be able to read plan line actions + action_read_result = test_action_as_bob.read([]) + self.assertEqual( + action_read_result[0]["condition"], + "==", + msg="User should be able to read plan line actions", + ) + + # User should not be able to create/write/unlink + with self.assertRaises(AccessError): + self.env["cx.tower.plan.line.action"].with_user(self.user_bob).create( + { + "line_id": self.plan_3_line_1.id, + "condition": "==", + "value_char": "test2", + "action": "e", + } + ) + + with self.assertRaises(AccessError): + test_action_as_bob.write({"value_char": "modified"}) + + with self.assertRaises(AccessError): + test_action_as_bob.unlink() + + def test_plan_line_action_subscribed_user_access_rights(self): + """ + Test user access rights for plan line actions assigned to servers + """ + self.add_to_group(self.user_bob, "cetmix_tower_server.group_user") + + # Assign plan to server + self.write_and_invalidate( + self.plan_3, **{"server_ids": [(6, 0, [self.server_test_1.id])]} + ) + + # User not subscribed - should not have access + test_action_as_bob = self.plan_3_line_1_action.with_user(self.user_bob) + with self.assertRaises(AccessError): + test_action_as_bob.read([]) + + # Subscribe user to server + self.server_test_1.message_subscribe([self.user_bob.partner_id.id]) + + # User should now have read access + action_read_result = test_action_as_bob.read([]) + self.assertEqual( + action_read_result[0]["condition"], + "==", + msg="Subscribed user should be able to read plan line actions", + ) + + def test_plan_line_action_manager_access_rights(self): + """ + Test manager access rights for plan line actions + """ + self.add_to_group(self.user_bob, "cetmix_tower_server.group_manager") + test_action_as_bob = self.plan_3_line_1_action.with_user(self.user_bob) + + # Manager should be able to read and write + action_read_result = test_action_as_bob.read([]) + self.assertEqual( + action_read_result[0]["condition"], + "==", + msg="Manager should be able to read plan line actions", + ) + + test_action_as_bob.write({"value_char": "modified"}) + self.assertEqual( + test_action_as_bob.value_char, + "modified", + msg="Manager should be able to modify plan line actions", + ) + + # Manager should be able to create own actions + new_action_as_bob = ( + self.env["cx.tower.plan.line.action"] + .with_user(self.user_bob) + .create( + { + "line_id": self.plan_3_line_1.id, + "condition": "==", + "value_char": "test2", + "action": "e", + } + ) + ) + + self.assertTrue( + new_action_as_bob.exists(), + msg="Manager should be able to create plan line actions", + ) + + # Manager should be able to delete own actions but not others + with self.assertRaises(AccessError): + test_action_as_bob.unlink() + + new_action_as_bob.unlink() + self.assertFalse( + new_action_as_bob.exists(), + msg="Manager should be able to delete own plan line actions", + ) + + def test_plan_line_action_subscribed_manager_access_rights(self): + """ + Test manager access rights for plan line actions assigned to servers + """ + self.add_to_group(self.user_bob, "cetmix_tower_server.group_manager") + # Assign plan to server + self.write_and_invalidate( + self.plan_3, **{"server_ids": [(6, 0, [self.server_test_1.id])]} + ) + test_action_as_bob = self.plan_3_line_1_action.with_user(self.user_bob) + + # Manager not subscribed - should not have access + with self.assertRaises(AccessError): + test_action_as_bob.read([]) + + # Subscribe manager to server + self.server_test_1.message_subscribe([self.user_bob.partner_id.id]) + + # Manager should now have full access + action_read_result = test_action_as_bob.read([]) + self.assertEqual( + action_read_result[0]["condition"], + "==", + msg="Subscribed manager should be able to read plan line actions", + ) + + # Create own action as subscribed manager + new_action_as_bob = ( + self.env["cx.tower.plan.line.action"] + .with_user(self.user_bob) + .create( + { + "line_id": self.plan_3_line_1.id, + "condition": "==", + "value_char": "test2", + "action": "e", + } + ) + ) + self.assertTrue( + new_action_as_bob.exists(), + msg="Subscribed manager should be able to create plan line actions", + ) + # Test that manager has no access to lines assigned to the server they + # are not subscribed to + self.server_test_1.message_unsubscribe([self.user_bob.partner_id.id]) + with self.assertRaises(AccessError): + new_action_as_bob.read([]) + + def test_plan_line_action_variable_values_user_access_rights(self): + """ + Test user access rights for variable values associated with plan line actions + """ + # group_user: Plan not assigned to server, ensure access to variable value in + # plan line action + # Add user to group + self.add_to_group(self.user_bob, "cetmix_tower_server.group_user") + test_plan_line_action_as_bob = self.plan_3_line_1_action.with_user( + self.user_bob + ) + plan_line_action_vv_read_result = ( + test_plan_line_action_as_bob.variable_value_ids.read([]) + ) + self.assertEqual( + plan_line_action_vv_read_result[0]["value_char"], + self.variable_value.value_char, + msg="Value should be the same", + ) + # User not subscribed to the server: ensure no access to variable value in + # plan line action + self.write_and_invalidate( + self.plan_3, **{"server_ids": [(6, 0, [self.server_test_1.id])]} + ) + with self.assertRaises(AccessError): + plan_line_action_vv_read_result = ( + test_plan_line_action_as_bob.variable_value_ids.read([]) + ) + # User subscribed to the server: ensure access to variable value in + # plan line action + self.server_test_1.message_subscribe([self.user_bob.partner_id.id]) + plan_line_action_vv_read_result = ( + test_plan_line_action_as_bob.variable_value_ids.read([]) + ) + self.assertEqual( + plan_line_action_vv_read_result[0]["value_char"], + self.variable_value.value_char, + msg="Value should be the same", + ) + + def test_plan_line_action_variable_values_manager_access_rights(self): + """ + Test manager access rights for variable values associated with plan line actions + """ + # add user_bob to group_manager + self.add_to_group(self.user_bob, "cetmix_tower_server.group_manager") + self.server_test_1.message_subscribe([self.user_bob.partner_id.id]) + self.write_and_invalidate( + self.plan_3, **{"server_ids": [(6, 0, [self.server_test_1.id])]} + ) + + # Manager subscribed to the server: ensure user_bob cannot remove variable value + # from action line if he is not creator of variable + with self.assertRaises(AccessError): + self.variable_value.with_user(self.user_bob).unlink() + # User subscribed to the server: ensure user_bob can create variable value in + # plan line action + variable_value_as_bob = ( + self.env["cx.tower.variable.value"] + .with_user(self.user_bob) + .create( + { + "variable_id": self.variable_os.id, + "value_char": "OS/2", + } + ) + ) + + plan_line_action_as_bob = ( + self.env["cx.tower.plan.line.action"] + .with_user(self.user_bob) + .create( + { + "line_id": self.plan_3_line_1.id, + "condition": ">", + "value_char": "100", + "action": "e", + "variable_value_ids": [(4, variable_value_as_bob.id)], + } + ) + ) + + # Ensure that variable value has assigned properly + self.assertIn( + variable_value_as_bob.id, + plan_line_action_as_bob.variable_value_ids.ids, + msg="variable_value_ids should contain variable_value.id", + ) + # User subscribed to the server: ensure user_bob can delete their own variable + # value from plan line action he created + variable_value_as_bob.unlink() + # Ensure the variable value has been deleted + self.assertFalse( + variable_value_as_bob.exists(), + msg="Manager should be able to delete own plan line action variable value", + ) diff --git a/cetmix_tower_server/tests/test_server_template.py b/cetmix_tower_server/tests/test_server_template.py index 063327bc..40523ee3 100644 --- a/cetmix_tower_server/tests/test_server_template.py +++ b/cetmix_tower_server/tests/test_server_template.py @@ -1,4 +1,5 @@ -from odoo.exceptions import ValidationError +from odoo.exceptions import AccessError, ValidationError +from odoo.tests.common import Form from .common import TestTowerCommon @@ -388,7 +389,6 @@ def test_successful_server_creation_with_required_variables(self): 0, { "variable_id": self.variable_version.id, - "value_char": "Test Value", "required": True, }, ) @@ -396,6 +396,12 @@ def test_successful_server_creation_with_required_variables(self): } ) + # Fill in the value for the required variable + with Form(wizard) as wizard_form: + with wizard_form.line_ids.edit(0) as line: + line.value_char = "Test Value" + wizard_form.save() + # Checking the successful creation of the server action = wizard.action_confirm() self.assertTrue(action, "Server should be created successfully.") @@ -735,3 +741,60 @@ def test_empty_values_for_required_variables(self): # Checking the error message error_message = str(cm.exception) self.assertIn("Empty values for variables: test_path_, test_dir", error_message) + + def test_server_template_variable_values_manager_access_rights(self): + """ + Test manager access rights for variable values associated with server templates + """ + self.add_to_group(self.user_bob, "cetmix_tower_server.group_manager") + server_template_sample_as_bob = self.server_template_sample.with_user( + self.user_bob + ) + # Assure that manager cannot read variable values + with self.assertRaises(AccessError): + server_template_sample_as_bob.variable_value_ids.read([]) + # Assure that manager can read variable values + self.server_template_sample.message_subscribe([self.user_bob.partner_id.id]) + # add variable values to server template + alien_variable_value = self.VariableValue.create( + { + "variable_id": self.variable_version.id, + "server_template_id": self.server_template_sample.id, + "value_char": "alien_value", + } + ) + variable_values_read = server_template_sample_as_bob.variable_value_ids.read([]) + self.assertEqual( + variable_values_read[0]["value_char"], + alien_variable_value.value_char, + "Variable values should be the same", + ) + + # Assure that manager cannot unlink variable values + with self.assertRaises(AccessError): + alien_variable_value.with_user(self.user_bob).unlink() + # Assure that manager can unlink own variable values + own_variable_value = self.VariableValue.with_user(self.user_bob).create( + { + "variable_id": self.variable_url.id, + "server_template_id": self.server_template_sample.id, + "value_char": "odoo.com", + } + ) + own_variable_value.unlink() + self.assertFalse( + self.VariableValue.search([("id", "=", own_variable_value.id)]), + "Own variable value should be deleted", + ) + # Assure that manager can create variable values but cannot unlink them + # if he unsubscribed from the server template + other_own_variable_value = self.VariableValue.with_user(self.user_bob).create( + { + "variable_id": self.variable_url.id, + "server_template_id": self.server_template_sample.id, + "value_char": "odoo.sh", + } + ) + self.server_template_sample.message_unsubscribe([self.user_bob.partner_id.id]) + with self.assertRaises(AccessError): + other_own_variable_value.unlink() diff --git a/cetmix_tower_server/tests/test_variable_option.py b/cetmix_tower_server/tests/test_variable_option.py index 89d7cef6..50083dfe 100644 --- a/cetmix_tower_server/tests/test_variable_option.py +++ b/cetmix_tower_server/tests/test_variable_option.py @@ -1,5 +1,7 @@ from psycopg2 import IntegrityError +from odoo.exceptions import ValidationError + from .common import TestTowerCommon @@ -10,20 +12,33 @@ class TestTowerVariableOption(TestTowerCommon): def setUp(self): super().setUp() - self.variable = self.env["cx.tower.variable"].create( + + self.variable_odoo_versions = self.Variable.create( { "name": "odoo_versions", + "variable_type": "o", } ) - def test_unique_constraint(self): - """Test the unique constraint on name and variable_id.""" - self.env["cx.tower.variable.option"].create( + self.variable_option_17_0 = self.VariableOption.create( { "name": "17.0", - "variable_id": self.variable.id, + "value_char": "17.0", + "variable_id": self.variable_odoo_versions.id, + } + ) + + self.variable_option_18_0 = self.VariableOption.create( + { + "name": "18.0", + "value_char": "18.0", + "variable_id": self.variable_odoo_versions.id, } ) + + def test_unique_constraint(self): + """Test the unique constraint on name and variable_id.""" + # Test that creating another option with the same # 'name' and 'variable_id' raises an IntegrityError with self.assertRaises( @@ -33,6 +48,30 @@ def test_unique_constraint(self): self.env["cx.tower.variable.option"].create( { "name": "17.0", - "variable_id": self.variable.id, + "value_char": "17.0", + "variable_id": self.variable_odoo_versions.id, } ) + + def test_variable_value_set_from_option(self): + """Test that a variable value can be set from an option.""" + + variable_value = self.VariableValue.create( + { + "server_id": self.server_test_1.id, + "variable_id": self.variable_odoo_versions.id, + } + ) + + # -- 1 -- + # Set value_char to an existing option + variable_value.value_char = "17.0" + self.assertEqual( + variable_value.option_id, + self.variable_option_17_0, + ) + + # -- 2 -- + # Set value_char to a non-existing option + with self.assertRaises(ValidationError): + variable_value.value_char = "29.0" diff --git a/cetmix_tower_server/views/cx_tower_command_log_view.xml b/cetmix_tower_server/views/cx_tower_command_log_view.xml index 07686bd8..8fdc0368 100644 --- a/cetmix_tower_server/views/cx_tower_command_log_view.xml +++ b/cetmix_tower_server/views/cx_tower_command_log_view.xml @@ -99,8 +99,10 @@ cx.tower.command.log diff --git a/cetmix_tower_server/views/cx_tower_command_view.xml b/cetmix_tower_server/views/cx_tower_command_view.xml index 91a72c60..1c6448dc 100644 --- a/cetmix_tower_server/views/cx_tower_command_view.xml +++ b/cetmix_tower_server/views/cx_tower_command_view.xml @@ -73,11 +73,6 @@ widget="many2many_tags" options="{'color_field': 'color'}" /> - + + @@ -129,6 +137,16 @@ >requests: Python 'requests' library. Available methods: 'post', 'get', 'request'

  • json: Python 'json' library. Available methods: 'dumps'
  • +
  • hashlib: Python 'hashlib' library. + Available methods: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'sha3_224', 'sha3_256',
    + 'sha3_384', 'sha3_512', 'shake_128', 'shake_256', 'blake2b', 'blake2s', 'md5', 'new'
  • +
  • hmac: Python 'hmac' library. Use 'new' to create HMAC objects.
    + Available methods on the HMAC *object*: 'update', 'copy', 'digest', 'hexdigest'.
    + Module-level function: 'compare_digest'.
  • UserError: Warning Exception to use with @@ -196,6 +214,7 @@ + diff --git a/cetmix_tower_server/views/cx_tower_file_template_view.xml b/cetmix_tower_server/views/cx_tower_file_template_view.xml index 67988cf5..a560581f 100644 --- a/cetmix_tower_server/views/cx_tower_file_template_view.xml +++ b/cetmix_tower_server/views/cx_tower_file_template_view.xml @@ -20,16 +20,12 @@
    @@ -47,14 +43,21 @@ name="keep_when_deleted" attrs="{'invisible': [('source', '=', 'server')]}" /> + + + - - diff --git a/cetmix_tower_server/views/cx_tower_file_view.xml b/cetmix_tower_server/views/cx_tower_file_view.xml index 55165a21..5669543a 100644 --- a/cetmix_tower_server/views/cx_tower_file_view.xml +++ b/cetmix_tower_server/views/cx_tower_file_view.xml @@ -68,11 +68,6 @@ name="keep_when_deleted" attrs="{'invisible': [('source', '!=', 'tower')]}" /> - @@ -85,6 +80,18 @@ attrs="{'invisible': ['|', ('auto_sync', '=', False), ('source', '!=', 'server')]}" /> + + diff --git a/cetmix_tower_server/views/cx_tower_interpreter_view.xml b/cetmix_tower_server/views/cx_tower_interpreter_view.xml deleted file mode 100644 index ba1411fe..00000000 --- a/cetmix_tower_server/views/cx_tower_interpreter_view.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - cx.tower.interpreter.view.form - cx.tower.interpreter - -
    - - - - - - - - - - - -
    -
    -
    - - - cx.tower.interpreter.view.tree - cx.tower.interpreter - - - - - - - - - Interpreter - ir.actions.act_window - cx.tower.interpreter - tree,form - - -
    diff --git a/cetmix_tower_server/views/cx_tower_key_view.xml b/cetmix_tower_server/views/cx_tower_key_view.xml index f6e678be..81a41efe 100644 --- a/cetmix_tower_server/views/cx_tower_key_view.xml +++ b/cetmix_tower_server/views/cx_tower_key_view.xml @@ -10,11 +10,15 @@ - + diff --git a/cetmix_tower_server/views/cx_tower_plan_line_view.xml b/cetmix_tower_server/views/cx_tower_plan_line_view.xml index 08a169bd..df0497e1 100644 --- a/cetmix_tower_server/views/cx_tower_plan_line_view.xml +++ b/cetmix_tower_server/views/cx_tower_plan_line_view.xml @@ -80,10 +80,26 @@ - + + + +
    diff --git a/cetmix_tower_server/views/cx_tower_plan_view.xml b/cetmix_tower_server/views/cx_tower_plan_view.xml index 916a6284..830a45ea 100644 --- a/cetmix_tower_server/views/cx_tower_plan_view.xml +++ b/cetmix_tower_server/views/cx_tower_plan_view.xml @@ -135,6 +135,7 @@ +

    - +

    @@ -176,13 +176,33 @@ - + + + + - + +

    - +

    @@ -288,15 +288,17 @@ - diff --git a/cetmix_tower_server/views/cx_tower_variable_view.xml b/cetmix_tower_server/views/cx_tower_variable_view.xml index 227b883b..7321967e 100644 --- a/cetmix_tower_server/views/cx_tower_variable_view.xml +++ b/cetmix_tower_server/views/cx_tower_variable_view.xml @@ -41,6 +41,8 @@ + + diff --git a/cetmix_tower_server/views/menuitems.xml b/cetmix_tower_server/views/menuitems.xml index f25e8711..ca5f7cfe 100644 --- a/cetmix_tower_server/views/menuitems.xml +++ b/cetmix_tower_server/views/menuitems.xml @@ -112,13 +112,6 @@ parent="menu_settings" sequence="100" /> -