Tower: upload cetmix_tower_server 16.0.2.2.9 (via marketplace)
This commit is contained in:
228
addons/cetmix_tower_server/models/cx_tower_file_template.py
Normal file
228
addons/cetmix_tower_server/models/cx_tower_file_template.py
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
# 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.exceptions import ValidationError
|
||||||
|
|
||||||
|
from .cx_tower_file import TEMPLATE_FILE_FIELD_MAPPING
|
||||||
|
|
||||||
|
|
||||||
|
class CxTowerFileTemplate(models.Model):
|
||||||
|
"""File template to manage multiple files at once"""
|
||||||
|
|
||||||
|
_name = "cx.tower.file.template"
|
||||||
|
_inherit = [
|
||||||
|
"cx.tower.reference.mixin",
|
||||||
|
"cx.tower.key.mixin",
|
||||||
|
"cx.tower.template.mixin",
|
||||||
|
"cx.tower.access.role.mixin",
|
||||||
|
"cx.tower.tag.mixin",
|
||||||
|
]
|
||||||
|
_description = "Cetmix Tower File Template"
|
||||||
|
_order = "name"
|
||||||
|
|
||||||
|
active = fields.Boolean(default=True)
|
||||||
|
file_name = fields.Char(
|
||||||
|
help="Default full file name with file type for example: test.txt",
|
||||||
|
)
|
||||||
|
code = fields.Text(string="File content")
|
||||||
|
server_dir = fields.Char(string="Directory on server")
|
||||||
|
file_ids = fields.One2many("cx.tower.file", "template_id")
|
||||||
|
file_count = fields.Integer(
|
||||||
|
"File(s)",
|
||||||
|
compute="_compute_file_count",
|
||||||
|
)
|
||||||
|
tag_ids = fields.Many2many(
|
||||||
|
relation="cx_tower_file_template_tag_rel",
|
||||||
|
column1="file_template_id",
|
||||||
|
column2="tag_id",
|
||||||
|
)
|
||||||
|
note = fields.Text(help="This field is used to put some notes regarding template.")
|
||||||
|
keep_when_deleted = fields.Boolean(
|
||||||
|
help="File will be kept on server when deleted in Tower",
|
||||||
|
)
|
||||||
|
auto_sync = fields.Boolean(
|
||||||
|
help="If enabled, files created from this template will have "
|
||||||
|
"Auto Sync enabled by default. Used only with 'Tower' source.",
|
||||||
|
)
|
||||||
|
file_type = fields.Selection(
|
||||||
|
selection=lambda self: self.env["cx.tower.file"]._selection_file_type(),
|
||||||
|
default=lambda self: self.env["cx.tower.file"]._default_file_type(),
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
source = fields.Selection(
|
||||||
|
[
|
||||||
|
("tower", "Tower"),
|
||||||
|
("server", "Server"),
|
||||||
|
],
|
||||||
|
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",
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---- Access. Add relation for mixin fields
|
||||||
|
user_ids = fields.Many2many(
|
||||||
|
relation="cx_tower_file_template_user_rel",
|
||||||
|
domain=lambda self: [
|
||||||
|
("groups_id", "in", [self.env.ref("cetmix_tower_server.group_manager").id])
|
||||||
|
],
|
||||||
|
)
|
||||||
|
manager_ids = fields.Many2many(
|
||||||
|
relation="cx_tower_file_template_manager_rel",
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _get_depends_fields(cls):
|
||||||
|
"""
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
return ["code", "server_dir", "file_name"]
|
||||||
|
|
||||||
|
# -- Computes
|
||||||
|
@api.depends("file_ids")
|
||||||
|
def _compute_file_count(self):
|
||||||
|
"""
|
||||||
|
Compute total template files
|
||||||
|
"""
|
||||||
|
for template in self:
|
||||||
|
template.file_count = len(template.file_ids)
|
||||||
|
|
||||||
|
# -- Create/Write/Unlink
|
||||||
|
def write(self, vals):
|
||||||
|
"""
|
||||||
|
Override to update files related with the templates
|
||||||
|
"""
|
||||||
|
result = super().write(vals)
|
||||||
|
if any([field_ in vals for field_ in TEMPLATE_FILE_FIELD_MAPPING]):
|
||||||
|
for file in self.mapped("file_ids"):
|
||||||
|
file.write(file._get_file_values_from_related_template())
|
||||||
|
return result
|
||||||
|
|
||||||
|
# -- Actions
|
||||||
|
def action_open_files(self):
|
||||||
|
"""
|
||||||
|
Open current template files
|
||||||
|
"""
|
||||||
|
action = self.env["ir.actions.actions"]._for_xml_id(
|
||||||
|
"cetmix_tower_server.cx_tower_file_action"
|
||||||
|
)
|
||||||
|
action["domain"] = [("id", "in", self.file_ids.ids)]
|
||||||
|
return action
|
||||||
|
|
||||||
|
# -- Business logic
|
||||||
|
def create_file(self, server, server_dir="", if_file_exists="raise"):
|
||||||
|
"""
|
||||||
|
Create a new file using the current template for the selected server.
|
||||||
|
If the same file already exists, just ignore it or raise an error based on the
|
||||||
|
parameter.
|
||||||
|
|
||||||
|
:param server: recordset
|
||||||
|
The server (cx.tower.server) on which the file should be created. This is a
|
||||||
|
required parameter.
|
||||||
|
:param if_file_exists: str, optional
|
||||||
|
Defines the behavior if the file already exists on the server.
|
||||||
|
:param server_dir: str, optional
|
||||||
|
The directory on the server where the file should be created. If not set,
|
||||||
|
the server_dir field of the template will be used.
|
||||||
|
|
||||||
|
:return: cx.tower.file
|
||||||
|
Returns the newly created file record (cx.tower.file) if the file was
|
||||||
|
created successfully or if_file_exists is set to "overwrite".
|
||||||
|
Returns the existing file record if the file already exists
|
||||||
|
and if_file_exists is set to "skip".
|
||||||
|
|
||||||
|
:raises ValidationError:
|
||||||
|
If the file already exists on the server if_file_exists is set to "raise".
|
||||||
|
"""
|
||||||
|
self.ensure_one()
|
||||||
|
# Explicit guard against invalid behavior values
|
||||||
|
valid_behaviors = {"skip", "raise", "overwrite"}
|
||||||
|
if if_file_exists not in valid_behaviors:
|
||||||
|
raise ValidationError(
|
||||||
|
f"Invalid if_file_exists value: {if_file_exists}. "
|
||||||
|
f"Expected one of {valid_behaviors}."
|
||||||
|
)
|
||||||
|
file_model = self.env["cx.tower.file"]
|
||||||
|
existing_files = file_model.search(
|
||||||
|
[
|
||||||
|
("server_id", "=", server.id),
|
||||||
|
("source", "=", self.source),
|
||||||
|
],
|
||||||
|
order="id DESC",
|
||||||
|
)
|
||||||
|
existing_dir = server_dir or self.server_dir
|
||||||
|
|
||||||
|
# Render the server directory and file name from the template
|
||||||
|
variables = list(
|
||||||
|
set(
|
||||||
|
self.get_variables_from_code(self.file_name)
|
||||||
|
+ self.get_variables_from_code(existing_dir)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
var_vals = server.get_variable_values(variables).get(server.id) or {}
|
||||||
|
|
||||||
|
unrendered_path = (
|
||||||
|
f"{existing_dir}/{self.file_name}" if existing_dir else self.file_name
|
||||||
|
)
|
||||||
|
rendered_path = self.render_code_custom(unrendered_path, **var_vals)
|
||||||
|
|
||||||
|
# Filter existing files by rendered path
|
||||||
|
existing_files = existing_files.filtered(
|
||||||
|
lambda f: f.full_server_path == rendered_path
|
||||||
|
)
|
||||||
|
|
||||||
|
# Filter existing files by template if it exists, otherwise take the first one
|
||||||
|
existing_file = (
|
||||||
|
existing_files.filtered(lambda f: f.template_id == self)[:1]
|
||||||
|
or existing_files[:1]
|
||||||
|
)
|
||||||
|
|
||||||
|
if existing_file and if_file_exists == "skip":
|
||||||
|
return existing_file.with_context(file_creation_skipped=True)
|
||||||
|
|
||||||
|
if existing_file and if_file_exists == "raise":
|
||||||
|
raise ValidationError(_("File already exists on server."))
|
||||||
|
|
||||||
|
if existing_file and if_file_exists == "overwrite":
|
||||||
|
existing_file.with_context(is_custom_server_dir=True).write(
|
||||||
|
{
|
||||||
|
"template_id": self.id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return existing_file
|
||||||
|
|
||||||
|
vals = {
|
||||||
|
"name": self.file_name,
|
||||||
|
"server_id": server.id,
|
||||||
|
"server_dir": existing_dir,
|
||||||
|
"template_id": self.id,
|
||||||
|
"code": self.code,
|
||||||
|
"file_type": self.file_type,
|
||||||
|
"source": self.source,
|
||||||
|
"auto_sync": self.auto_sync,
|
||||||
|
}
|
||||||
|
|
||||||
|
new_file = file_model.with_context(is_custom_server_dir=True).create(vals)
|
||||||
|
# Return new_file if no file exists
|
||||||
|
return new_file
|
||||||
Reference in New Issue
Block a user