133 lines
5.1 KiB
Python
133 lines
5.1 KiB
Python
import os
|
|
import time
|
|
import hashlib
|
|
import datetime
|
|
import cStringIO
|
|
from PIL import Image
|
|
from sys import maxint
|
|
|
|
import openerp
|
|
from openerp.osv import osv, orm
|
|
from openerp.addons.web.http import request
|
|
from openerp.tools import image_resize_and_sharpen, image_save_for_web
|
|
|
|
|
|
class website(osv.osv):
|
|
_inherit = "website"
|
|
|
|
def _image(self, cr, uid, model, id, 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]
|
|
id = int(id)
|
|
|
|
ids = Model.search(cr, uid,
|
|
[('id', '=', id)], context=context)
|
|
if not ids and 'website_published' in Model._fields:
|
|
ids = Model.search(cr, openerp.SUPERUSER_ID,
|
|
[('id', '=', id), ('website_published', '=', True)], context=context)
|
|
if not ids:
|
|
return self._image_placeholder(response)
|
|
|
|
concurrency = '__last_update'
|
|
[record] = Model.read(cr, openerp.SUPERUSER_ID, [id],
|
|
[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':
|
|
path = record.get(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[0], *path[1:])
|
|
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('.', '_'), id, 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
|
|
|
|
class ir_http(orm.AbstractModel):
|
|
_inherit = 'ir.http'
|
|
|
|
def _serve_attachment(self):
|
|
response = super(ir_http, self)._serve_attachment()
|
|
if response and response.mimetype == 'application/octet-stream':
|
|
# Try to set mimetype via attachment mimetype field
|
|
attach = self.pool['ir.attachment'].search_read(request.cr, openerp.SUPERUSER_ID,
|
|
[('type', '=', 'binary'), ('url', '=', request.httprequest.path)],
|
|
['mimetype'], context=request.context)
|
|
if attach and attach[0].get('mimetype'):
|
|
response.mimetype = attach[0].get('mimetype')
|
|
return response
|