123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- 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
|