← Back to team overview

openerp-community-reviewer team mailing list archive

[Merge] lp:~akretion-team/server-env-tools/server-env-tools into lp:server-env-tools

 

Sébastien BEAU - http://www.akretion.com has proposed merging lp:~akretion-team/server-env-tools/server-env-tools into lp:server-env-tools.

Requested reviews:
  Server Environment And Tools Core Editors (server-env-tools-core-editors)

For more details, see:
https://code.launchpad.net/~akretion-team/server-env-tools/server-env-tools/+merge/222291

Here is a proposal too add new fields for image and binary
-- 
https://code.launchpad.net/~akretion-team/server-env-tools/server-env-tools/+merge/222291
Your team Server Environment And Tools Core Editors is requested to review the proposed merge of lp:~akretion-team/server-env-tools/server-env-tools into lp:server-env-tools.
=== added directory 'binary_field'
=== added file 'binary_field/__init__.py'
--- binary_field/__init__.py	1970-01-01 00:00:00 +0000
+++ binary_field/__init__.py	2014-06-06 09:01:45 +0000
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+#   Module for OpenERP 
+#   Copyright (C) 2013 Akretion (http://www.akretion.com).
+#   @author Sébastien BEAU <sebastien.beau@xxxxxxxxxxxx>
+#
+#   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 fields

=== added file 'binary_field/__openerp__.py'
--- binary_field/__openerp__.py	1970-01-01 00:00:00 +0000
+++ binary_field/__openerp__.py	2014-06-06 09:01:45 +0000
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+#   Module for OpenERP 
+#   Copyright (C) 2013 Akretion (http://www.akretion.com).
+#   @author Sébastien BEAU <sebastien.beau@xxxxxxxxxxxx>
+#
+#   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': 'Binary Field',
+ 'version': '0.0.1',
+ 'author': 'Akretion',
+ 'website': 'www.akretion.com',
+ 'license': 'AGPL-3',
+ 'category': 'Framework',
+ 'description': """This module extend the fields class in order to add 3 new
+type of fields
+- BinaryStore
+- ImageStore
+- ImageRezise
+
+Now let's do it ;)
+ 
+ """,
+ 'depends': [
+     'base',
+ ],
+ 'data': [
+     'data.xml',
+ ],
+ 'installable': True,
+ 'application': True,
+}
+
+
+
+

=== added file 'binary_field/data.xml'
--- binary_field/data.xml	1970-01-01 00:00:00 +0000
+++ binary_field/data.xml	2014-06-06 09:01:45 +0000
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+    <data>
+        <record id="binary_storage_parameter" model="ir.config_parameter">
+            <field name="key">binary.location</field>
+            <field name="value">file:///filestore</field>
+        </record>
+    </data>
+</openerp>

=== added file 'binary_field/fields.py'
--- binary_field/fields.py	1970-01-01 00:00:00 +0000
+++ binary_field/fields.py	2014-06-06 09:01:45 +0000
@@ -0,0 +1,249 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+#   Module for OpenERP
+#   Copyright (C) 2014 Akretion (http://www.akretion.com).
+#   @author Sébastien BEAU <sebastien.beau@xxxxxxxxxxxx>
+#
+#   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 fields, orm
+from openerp.tools import image_resize_image
+from openerp.tools.translate import _
+from openerp import tools
+import os
+import sys
+import logging
+
+_logger = logging.getLogger(__name__)
+
+
+class Storage(object):
+
+    def __init__(self, cr, uid, record, field_name):
+        self.cr = cr
+        self.uid = uid
+        self.pool = record._model.pool
+        self.field_key = ("%s-%s" % (record._name, field_name)).replace('.', '')
+        base_location = self.pool.get('ir.config_parameter').\
+            get_param(cr, uid, 'binary.location')
+        if not base_location:
+            raise orm.except_orm(
+                _('Configuration Error'),
+                _('The "binary.location" is empty, please fill it in'
+                  'Configuration > Parameters > System Parameters'))
+        self.base_location = base_location
+        self.location = (self.base_location, self.field_key)
+
+    def add(self, value):
+        if not value:
+            return {}
+        file_size = sys.getsizeof(value.decode('base64'))
+        binary_uid = self.pool['ir.attachment'].\
+            _file_write(self.cr, self.uid, self.location, value)
+        _logger.debug('Add binary %s/%s' % (self.field_key, binary_uid))
+        return {
+            'binary_uid': binary_uid,
+            'file_size': file_size,
+            }
+
+    def update(self, binary_uid, value):
+        _logger.debug('Delete binary %s/%s' % (self.field_key, binary_uid))
+        self.pool['ir.attachment'].\
+            _file_delete(self.cr, self.uid, self.location, binary_uid)
+        if not value:
+            return {}
+        return self.add(value)
+
+    def get(self, binary_uid):
+        return self.pool['ir.attachment'].\
+            _file_read(self.cr, self.uid, self.location, binary_uid)
+
+
+class BinaryField(fields.function):
+
+    def __init__(self, string, filters=None, get_storage=Storage, **kwargs):
+        new_kwargs = {
+            'type': 'binary',
+            'string': string,
+            'fnct': self._fnct_read,
+            'fnct_inv': self._fnct_write,
+            'multi': False,
+            }
+        new_kwargs.update(kwargs)
+        self.filters = filters
+        self.get_storage = get_storage
+        super(BinaryField, self).__init__(**new_kwargs)
+
+    #No postprocess are needed
+    #we already take care of bin_size option in the context
+    def postprocess(self, cr, uid, obj, field, value=None, context=None):
+        return value
+
+    def _prepare_binary_meta(self, cr, uid, field_name, res, context=None):
+        return {
+            '%s_uid' % field_name: res.get('binary_uid'),
+            '%s_file_size' % field_name: res.get('file_size'),
+            }
+
+    def _fnct_write(self, obj, cr, uid, ids, field_name, value, args,
+                    context=None):
+        if not isinstance(ids, (list, tuple)):
+            ids = [ids]
+        for record in obj.browse(cr, uid, ids, context=context):
+            storage = self.get_storage(cr, uid, record, field_name)
+            binary_uid = record['%s_uid' % field_name]
+            if binary_uid:
+                res = storage.update(binary_uid, value)
+            else:
+                res = storage.add(value)
+            vals = self._prepare_binary_meta(cr, uid, field_name, res, context=context)
+            record.write(vals)
+        return True
+
+    def _fnct_read(self, obj, cr, uid, ids, field_name, args, context=None):
+        result = {}
+        for record in obj.browse(cr, uid, ids, context=context):
+            storage = self.get_storage(cr, uid, record, field_name)
+            binary_uid = record['%s_uid' % field_name]
+            if binary_uid:
+                #Compatibility with existing binary field
+                if context.get('bin_size_%s' % field_name, context.get('bin_size')):
+                    size = record['%s_file_size' % field_name]
+                    result[record.id] = tools.human_size(long(size))
+                else:
+                    result[record.id] = storage.get(binary_uid)
+            else:
+                result[record.id] = None
+        return result
+
+
+class ImageField(BinaryField):
+
+    def __init__(self, string, filters=None, **kwargs):
+        self.filters = filters
+        super(ImageField, self).__init__(
+            string=string,
+            **kwargs)
+
+    def _fnct_write(self, obj, cr, uid, ids, field_name, value, args,
+                    context=None):
+        super(ImageField, self)._fnct_write(
+            obj, cr, uid, ids, field_name, value, args, context=context)
+        for name, field in obj._columns.items():
+            if isinstance(field, ImageResizeField) \
+                    and field.related_field == field_name:
+                field._refresh_cache(
+                    obj, cr, uid, ids, name, context=context)
+        return True
+
+
+class ImageResizeField(ImageField):
+
+    def __init__(self, string, related_field, height, width,
+                 filters=None, **kwargs):
+        self.filters = filters
+        self.height = height
+        self.width = width
+        self.related_field = related_field
+        super(ImageResizeField, self).__init__(
+            string=string,
+            **kwargs)
+
+    def _refresh_cache(self, obj, cr, uid, ids, field_name, context=None):
+        if not isinstance(ids, (list, tuple)):
+            ids = [ids]
+        for record_id in ids:
+            _logger.debug('Refreshing Image Cache from the field %s of object %s '
+                          'id : %s' % (field_name, obj._name, record_id))
+            field = obj._columns[field_name]
+            record = obj.browse(cr, uid, record_id, context=context)
+            original_image = record[field.related_field]
+            if original_image:
+                size = (field.height, field.width)
+                resized_image = image_resize_image(original_image, size)
+            else:
+                resized_image = None
+            ctx = context.copy()
+            ctx['refresh_image_cache'] = True
+            self._fnct_write(obj, cr, uid, [record_id], field_name,
+                             resized_image, None, context=ctx)
+
+    def _fnct_write(self, obj, cr, uid, ids, field_name, value, args,
+                    context=None):
+        if context is not None and context.get('refresh_image_cache'):
+            field = field_name
+        else:
+            field = obj._columns[field_name].related_field
+        return super(ImageResizeField, self)._fnct_write(
+            obj, cr, uid, ids, field, value, args, context=context)
+
+
+fields.BinaryField = BinaryField
+fields.ImageField = ImageField
+fields.ImageResizeField = ImageResizeField
+
+
+original__init__ = orm.BaseModel.__init__
+
+
+def __init__(self, pool, cr):
+    original__init__(self, pool, cr)
+    if self.pool.get('binary.field.installed'):
+        additionnal_field = {}
+        for field in self._columns:
+            if isinstance(self._columns[field], BinaryField):
+                additionnal_field.update({
+                    '%s_uid' % field:
+                        fields.char('%s UID' % self._columns[field].string),
+                    '%s_file_size' % field:
+                        fields.char('%s File Size' % self._columns[field].string),
+                    })
+
+            #Inject the store invalidation function for ImageResize
+            if isinstance(self._columns[field], ImageResizeField):
+                self._columns[field].store = {
+                    self._name: (
+                        lambda self, cr, uid, ids, c={}: ids,
+                        [self._columns[field].related_field],
+                        10),
+                }
+        self._columns.update(additionnal_field)
+
+
+orm.BaseModel.__init__ = __init__
+
+
+class IrAttachment(orm.Model):
+    _inherit = 'ir.attachment'
+
+    def _full_path(self, cr, uid, location, path):
+        # Hack for passing the field_key in the full path
+        # For now I prefer to use this hack and to reuse
+        # the ir.attachment code
+        # An alternative way will to copy/paste and 
+        # adapt the ir.attachment code
+        if isinstance(location, tuple):
+            base_location, field_key = location
+            path = os.path.join(field_key, path)
+        else:
+            base_location = location
+        return super(IrAttachment, self).\
+            _full_path(cr, uid, base_location, path)
+
+
+class BinaryFieldInstalled(orm.AbstractModel):
+    _name = 'binary.field.installed'

=== added directory 'binary_field_example'
=== added file 'binary_field_example/__init__.py'
--- binary_field_example/__init__.py	1970-01-01 00:00:00 +0000
+++ binary_field_example/__init__.py	2014-06-06 09:01:45 +0000
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+#   Module for OpenERP 
+#   Copyright (C) 2013 Akretion (http://www.akretion.com).
+#   @author Sébastien BEAU <sebastien.beau@xxxxxxxxxxxx>
+#
+#   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 res_company
+

=== added file 'binary_field_example/__openerp__.py'
--- binary_field_example/__openerp__.py	1970-01-01 00:00:00 +0000
+++ binary_field_example/__openerp__.py	2014-06-06 09:01:45 +0000
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+#   Module for OpenERP 
+#   Copyright (C) 2013 Akretion (http://www.akretion.com).
+#   @author Sébastien BEAU <sebastien.beau@xxxxxxxxxxxx>
+#
+#   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': 'binary field example',
+ 'version': '0.0.1',
+ 'author': 'Akretion',
+ 'website': 'www.akretion.com',
+ 'license': 'AGPL-3',
+ 'category': 'Generic Modules',
+ 'description': """Just an example
+ 
+ """,
+ 'depends': [
+     'binary_field',
+ ],
+ 'data': [
+     'res_company_view.xml',
+ ],
+ 'installable': True,
+ 'application': True,
+}
+
+
+
+

=== added file 'binary_field_example/res_company.py'
--- binary_field_example/res_company.py	1970-01-01 00:00:00 +0000
+++ binary_field_example/res_company.py	2014-06-06 09:01:45 +0000
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+#   Module for OpenERP 
+#   Copyright (C) 2013 Akretion (http://www.akretion.com).
+#   @author Sébastien BEAU <sebastien.beau@xxxxxxxxxxxx>
+#
+#   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 fields, orm
+
+
+class ResCompany(orm.Model):
+    _inherit = 'res.company'
+    
+    _columns = {
+        'binary_test': fields.BinaryField('Test Binary'),
+        'image_test': fields.ImageField('Test Image'),
+        'image_test_resize': fields.ImageResizeField(
+            related_field='image_test',
+            string='Test Image small',
+            height=64,
+            width=64,
+            ),
+    }

=== added file 'binary_field_example/res_company_view.xml'
--- binary_field_example/res_company_view.xml	1970-01-01 00:00:00 +0000
+++ binary_field_example/res_company_view.xml	2014-06-06 09:01:45 +0000
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+    <data>
+
+        <record id="view_res_company_form" model="ir.ui.view">
+            <field name="model">res.company</field>
+            <field name="inherit_id" ref="base.view_company_form"/>
+            <field name="arch" type="xml">
+                <field name="parent_id" position="after">
+                    <field name="binary_test"/>
+                    <field name="image_test" widget='image'/>
+                    <field name="image_test_resize" widget='image'/>
+                </field>
+            </field>
+        </record>
+
+    </data>
+</openerp>


Follow ups