misc: include image thumbnails in formdata view page (#20045)
This commit is contained in:
parent
b89e466a72
commit
61d37fa4b0
|
@ -1853,11 +1853,22 @@ def test_form_file_field_image_submit(pub):
|
|||
assert '<img alt="" src="tempfile?' in resp.body
|
||||
tempfile_id = resp.body[resp.body.index('tempfile?'):].split('&', 1)[0].split('=')[1]
|
||||
|
||||
resp = app.get('/test/tempfile?t=%s' % tempfile_id)
|
||||
assert resp.body == image_content
|
||||
resp_tempfile = app.get('/test/tempfile?t=%s' % tempfile_id)
|
||||
assert resp_tempfile.body == image_content
|
||||
|
||||
if Image: # check thumbnailing
|
||||
resp = app.get('/test/tempfile?t=%s&thumbnail=1' % tempfile_id)
|
||||
if Image:
|
||||
# check thumbnailing of image in validation page
|
||||
resp_thumbnail = app.get('/test/tempfile?t=%s&thumbnail=1' % tempfile_id)
|
||||
assert resp_thumbnail.content_type == 'image/png'
|
||||
|
||||
resp = resp.form.submit('submit').follow()
|
||||
assert '<img ' in resp.body
|
||||
assert 'download?f=0&thumbnail=1' in resp.body
|
||||
resp = resp.goto('download?f=0&thumbnail=1')
|
||||
assert '/thumbnail/' in resp.location
|
||||
resp = resp.follow()
|
||||
if Image:
|
||||
# check thumbnailing of image in submitted form
|
||||
assert resp.content_type == 'image/png'
|
||||
|
||||
# check a fake image is not sent back
|
||||
|
|
|
@ -803,9 +803,18 @@ class FileField(WidgetField):
|
|||
return upload
|
||||
raise ValueError('invalid data for file type (%r)' % value)
|
||||
|
||||
def get_view_value(self, value):
|
||||
return htmltext('<a download="%s" href="[download]?f=%s">%s</a>') % (
|
||||
value.base_filename, self.id, value)
|
||||
def get_view_short_value(self, value, max_len=30):
|
||||
return self.get_view_value(value, include_image_thumbnail=False)
|
||||
|
||||
def get_view_value(self, value, include_image_thumbnail=True):
|
||||
t = TemplateIO(html=True)
|
||||
t += htmltext('<div class="file-field">')
|
||||
t += htmltext('<a download="%s" href="[download]?f=%s">') % (value.base_filename, self.id)
|
||||
if value.content_type and value.content_type.startswith('image/'):
|
||||
t += htmltext('<img alt="" src="[download]?f=%s&thumbnail=1"/>') % self.id
|
||||
t += htmltext('<span>%s</span>') % value
|
||||
t += htmltext('</a></div>')
|
||||
return t.getvalue()
|
||||
|
||||
def get_csv_value(self, value, **kwargs):
|
||||
return [str(value) if value else '']
|
||||
|
|
|
@ -28,6 +28,7 @@ from wcs.workflows import EditableWorkflowStatusItem
|
|||
from django.template import RequestContext
|
||||
|
||||
from qommon import _
|
||||
from qommon import misc
|
||||
from qommon import template
|
||||
from qommon import get_logger
|
||||
from qommon.form import *
|
||||
|
@ -40,6 +41,7 @@ from qommon import errors
|
|||
class FileDirectory(Directory):
|
||||
_q_exports = []
|
||||
_lookup_methods = ['lookup_file_field']
|
||||
thumbnails = False
|
||||
|
||||
def __init__(self, formdata, reference):
|
||||
self.formdata = formdata
|
||||
|
@ -50,6 +52,9 @@ class FileDirectory(Directory):
|
|||
return self.formdata.data[self.reference]
|
||||
|
||||
def _q_lookup(self, component):
|
||||
if component == 'thumbnail':
|
||||
self.thumbnails = True
|
||||
return self
|
||||
upload = None
|
||||
for lookup_method_name in self._lookup_methods:
|
||||
lookup_method = getattr(self, lookup_method_name)
|
||||
|
@ -78,8 +83,17 @@ class FileDirectory(Directory):
|
|||
response.set_header(
|
||||
'content-disposition', 'attachment; filename="%s"' % file.base_filename)
|
||||
|
||||
return file.get_file_pointer().read()
|
||||
fp = file.get_file_pointer()
|
||||
if self.thumbnails and file.content_type.startswith('image/'):
|
||||
try:
|
||||
thumbnail = misc.get_thumbnail(fp)
|
||||
except misc.ThumbnailError:
|
||||
pass
|
||||
else:
|
||||
response.set_content_type('image/png')
|
||||
return thumbnail
|
||||
|
||||
return fp.read()
|
||||
|
||||
|
||||
class FilesDirectory(Directory):
|
||||
|
@ -557,10 +571,12 @@ class FormStatusPage(Directory):
|
|||
if not hasattr(file, 'content_type'):
|
||||
raise errors.TraversalError()
|
||||
|
||||
if hasattr(file, 'base_filename') and file.base_filename:
|
||||
return redirect('files/%s/%s' % (fn, file.base_filename))
|
||||
else:
|
||||
return redirect('files/%s/' % fn)
|
||||
file_url = 'files/%s/' % fn
|
||||
if get_request().form.get('thumbnail') == '1':
|
||||
file_url += 'thumbnail/'
|
||||
if getattr(file, 'base_filename'):
|
||||
file_url += file.base_filename
|
||||
return redirect(file_url)
|
||||
|
||||
def display_file_field(self, form_url, field, value):
|
||||
r = TemplateIO(html=True)
|
||||
|
|
|
@ -19,11 +19,6 @@ import time
|
|||
from StringIO import StringIO
|
||||
import urllib2
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
Image = None
|
||||
|
||||
try:
|
||||
import qrcode
|
||||
except ImportError:
|
||||
|
@ -1085,19 +1080,15 @@ class FormPage(Directory):
|
|||
response.set_charset(tempfile['charset'])
|
||||
|
||||
file_pointer = get_session().get_tempfile_content(t).get_file_pointer()
|
||||
if Image is not None and get_request().form.get('thumbnail') == '1':
|
||||
if get_request().form.get('thumbnail') == '1':
|
||||
try:
|
||||
image = Image.open(file_pointer)
|
||||
image.thumbnail((500, 300))
|
||||
image_thumb_fp = StringIO()
|
||||
image.save(image_thumb_fp, "PNG")
|
||||
except IOError:
|
||||
# too bad we couldn't load the image, return the whole file :/
|
||||
return file_pointer.read()
|
||||
response.set_content_type('image/png')
|
||||
return image_thumb_fp.getvalue()
|
||||
else:
|
||||
return file_pointer.read()
|
||||
thumbnail = misc.get_thumbnail(file_pointer)
|
||||
except misc.ThumbnailError:
|
||||
pass
|
||||
else:
|
||||
response.set_content_type('image/png')
|
||||
return thumbnail
|
||||
return file_pointer.read()
|
||||
|
||||
def validating(self, data):
|
||||
self.html_top(self.formdef.name)
|
||||
|
|
|
@ -31,6 +31,11 @@ import tempfile
|
|||
import unicodedata
|
||||
import hashlib
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
Image = None
|
||||
|
||||
from django.utils import datetime_safe
|
||||
|
||||
from quixote import get_publisher, get_response, get_request
|
||||
|
@ -45,6 +50,10 @@ from urllib2 import urlparse
|
|||
from cStringIO import StringIO
|
||||
|
||||
|
||||
class ThumbnailError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_abs_path(s):
|
||||
if not s:
|
||||
return s
|
||||
|
@ -530,3 +539,19 @@ def file_digest(content, chunk_size=100000):
|
|||
for chunk in iter(read_chunk, ''):
|
||||
digest.update(chunk)
|
||||
return digest.hexdigest()
|
||||
|
||||
def get_thumbnail(fp):
|
||||
if Image is None:
|
||||
raise ThumbnailError()
|
||||
|
||||
try:
|
||||
image = Image.open(fp)
|
||||
image.thumbnail((500, 300))
|
||||
image_thumb_fp = StringIO()
|
||||
image.save(image_thumb_fp, "PNG")
|
||||
except IOError:
|
||||
# failed to create thumbnail; restore file pointer state and raise
|
||||
# exception.
|
||||
fp.rewind()
|
||||
raise ThumbnailError()
|
||||
return image_thumb_fp.getvalue()
|
||||
|
|
|
@ -608,3 +608,9 @@ div.halfwidth input,
|
|||
div.fullwidth input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.file-field img {
|
||||
max-width: 100%;
|
||||
max-height: 25vh;
|
||||
display: block;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue