Skip to content

Commit 14db6bd

Browse files
committed
Add minio attachments
1 parent 85727ff commit 14db6bd

File tree

4 files changed

+184
-0
lines changed

4 files changed

+184
-0
lines changed

ir_attachment_minio/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from __future__ import absolute_import
2+
from . import ir_attachment

ir_attachment_minio/__terp__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# -*- coding: utf-8 -*-
2+
{
3+
"name": "ir_attachment_minio",
4+
"version": "0.1.0",
5+
"depends": ["base", "minio_backend"],
6+
"author": "GISCE-TI, S.L",
7+
"category": "Storage",
8+
"description": """
9+
This module provide :
10+
* Stores binary data to minio server.
11+
""",
12+
"init_xml": [],
13+
'update_xml': [],
14+
'demo_xml': [],
15+
'installable': True,
16+
'active': False,
17+
}

ir_attachment_minio/ir_attachment.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# encoding=utf-8
2+
from __future__ import absolute_import
3+
from osv import osv
4+
from minio_backend.fields import S3File
5+
6+
7+
def minioize(vals):
8+
vals['datas_minio'] = vals['datas']
9+
vals['datas'] = False
10+
11+
12+
def unminioize(vals):
13+
vals['datas'] = vals['datas_minio']
14+
del vals['datas_minio']
15+
16+
17+
class IrAttachment(osv.osv):
18+
_name = 'ir.attachment'
19+
_inherit = 'ir.attachment'
20+
21+
def create(self, cursor, uid, vals, context=None):
22+
if context is None:
23+
context = {}
24+
ctx = context.copy()
25+
if 'filename' in vals:
26+
ctx['datas_minio_filename'] = vals['filename']
27+
if 'datas' in vals and vals['datas']:
28+
minioize(vals)
29+
return super(IrAttachment, self).create(cursor, uid, vals, context=ctx)
30+
31+
def write(self, cursor, uid, ids, vals, context=None):
32+
if context is None:
33+
context = {}
34+
ctx = context.copy()
35+
if 'datas' in vals:
36+
minioize(vals)
37+
if 'filename' in vals:
38+
ctx['datas_minio_filename'] = vals['filename']
39+
return super(
40+
IrAttachment, self).write(cursor, uid, ids, vals, context=ctx
41+
)
42+
43+
def read(self, cursor, uid, ids, fields=None, context=None,
44+
load='_classic_read'):
45+
if fields and 'datas' in fields and 'datas_minio' not in fields:
46+
fields.append('datas_minio')
47+
res = super(IrAttachment, self).read(cursor, uid, ids, fields, context,
48+
load)
49+
if isinstance(ids, (list, tuple)):
50+
if res and 'datas' in res[0]:
51+
for attach in res:
52+
if attach['datas_minio']:
53+
unminioize(attach)
54+
else:
55+
if 'datas' in res and res['datas_minio']:
56+
unminioize(res)
57+
return res
58+
59+
def unlink(self, cursor, uid, ids, context=None):
60+
self.write(cursor, uid, ids, {'datas': False})
61+
return super(IrAttachment, self).unlink(cursor, uid, ids, context)
62+
63+
_columns = {
64+
'datas_minio': S3File('Minio object', 'attachments')
65+
}
66+
67+
68+
IrAttachment()

ir_attachment_minio/tests/__init__.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import base64
2+
from destral import testing
3+
from minio_backend.minio_backend import get_minio_client
4+
from minio.error import NoSuchKey
5+
6+
7+
class TestIrAttachmentMinio(testing.OOTestCaseWithCursor):
8+
def test_create_attachment_stores_in_minio(self):
9+
cursor = self.cursor
10+
uid = self.uid
11+
pool = self.openerp.pool
12+
attach_obj = pool.get('ir.attachment')
13+
14+
content = 'THIS IS A TEST FILE!'
15+
16+
attach_id = attach_obj.create(cursor, uid, {
17+
'name': 'This is a description',
18+
'filename': 'test.txt',
19+
'datas': base64.b64encode(content)
20+
})
21+
22+
client = get_minio_client()
23+
self.assertTrue(client.bucket_exists('attachments'))
24+
object_path = 'ir_attachment/{}_test.txt'.format(attach_id)
25+
self.assertEqual(
26+
client.get_object('attachments', object_path).data,
27+
content
28+
)
29+
30+
def test_write_attachment_stores_in_minio(self):
31+
cursor = self.cursor
32+
uid = self.uid
33+
pool = self.openerp.pool
34+
attach_obj = pool.get('ir.attachment')
35+
36+
content = 'THIS IS A TEST FILE!'
37+
38+
attach_id = attach_obj.create(cursor, uid, {
39+
'name': 'This is a description',
40+
'filename': 'test2.txt',
41+
'datas': base64.b64encode(content)
42+
})
43+
44+
new_content = 'THIS IS A MODIFIED TEST FILE!'
45+
46+
attach_obj.write(cursor, uid, [attach_id], {
47+
'datas': base64.b64encode(new_content)
48+
})
49+
50+
client = get_minio_client()
51+
self.assertTrue(client.bucket_exists('attachments'))
52+
object_path = 'ir_attachment/{}_test2.txt'.format(attach_id)
53+
self.assertEqual(
54+
client.get_object('attachments', object_path).data,
55+
new_content
56+
)
57+
58+
def test_unlink_attachment_removes_file_in_minio(self):
59+
cursor = self.cursor
60+
uid = self.uid
61+
pool = self.openerp.pool
62+
attach_obj = pool.get('ir.attachment')
63+
64+
content = 'THIS IS A TEST FILE!'
65+
66+
attach_id = attach_obj.create(cursor, uid, {
67+
'name': 'This is a description',
68+
'filename': 'test.txt',
69+
'datas': base64.b64encode(content)
70+
})
71+
72+
attach_obj.unlink(cursor, uid, [attach_id])
73+
74+
client = get_minio_client()
75+
object_path = 'ir_attachment/{}_test.txt'.format(attach_id)
76+
with self.assertRaises(NoSuchKey):
77+
client.get_object('attachments', object_path)
78+
79+
def test_read_attachment_from_minio(self):
80+
cursor = self.cursor
81+
uid = self.uid
82+
pool = self.openerp.pool
83+
attach_obj = pool.get('ir.attachment')
84+
85+
content = 'THIS IS A TEST FILE!'
86+
87+
attach_id = attach_obj.create(cursor, uid, {
88+
'name': 'This is a description',
89+
'filename': 'test.txt',
90+
'datas': base64.b64encode(content)
91+
})
92+
93+
attach = attach_obj.read(cursor, uid, attach_id, ['datas'])
94+
self.assertEqual(
95+
attach['datas'],
96+
base64.b64encode(content)
97+
)

0 commit comments

Comments
 (0)