[ADD] module attachment_file_extension

This commit is contained in:
Alex Comba 2015-04-15 11:15:35 +02:00
parent 420ae2218a
commit ee62a2f628
7 changed files with 234 additions and 0 deletions

View File

@ -0,0 +1,34 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License: AGPL-3
Attachment File Extension
=========================
This module was written to get attachment files readable by any external
software, expecially by those that need to recognise the file type from their
extension to open them properly. It allows to store attachments on filesystem
adding the file extension to their filename.
Credits
=======
Contributors
------------
* Alex Comba <alex.comba@agilebg.com>
* Lorenzo Battistini <lorenzo.battistini@agilebg.com>
Maintainer
----------
.. image:: http://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: http://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit http://odoo-community.org.

View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (C) 2015 Agile Business Group sagl (<http://www.agilebg.com>)
# @author Alex Comba <alex.comba@agilebg.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import models

View File

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (C) 2015 Agile Business Group sagl (<http://www.agilebg.com>)
# @author Alex Comba <alex.comba@agilebg.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{
"name": "Attachment File Extension",
"version": "1.0",
"category": "Knowledge Management",
"summary": """
It allows to store attachments on filesystem adding the extension file to
their filename.
""",
'author': "Agile Business Group, Odoo Community Association (OCA)",
"website": "http://www.agilebg.com",
"license": "AGPL-3",
"depends": [],
"data": [],
"installable": True,
}

View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (C) 2015 Agile Business Group sagl (<http://www.agilebg.com>)
# @author Alex Comba <alex.comba@agilebg.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import ir_attachment

View File

@ -0,0 +1,85 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (C) 2015 Agile Business Group sagl
# (<http://www.agilebg.com>)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv import orm, fields
import os.path
import threading
class IrAttachment(orm.Model):
_inherit = 'ir.attachment'
def __init__(self, *args, **kwargs):
self._file_extension_lock = threading.RLock()
self._extension = None
super(IrAttachment, self).__init__(*args, **kwargs)
def _full_path(self, cr, uid, path):
# every calls to this method is managed using by _file_extension_lock
# to avoid the risk of overwriting the _extension attribute
full_path = super(IrAttachment, self)._full_path(cr, uid, path)
if self._extension:
full_path += self._extension
return full_path
def _data_set(self, cr, uid, id, name, value, arg, context=None):
with self._file_extension_lock:
attachment = self.browse(cr, uid, id, context=context)
if attachment.datas_fname:
filename, extension = os.path.splitext(attachment.datas_fname)
self._extension = extension
attachment.write({'extension': extension})
super(IrAttachment, self)._data_set(
cr, uid, id, name, value, arg, context=context)
def _data_get(self, cr, uid, ids, name, arg, context=None):
res = {}
for attachment in self.browse(cr, uid, ids, context=context):
if attachment.extension:
with self._file_extension_lock:
self._extension = attachment.extension
res.update(
super(IrAttachment, self)._data_get(
cr, uid, [attachment.id], name, arg,
context=context))
else:
res.update(
super(IrAttachment, self)._data_get(
cr, uid, [attachment.id], name, arg,
context=context))
return res
def unlink(self, cr, uid, ids, context=None):
for attachment in self.browse(cr, uid, ids, context=context):
if attachment.extension:
with self._file_extension_lock:
self._extension = attachment.extension
super(IrAttachment, self).unlink(
cr, uid, ids, context=context)
else:
super(IrAttachment, self).unlink(cr, uid, ids, context=context)
_columns = {
'datas': fields.function(
_data_get, fnct_inv=_data_set, string='File Content',
type="binary", nodrop=True),
'extension': fields.char(string='Attachment File Extension', size=4),
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,38 @@
import hashlib
import os
from openerp.tests.common import TransactionCase
HASH_SPLIT = 2
class TestAttachmentFileEstension(TransactionCase):
def setUp(self):
super(TestAttachmentFileEstension, self).setUp()
registry, cr, uid = self.registry, self.cr, self.uid
self.ira = registry('ir.attachment')
self.filestore = self.ira._filestore(cr, uid)
# Blob
self.blob = 'blob'
self.blob_b64 = self.blob.encode('base64')
blob_hash = hashlib.sha1(self.blob).hexdigest()
self.blob_fname = blob_hash[:HASH_SPLIT] + '/' + blob_hash
self.blob_datas_fname = 'ira.ext'
def test_01_store_on_disk(self):
cr, uid = self.cr, self.uid
ira_id = self.ira.create(
cr, uid, {'name': 'ira',
'datas': self.blob_b64,
'datas_fname': self.blob_datas_fname})
attachment = self.ira.browse(cr, uid, ira_id)
filename, extension = os.path.splitext(self.blob_datas_fname)
self.assertEqual(attachment.store_fname, self.blob_fname)
self.assertEqual(attachment.extension, extension)
self.assertTrue(
os.path.isfile(os.path.join(
self.filestore,
attachment.store_fname + attachment.extension)))