summaryrefslogtreecommitdiff
path: root/addons/web_editor/models/ir_attachment.py
diff options
context:
space:
mode:
authorChristophe Matthieu <chm@odoo.com>2015-07-07 16:02:53 +0200
committerChristophe Matthieu <chm@odoo.com>2015-07-10 17:00:11 +0200
commit8c559044a5e1be111dcb577ad7e5ab462c1002a0 (patch)
treeba1602e15b2bca38babd6cca63a41da1d05b4321 /addons/web_editor/models/ir_attachment.py
parenta616c57c609da0e5e56835dcb45e1c05590d25b8 (diff)
[IMP] web_editor: split website into web_editor (to use editor in backend for html field) and website
Diffstat (limited to 'addons/web_editor/models/ir_attachment.py')
-rw-r--r--addons/web_editor/models/ir_attachment.py149
1 files changed, 149 insertions, 0 deletions
diff --git a/addons/web_editor/models/ir_attachment.py b/addons/web_editor/models/ir_attachment.py
new file mode 100644
index 00000000000..3068807b2ab
--- /dev/null
+++ b/addons/web_editor/models/ir_attachment.py
@@ -0,0 +1,149 @@
+# -*- coding: utf-8 -*-
+import openerp
+from openerp.osv import osv, fields
+
+import contextlib
+from sys import maxint
+from openerp.addons.web.http import request
+import datetime
+import hashlib
+import time
+import os
+
+from openerp.tools import html_escape as escape, ustr, image_resize_and_sharpen, image_save_for_web
+from PIL import Image
+import cStringIO
+
+import logging
+logger = logging.getLogger(__name__)
+
+
+class ir_attachment(osv.osv):
+
+ _inherit = "ir.attachment"
+
+ def _local_url_get(self, cr, uid, ids, name, arg, context=None):
+ result = {}
+ for attach in self.browse(cr, uid, ids, context=context):
+ if attach.url:
+ result[attach.id] = attach.url
+ else:
+ result[attach.id] = self.image_url(cr, uid, attach, 'datas')
+ return result
+
+ _columns = {
+ 'local_url': fields.function(_local_url_get, string="Attachment URL", type='char'),
+ }
+
+ def _image_placeholder(self, response):
+ # file_open may return a StringIO. StringIO can be closed but are
+ # not context managers in Python 2 though that is fixed in 3
+ with contextlib.closing(openerp.tools.misc.file_open(
+ os.path.join('web', 'static', 'src', 'img', 'placeholder.png'),
+ mode='rb')) as f:
+ response.data = f.read()
+ return response.make_conditional(request.httprequest)
+
+ def _image(self, cr, uid, model, id_or_ids, field, response, max_width=maxint, max_height=maxint, cache=None, context=None):
+ """ Fetches the requested field and ensures it does not go above
+ (max_width, max_height), resizing it if necessary.
+
+ Resizing is bypassed if the object provides a $field_big, which will
+ be interpreted as a pre-resized version of the base field.
+
+ If the record is not found or does not have the requested field,
+ returns a placeholder image via :meth:`~._image_placeholder`.
+
+ Sets and checks conditional response parameters:
+ * :mailheader:`ETag` is always set (and checked)
+ * :mailheader:`Last-Modified is set iif the record has a concurrency
+ field (``__last_update``)
+
+ The requested field is assumed to be base64-encoded image data in
+ all cases.
+ """
+ Model = self.pool[model]
+ ids = isinstance(id_or_ids, (list, tuple)) and id_or_ids or [int(id_or_ids)]
+ ids = Model.search(cr, uid, [('id', 'in', ids)], context=context)
+
+ if not ids:
+ return self._image_placeholder(response)
+
+ concurrency = '__last_update'
+ [record] = Model.read(cr, openerp.SUPERUSER_ID, ids, [concurrency, field], context=context)
+
+ if concurrency in record:
+ server_format = openerp.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT
+ try:
+ response.last_modified = datetime.datetime.strptime(
+ record[concurrency], server_format + '.%f')
+ except ValueError:
+ # just in case we have a timestamp without microseconds
+ response.last_modified = datetime.datetime.strptime(
+ record[concurrency], server_format)
+
+ # Field does not exist on model or field set to False
+ if not record.get(field):
+ # FIXME: maybe a field which does not exist should be a 404?
+ return self._image_placeholder(response)
+
+ response.set_etag(hashlib.sha1(record[field]).hexdigest())
+ response.make_conditional(request.httprequest)
+
+ if cache:
+ response.cache_control.max_age = cache
+ response.expires = int(time.time() + cache)
+
+ # conditional request match
+ if response.status_code == 304:
+ return response
+
+ if model == 'ir.attachment' and field == 'url' and field in record:
+ path = record[field].strip('/')
+
+ # Check that we serve a file from within the module
+ if os.path.normpath(path).startswith('..'):
+ return self._image_placeholder(response)
+
+ # Check that the file actually exists
+ path = path.split('/')
+ resource = openerp.modules.get_module_resource(*path)
+ if not resource:
+ return self._image_placeholder(response)
+
+ data = open(resource, 'rb').read()
+ else:
+ data = record[field].decode('base64')
+ image = Image.open(cStringIO.StringIO(data))
+ response.mimetype = Image.MIME[image.format]
+
+ filename = '%s_%s.%s' % (model.replace('.', '_'), ids[0], str(image.format).lower())
+ response.headers['Content-Disposition'] = 'inline; filename="%s"' % filename
+
+ if (not max_width) and (not max_height):
+ response.data = data
+ return response
+
+ w, h = image.size
+ max_w = int(max_width) if max_width else maxint
+ max_h = int(max_height) if max_height else maxint
+
+ if w < max_w and h < max_h:
+ response.data = data
+ else:
+ size = (max_w, max_h)
+ img = image_resize_and_sharpen(image, size, preserve_aspect_ratio=True)
+ image_save_for_web(img, response.stream, format=image.format)
+ # invalidate content-length computed by make_conditional as
+ # writing to response.stream does not do it (as of werkzeug 0.9.3)
+ del response.headers['Content-Length']
+
+ return response
+
+ def image_url(self, cr, uid, record, field, size=None, context=None):
+ """Returns a local url that points to the image field of a given browse record."""
+ model = record._name
+ sudo_record = record.sudo()
+ id = '%s_%s' % (record.id, hashlib.sha1(sudo_record.write_date or sudo_record.create_date or '').hexdigest()[0:7])
+ size = '' if size is None else '/%s' % size
+ return '/web_editor/image/%s/%s/%s%s' % (model, id, field, size)