diff --git a/attachment_synchronize/__manifest__.py b/attachment_synchronize/__manifest__.py
index 9594dbd13..6bc0943f6 100644
--- a/attachment_synchronize/__manifest__.py
+++ b/attachment_synchronize/__manifest__.py
@@ -22,6 +22,7 @@
'security/ir.model.access.csv',
],
'demo': [
+ "demo/attachment_synchronize_task_demo.xml",
],
'installable': True,
'application': False,
diff --git a/attachment_synchronize/data/cron.xml b/attachment_synchronize/data/cron.xml
index ab2f883f2..57b5e766e 100644
--- a/attachment_synchronize/data/cron.xml
+++ b/attachment_synchronize/data/cron.xml
@@ -1,16 +1,16 @@
-
-
+
+
Run attachment tasks import
30
minutes
-1
False
-
+
code
- model.run_task_scheduler([('method_type', '=', 'import')])
+ model.run_task_import_scheduler()
diff --git a/attachment_synchronize/demo/attachment_synchronize_task_demo.xml b/attachment_synchronize/demo/attachment_synchronize_task_demo.xml
new file mode 100644
index 000000000..8742b8d06
--- /dev/null
+++ b/attachment_synchronize/demo/attachment_synchronize_task_demo.xml
@@ -0,0 +1,20 @@
+
+
+
+ TEST Import
+
+ import
+ delete
+ test_import
+ foo@example.org,bar@example.org
+
+
+
+ TEST Export
+
+ export
+ test_export
+ foo@example.org,bar@example.org
+
+
+
diff --git a/attachment_synchronize/models/attachment.py b/attachment_synchronize/models/attachment.py
index 28df51bb5..183f965a0 100644
--- a/attachment_synchronize/models/attachment.py
+++ b/attachment_synchronize/models/attachment.py
@@ -8,7 +8,7 @@ import os
class AttachmentQueue(models.Model):
_inherit = 'attachment.queue'
- task_id = fields.Many2one('storage.backend.task', string='Task')
+ task_id = fields.Many2one('attachment.synchronize.task', string='Task')
storage_backend_id = fields.Many2one(
'storage.backend', string='Storage Backend',
related='task_id.backend_id', store=True)
diff --git a/attachment_synchronize/models/storage_backend.py b/attachment_synchronize/models/storage_backend.py
index b77a304db..8d88d9435 100644
--- a/attachment_synchronize/models/storage_backend.py
+++ b/attachment_synchronize/models/storage_backend.py
@@ -6,6 +6,6 @@ from odoo import fields, models
class StorageBackend(models.Model):
_inherit = "storage.backend"
- task_ids = fields.One2many(
- "storage.backend.task", "backend_id",
+ synchronize_task_ids = fields.One2many(
+ "attachment.synchronize.task", "backend_id",
string="Tasks")
diff --git a/attachment_synchronize/models/task.py b/attachment_synchronize/models/task.py
index eafd110ce..4212f0cfa 100644
--- a/attachment_synchronize/models/task.py
+++ b/attachment_synchronize/models/task.py
@@ -6,6 +6,7 @@ import os
import odoo
from odoo import api, fields, models, tools
+from odoo.osv import expression
_logger = logging.getLogger(__name__)
@@ -41,9 +42,9 @@ except ImportError:
_logger.warning("jinja2 not available, templating features will not work!")
-class StorageBackendTask(models.Model):
- _name = 'storage.backend.task'
- _description = 'Storage Backend task'
+class AttachmentSynchronizeTask(models.Model):
+ _name = 'attachment.synchronize.task'
+ _description = 'Attachment synchronize task'
name = fields.Char(required=True)
method_type = fields.Selection(
@@ -118,13 +119,13 @@ class StorageBackendTask(models.Model):
return render_result
@api.model
- def run_task_scheduler(self, domain=None):
+ def run_task_import_scheduler(self, domain=None):
if domain is None:
domain = []
- domain = expression.AND(domain, [
+ domain = expression.AND([domain, [
('method_type', '=', 'import'),
('enabled', '=', True),
- ])
+ ]])
for task in self.search(domain):
task.run_import()
@@ -133,8 +134,8 @@ class StorageBackendTask(models.Model):
self.ensure_one()
attach_obj = self.env['attachment.queue']
backend = self.backend_id
- filenames = backend._list(
- relative_path=self.filepath, pattern=self.pattern)
+ filepath = self.filepath or ""
+ filenames = backend._list(relative_path=filepath, pattern=self.pattern)
if self.check_duplicated_files:
filenames = self._file_to_import(filenames)
total_import = 0
@@ -145,8 +146,7 @@ class StorageBackendTask(models.Model):
new_env = api.Environment(new_cr, self.env.uid,
self.env.context)
try:
- full_absolute_path = os.path.join(
- self.filepath, file_name)
+ full_absolute_path = os.path.join(filepath, file_name)
datas = backend._get_b64_data(full_absolute_path)
attach_vals = self._prepare_attachment_vals(
datas, file_name)
@@ -156,8 +156,7 @@ class StorageBackendTask(models.Model):
if self.after_import == 'rename':
new_name = self._template_render(
self.new_name, attachment)
- new_full_path = os.path.join(
- self.filepath, new_name)
+ new_full_path = os.path.join(filepath, new_name)
elif self.after_import == 'move':
new_full_path = os.path.join(
self.move_path, file_name)
diff --git a/attachment_synchronize/security/ir.model.access.csv b/attachment_synchronize/security/ir.model.access.csv
index 5d4973cec..742f94e2f 100644
--- a/attachment_synchronize/security/ir.model.access.csv
+++ b/attachment_synchronize/security/ir.model.access.csv
@@ -1,2 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-access_storage_backend_task_manager,storage.backend.task.manager,model_storage_backend_task,base.group_system,1,1,1,1
+access_attachment_synchronize_task_manager,attachment.synchronize.task.manager,model_attachment_synchronize_task,base.group_system,1,1,1,1
diff --git a/attachment_synchronize/tests/__init__.py b/attachment_synchronize/tests/__init__.py
index e69de29bb..3845a51ae 100644
--- a/attachment_synchronize/tests/__init__.py
+++ b/attachment_synchronize/tests/__init__.py
@@ -0,0 +1,2 @@
+from . import test_import
+from . import test_export
diff --git a/attachment_synchronize/tests/common.py b/attachment_synchronize/tests/common.py
new file mode 100644
index 000000000..aee8d23f3
--- /dev/null
+++ b/attachment_synchronize/tests/common.py
@@ -0,0 +1,38 @@
+# Copyright 2020 Akretion (http://www.akretion.com).
+# @author Sébastien BEAU
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+import mock
+import os
+from odoo.addons.storage_backend.tests.common import Common
+
+
+class SyncCommon(Common):
+
+ def _clean_testing_directory(self):
+ for test_dir in [
+ self.directory_input, self.directory_output, self.directory_archived]:
+ for filename in self.backend._list(test_dir):
+ self.backend._delete(os.path.join(test_dir, filename))
+
+ def _create_test_file(self):
+ self.backend._add_b64_data(
+ os.path.join(self.directory_input, "bar.txt"),
+ self.filedata,
+ mimetype=u"text/plain")
+
+ def setUp(self):
+ super().setUp()
+ self.env.cr.commit = mock.Mock()
+ self.registry.enter_test_mode(self.env.cr)
+ self.directory_input = "test_import"
+ self.directory_output = "test_output"
+ self.directory_archived = "test_archived"
+ self._clean_testing_directory()
+ self._create_test_file()
+ self.task = self.env.ref("attachment_synchronize.import_from_filestore")
+
+ def tearDown(self):
+ self.registry.leave_test_mode()
+ self._clean_testing_directory()
+ super().tearDown()
diff --git a/attachment_synchronize/tests/test_export.py b/attachment_synchronize/tests/test_export.py
new file mode 100644
index 000000000..b902bc188
--- /dev/null
+++ b/attachment_synchronize/tests/test_export.py
@@ -0,0 +1,35 @@
+# Copyright 2020 Akretion (http://www.akretion.com).
+# @author Sébastien BEAU
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+import os
+import mock
+from .common import SyncCommon
+
+def raising_side_effect(*args, **kwargs):
+ raise Exception("Boom")
+
+
+class TestExport(SyncCommon):
+
+ def setUp(self):
+ super().setUp()
+ self.task = self.env.ref("attachment_synchronize.export_to_filestore")
+ self.attachment = self.env["attachment.queue"].create({
+ "name": "foo.txt",
+ "datas_fname": "foo.txt",
+ "task_id": self.task.id,
+ "file_type": "export",
+ "datas": self.filedata,
+ })
+
+ def test_export(self):
+ self.attachment.run()
+ result = self.backend._list("test_export")
+ self.assertEqual(result, ["foo.txt"])
+
+ def test_failing_export(self):
+ with mock.patch.object(type(self.backend), "_add_b64_data", side_effect=raising_side_effect):
+ self.attachment.run()
+ self.assertEqual(self.attachment.state, "failed")
+ self.assertEqual(self.attachment.state_message, "Boom")
diff --git a/attachment_synchronize/tests/test_import.py b/attachment_synchronize/tests/test_import.py
new file mode 100644
index 000000000..d1c58d5e5
--- /dev/null
+++ b/attachment_synchronize/tests/test_import.py
@@ -0,0 +1,80 @@
+# Copyright 2020 Akretion (http://www.akretion.com).
+# @author Sébastien BEAU
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from .common import SyncCommon
+
+
+class TestImport(SyncCommon):
+
+ @property
+ def archived_files(self):
+ return self.backend._list(self.directory_archived)
+
+ @property
+ def input_files(self):
+ return self.backend._list(self.directory_input)
+
+ def _check_attachment_created(self, count=1):
+ attachment = self.env["attachment.queue"].search([("name", "=", "bar.txt")])
+ self.assertEqual(len(attachment), count)
+
+ def test_import_with_rename(self):
+ self.task.write({"after_import": "rename", "new_name": "foo.txt"})
+ self.task.run_import()
+ self._check_attachment_created()
+ self.assertEqual(self.input_files, ["foo.txt"])
+ self.assertEqual(self.archived_files, [])
+
+ def test_import_with_move(self):
+ self.task.write({"after_import": "move", "move_path": self.directory_archived})
+ self.task.run_import()
+ self._check_attachment_created()
+ self.assertEqual(self.input_files, [])
+ self.assertEqual(self.archived_files, ["bar.txt"])
+
+ def test_import_with_move_and_rename(self):
+ self.task.write({
+ "after_import": "move_rename",
+ "new_name": "foo.txt",
+ "move_path": self.directory_archived,
+ })
+ self.task.run_import()
+ self._check_attachment_created()
+ self.assertEqual(self.input_files, [])
+ self.assertEqual(self.archived_files, ["foo.txt"])
+
+ def test_import_with_delete(self):
+ self.task.write({"after_import": "delete"})
+ self.task.run_import()
+ self._check_attachment_created()
+ self.assertEqual(self.input_files, [])
+ self.assertEqual(self.archived_files, [])
+
+ def test_import_twice(self):
+ self.task.write({"after_import": "delete"})
+ self.task.run_import()
+ self._check_attachment_created(count=1)
+
+ self._create_test_file()
+ self.task.run_import()
+ self._check_attachment_created(count=2)
+
+ def test_import_twice_no_duplicate(self):
+ self.task.write({"after_import": "delete", "check_duplicated_files": True})
+ self.task.run_import()
+ self._check_attachment_created(count=1)
+
+ self._create_test_file()
+ self.task.run_import()
+ self._check_attachment_created(count=1)
+
+ def test_running_cron(self):
+ self.task.write({"after_import": "delete"})
+ self.env["attachment.synchronize.task"].run_task_import_scheduler()
+ self._check_attachment_created(count=1)
+
+ def test_running_cron_disable_task(self):
+ self.task.write({"after_import": "delete", "enabled": False})
+ self.env["attachment.synchronize.task"].run_task_import_scheduler()
+ self._check_attachment_created(count=0)
diff --git a/attachment_synchronize/views/storage_backend_view.xml b/attachment_synchronize/views/storage_backend_view.xml
index 143aa1b46..71d159fdf 100644
--- a/attachment_synchronize/views/storage_backend_view.xml
+++ b/attachment_synchronize/views/storage_backend_view.xml
@@ -9,7 +9,7 @@
-
+
diff --git a/attachment_synchronize/views/task_view.xml b/attachment_synchronize/views/task_view.xml
index 9195143aa..75b8a8321 100644
--- a/attachment_synchronize/views/task_view.xml
+++ b/attachment_synchronize/views/task_view.xml
@@ -1,7 +1,7 @@
- storage.backend.task
+ attachment.synchronize.task
- storage.backend.task
+ attachment.synchronize.task