[IMP] website: refactor website_image controller (and placeholder), move to model to make it reusable
It is "almost" reusable because it still depends on the global `request` variable, this could be solved by making it an explicit parameter.
This commit is contained in:
parent
8f2bbf73ae
commit
6130ed3ce0
|
@ -1,18 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import cStringIO
|
||||
import contextlib
|
||||
import hashlib
|
||||
import json
|
||||
import logging
|
||||
import math
|
||||
import os
|
||||
import datetime
|
||||
import re
|
||||
|
||||
from sys import maxint
|
||||
|
||||
import werkzeug
|
||||
import werkzeug.exceptions
|
||||
import werkzeug.utils
|
||||
import werkzeug.wrappers
|
||||
from PIL import Image
|
||||
|
@ -336,13 +330,7 @@ class Website(openerp.addons.web.controllers.main.Home):
|
|||
return request.website.kanban_col(**post)
|
||||
|
||||
def 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)
|
||||
return request.registry['website']._image_placeholder(response)
|
||||
|
||||
@http.route([
|
||||
'/website/image',
|
||||
|
@ -366,74 +354,10 @@ class Website(openerp.addons.web.controllers.main.Home):
|
|||
The requested field is assumed to be base64-encoded image data in
|
||||
all cases.
|
||||
"""
|
||||
Model = request.registry[model]
|
||||
|
||||
response = werkzeug.wrappers.Response()
|
||||
return request.registry['website']._image(
|
||||
request.cr, request.uid, model, id, field, response)
|
||||
|
||||
id = int(id)
|
||||
|
||||
ids = Model.search(request.cr, request.uid,
|
||||
[('id', '=', id)], context=request.context)
|
||||
if not ids and 'website_published' in Model._all_columns:
|
||||
ids = Model.search(request.cr, openerp.SUPERUSER_ID,
|
||||
[('id', '=', id), ('website_published', '=', True)], context=request.context)
|
||||
|
||||
if not ids:
|
||||
return self.placeholder(response)
|
||||
|
||||
presized = '%s_big' % field
|
||||
concurrency = '__last_update'
|
||||
[record] = Model.read(request.cr, openerp.SUPERUSER_ID, [id],
|
||||
[concurrency, field, presized],
|
||||
context=request.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.placeholder(response)
|
||||
|
||||
response.set_etag(hashlib.sha1(record[field]).hexdigest())
|
||||
response.make_conditional(request.httprequest)
|
||||
|
||||
# conditional request match
|
||||
if response.status_code == 304:
|
||||
return response
|
||||
|
||||
data = (record.get(presized) or record[field]).decode('base64')
|
||||
|
||||
image = Image.open(cStringIO.StringIO(data))
|
||||
response.mimetype = Image.MIME[image.format]
|
||||
|
||||
# record provides a pre-resized version of the base field, use that
|
||||
# directly
|
||||
if record.get(presized):
|
||||
response.data = data
|
||||
return response
|
||||
|
||||
fit = int(max_width), int(max_height)
|
||||
w, h = image.size
|
||||
max_w, max_h = fit
|
||||
|
||||
if w < max_w and h < max_h:
|
||||
response.data = data
|
||||
else:
|
||||
image.thumbnail(fit, Image.ANTIALIAS)
|
||||
image.save(response.stream, 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
|
||||
|
||||
#------------------------------------------------------
|
||||
# Server actions
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import cStringIO
|
||||
import contextlib
|
||||
import datetime
|
||||
import hashlib
|
||||
import inspect
|
||||
import itertools
|
||||
import logging
|
||||
import math
|
||||
import mimetypes
|
||||
import os
|
||||
import re
|
||||
import urlparse
|
||||
|
||||
from PIL import Image
|
||||
from sys import maxint
|
||||
|
||||
import werkzeug
|
||||
import werkzeug.exceptions
|
||||
import werkzeug.utils
|
||||
|
@ -472,6 +479,99 @@ class website(osv.osv):
|
|||
html += request.website._render(template, {'object_id': object_id})
|
||||
return html
|
||||
|
||||
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, field, response, max_width=maxint, max_height=maxint, 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._all_columns:
|
||||
ids = Model.search(cr, openerp.SUPERUSER_ID,
|
||||
[('id', '=', id), ('website_published', '=', True)], context=context)
|
||||
if not ids:
|
||||
return self._image_placeholder(response)
|
||||
|
||||
presized = '%s_big' % field
|
||||
concurrency = '__last_update'
|
||||
[record] = Model.read(cr, openerp.SUPERUSER_ID, [id],
|
||||
[concurrency, field, presized],
|
||||
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)
|
||||
|
||||
# conditional request match
|
||||
if response.status_code == 304:
|
||||
return response
|
||||
|
||||
data = (record.get(presized) or record[field]).decode('base64')
|
||||
|
||||
image = Image.open(cStringIO.StringIO(data))
|
||||
response.mimetype = Image.MIME[image.format]
|
||||
|
||||
# record provides a pre-resized version of the base field, use that
|
||||
# directly
|
||||
if record.get(presized):
|
||||
response.data = data
|
||||
return response
|
||||
|
||||
fit = int(max_width), int(max_height)
|
||||
w, h = image.size
|
||||
max_w, max_h = fit
|
||||
|
||||
if w < max_w and h < max_h:
|
||||
response.data = data
|
||||
else:
|
||||
image.thumbnail(fit, Image.ANTIALIAS)
|
||||
image.save(response.stream, 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 website_menu(osv.osv):
|
||||
_name = "website.menu"
|
||||
_description = "Website Menu"
|
||||
|
|
Loading…
Reference in New Issue