From 11eed83d5a8ac3b7bf3578e6f197cde29138f1f1 Mon Sep 17 00:00:00 2001 From: Ivan Kropotkin Date: Sat, 11 May 2024 19:03:45 +0200 Subject: [PATCH] :zap: sync: add data files support --- sync/doc/changelog.rst | 1 + sync/models/__init__.py | 1 + sync/models/sync_data.py | 45 +++++++++++++++++++++++++++++++ sync/models/sync_project.py | 40 +++++++++++++++++++++++++++ sync/security/ir.model.access.csv | 3 +++ sync/views/sync_project_views.xml | 42 ++++++++++++++--------------- sync/views/sync_task_views.xml | 9 ++++++- 7 files changed, 118 insertions(+), 23 deletions(-) create mode 100644 sync/models/sync_data.py diff --git a/sync/doc/changelog.rst b/sync/doc/changelog.rst index 6ff2ee99..08d2165a 100644 --- a/sync/doc/changelog.rst +++ b/sync/doc/changelog.rst @@ -2,6 +2,7 @@ ------- - **New:** Use prime numbers for major releases ;-) +- **New:** Support data files - **Improvement:** make links dependent on project `7.0.0` diff --git a/sync/models/__init__.py b/sync/models/__init__.py index d0b38e2a..46411344 100644 --- a/sync/models/__init__.py +++ b/sync/models/__init__.py @@ -10,6 +10,7 @@ from . import sync_project_demo from . import sync_task from . import sync_job +from . import sync_data from . import ir_logging from . import ir_actions from . import ir_attachment diff --git a/sync/models/sync_data.py b/sync/models/sync_data.py new file mode 100644 index 00000000..e26933b5 --- /dev/null +++ b/sync/models/sync_data.py @@ -0,0 +1,45 @@ +# Copyright 2024 Ivan Yelizariev +import base64 +import csv +import json +from io import StringIO + +import yaml + +from odoo import fields, models + + +class SyncData(models.Model): + _name = "sync.data" + _description = "Sync Data File" + + name = fields.Char("Technical name") + project_id = fields.Many2one("sync.project", ondelete="cascade") + file_name = fields.Char("File Name") + file_content = fields.Binary("File Content") + + def csv(self, *args, **kwargs): + """Parse CSV file from binary field.""" + if self.file_content: + file_content = base64.b64decode(self.file_content) + file_content = file_content.decode("utf-8") + file_like_object = StringIO(file_content) + reader = csv.DictReader(file_like_object, *args, **kwargs) + return [row for row in reader] + return [] + + def json(self): + """Parse JSON file from binary field.""" + if self.file_content: + file_content = base64.b64decode(self.file_content) + file_content = file_content.decode("utf-8") + return json.loads(file_content) + return {} + + def yaml(self): + """Parse YAML file from binary field.""" + if self.file_content: + file_content = base64.b64decode(self.file_content) + file_content = file_content.decode("utf-8") + return yaml.safe_load(file_content) + return None diff --git a/sync/models/sync_project.py b/sync/models/sync_project.py index d4a8885f..34cfc5cf 100644 --- a/sync/models/sync_project.py +++ b/sync/models/sync_project.py @@ -5,8 +5,10 @@ import base64 import logging +import os from datetime import datetime +import urllib3 from pytz import timezone from odoo import api, fields, models @@ -107,6 +109,7 @@ class SyncProject(models.Model): log_count = fields.Integer(compute="_compute_log_count") link_ids = fields.One2many("sync.link", "project_id") link_count = fields.Integer(compute="_compute_link_count") + data_ids = fields.One2many("sync.data", "project_id") def copy(self, default=None): default = dict(default or {}) @@ -319,6 +322,10 @@ def record2image(record, fname="image_1920"): for w in self.task_ids.mapped("webhook_ids"): WEBHOOKS[w.trigger_name] = w.website_url + DATA = AttrDict() + for d in self.data_ids: + DATA[d.name] = d + core_eval_context = { "MAGIC": MAGIC, "SECRETS": SECRETS, @@ -330,6 +337,7 @@ def record2image(record, fname="image_1920"): "CORE": CORE, "PARAMS": PARAMS, "WEBHOOKS": WEBHOOKS, + "DATA": DATA, } LIB = eval_export(safe_eval, self.common_code, lib_eval_context) @@ -499,6 +507,38 @@ def magic_upgrade(self): if gist_files.get(file_name): vals[field_name] = gist_files[file_name] + # [DATA] + http = urllib3.PoolManager() + for file_info in gist_content["files"].values(): + # e.g. "data.emoji.csv" + file_name = file_info["filename"] + if not file_name.startswith("data."): + continue + raw_url = file_info["raw_url"] + response = http.request("GET", raw_url) + if response.status == 200: + file_content = response.data + file_content = base64.b64encode(file_content) + else: + raise Exception( + f"Failed to fetch raw content from {raw_url}. Status code: {response.status}" + ) + + technical_name = file_name + technical_name = technical_name[len("data.") :] + technical_name = os.path.splitext(technical_name)[0] + technical_name = technical_name.replace(".", "_") + + data_vals = { + "name": technical_name, + "project_id": self.id, + "file_name": file_name, + "file_content": file_content, + } + self.env["sync.data"]._create_or_update_by_xmlid( + data_vals, file_name, namespace=gist_id + ) + # Tasks 🦋 for file_name in gist_files: # e.g. "task.setup.py" diff --git a/sync/security/ir.model.access.csv b/sync/security/ir.model.access.csv index 5964da44..2ac9e400 100644 --- a/sync/security/ir.model.access.csv +++ b/sync/security/ir.model.access.csv @@ -5,6 +5,9 @@ access_sync_project_manager,sync.project manager,model_sync_project,sync_group_m access_sync_task_user,sync.task user,model_sync_task,sync_group_user,1,0,0,0 access_sync_task_dev,sync.task dev,model_sync_task,sync_group_dev,1,1,1,1 access_sync_task_manager,sync.task manager,model_sync_task,sync_group_manager,1,1,1,1 +access_sync_data_user,sync.data user,model_sync_data,sync_group_user,1,0,0,0 +access_sync_data_dev,sync.data dev,model_sync_data,sync_group_dev,1,1,1,1 +access_sync_data_manager,sync.data manager,model_sync_data,sync_group_manager,1,1,1,1 access_sync_trigger_automation_user,sync.trigger.automation user,model_sync_trigger_automation,sync_group_user,1,0,0,0 access_sync_trigger_automation_dev,sync.trigger.automation dev,model_sync_trigger_automation,sync_group_dev,1,1,1,1 access_sync_trigger_automation_manager,sync.trigger.automation manager,model_sync_trigger_automation,sync_group_manager,1,1,1,1 diff --git a/sync/views/sync_project_views.xml b/sync/views/sync_project_views.xml index 399cff3b..6a04c9f7 100644 --- a/sync/views/sync_project_views.xml +++ b/sync/views/sync_project_views.xml @@ -214,28 +214,6 @@

- @@ -275,6 +253,26 @@ + + + + + + + + +

+ + Hint: + + Documentation + + +

+

diff --git a/sync/views/sync_task_views.xml b/sync/views/sync_task_views.xml index 9d661c97..823afafd 100644 --- a/sync/views/sync_task_views.xml +++ b/sync/views/sync_task_views.xml @@ -1,5 +1,5 @@ - @@ -68,6 +68,13 @@ Hint: Updating this code won't change the triggers. Instead, update the gist file. +
+ + Documentation +