Return resized img, if/as requested and now also return default image (not yet as specified by the url parameters!

This commit is contained in:
Oliver Falk
2018-07-09 15:21:24 +02:00
parent 1bf2eb1e43
commit 14ee40f52c
3 changed files with 69 additions and 33 deletions

View File

@@ -1059,7 +1059,7 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
self.user.photo_set.first(), self.user.photo_set.first(),
'set_photo did not work!?') 'set_photo did not work!?')
def test_avatar_url_mail(self, do_upload_and_confirm=True): def test_avatar_url_mail(self, do_upload_and_confirm=True, size=(80, 80)):
''' '''
Test fetching avatar via mail Test fetching avatar via mail
''' '''
@@ -1068,18 +1068,21 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
self.test_confirm_email() self.test_confirm_email()
urlobj = urlsplit( urlobj = urlsplit(
libravatar_url( libravatar_url(
email=self.user.confirmedemail_set.first().email) email=self.user.confirmedemail_set.first().email,
size=size[0],
)
) )
url = urlobj.path url = '%s?%s' % (urlobj.path, urlobj.query)
response = self.client.get(url, follow=True) response = self.client.get(url, follow=True)
self.assertEqual( self.assertEqual(
response.status_code, response.status_code,
200, 200,
'unable to fetch avatar?') 'unable to fetch avatar?')
photodata = Image.open(BytesIO(response.content))
self.assertEqual( self.assertEqual(
response.content, photodata.size,
self.user.photo_set.first().data, size,
'Why is this not the same data?') 'Why is this not the correct size?')
def test_avatar_url_openid(self): def test_avatar_url_openid(self):
''' '''
@@ -1088,18 +1091,21 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
self.test_assign_photo_to_openid() self.test_assign_photo_to_openid()
urlobj = urlsplit( urlobj = urlsplit(
libravatar_url( libravatar_url(
openid=self.user.confirmedopenid_set.first().openid) openid=self.user.confirmedopenid_set.first().openid,
size=80,
)
) )
url = urlobj.path url = '%s?%s' % (urlobj.path, urlobj.query)
response = self.client.get(url, follow=True) response = self.client.get(url, follow=True)
self.assertEqual( self.assertEqual(
response.status_code, response.status_code,
200, 200,
'unable to fetch avatar?') 'unable to fetch avatar?')
photodata = Image.open(BytesIO(response.content))
self.assertEqual( self.assertEqual(
response.content, photodata.size,
self.user.photo_set.first().data, (80, 80),
'Why is this not the same data?') 'Why is this not the correct size?')
def test_avatar_url_inexisting_mail_digest(self): # pylint: disable=invalid-name def test_avatar_url_inexisting_mail_digest(self): # pylint: disable=invalid-name
''' '''
@@ -1109,14 +1115,20 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
self.test_confirm_email() self.test_confirm_email()
urlobj = urlsplit( urlobj = urlsplit(
libravatar_url( libravatar_url(
email=self.user.confirmedemail_set.first().email) email=self.user.confirmedemail_set.first().email,
size=80,
)
) )
# Simply delete it, then it digest is 'correct', but # Simply delete it, then it digest is 'correct', but
# the hash is no longer there # the hash is no longer there
self.user.confirmedemail_set.first().delete() self.user.confirmedemail_set.first().delete()
url = urlobj.path url = '%s?%s' % (urlobj.path, urlobj.query)
self.assertRaises(Exception, lambda: response = self.client.get(url, follow=True)
self.client.get(url, follow=True)) self.assertEqual(
response['Content-Type'],
'image/png',
'Content type wrong!?')
# Eventually one should check if the data is the same
def test_crop_photo(self): def test_crop_photo(self):
''' '''
@@ -1135,6 +1147,6 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
response.status_code, response.status_code,
200, 200,
'unable to crop?') 'unable to crop?')
self.test_avatar_url_mail(do_upload_and_confirm=False) self.test_avatar_url_mail(do_upload_and_confirm=False, size=(20, 20))
img = Image.open(BytesIO(self.user.photo_set.first().data)) img = Image.open(BytesIO(self.user.photo_set.first().data))
self.assertEqual(img.size, (20, 20), 'cropped to 20x20, but resulting image isn\'t 20x20!?') self.assertEqual(img.size, (20, 20), 'cropped to 20x20, but resulting image isn\'t 20x20!?')

View File

@@ -531,7 +531,7 @@ class CropPhotoView(TemplateView):
model = Photo model = Photo
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
photo = self.model.objects.get(pk=kwargs['pk'], user=request.user) photo = self.model.objects.get(pk=kwargs['pk'], user=request.user) # pylint: disable=no-member
email = request.GET.get('email') email = request.GET.get('email')
openid = request.GET.get('openid') openid = request.GET.get('openid')
return render(self.request, self.template_name, { return render(self.request, self.template_name, {
@@ -541,7 +541,7 @@ class CropPhotoView(TemplateView):
}) })
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
photo = self.model.objects.get(pk=kwargs['pk'], user=request.user) photo = self.model.objects.get(pk=kwargs['pk'], user=request.user) # pylint: disable=no-member
dimensions = { dimensions = {
'x': int(request.POST['x']), 'x': int(request.POST['x']),
'y': int(request.POST['y']), 'y': int(request.POST['y']),

View File

@@ -1,29 +1,42 @@
''' '''
views under / views under /
''' '''
import io from io import BytesIO
from os import path
from PIL import Image
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.http import HttpResponse from django.http import HttpResponse
from . ivataraccount.models import ConfirmedEmail, ConfirmedOpenId
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from ivatar.settings import AVATAR_MAX_SIZE, JPEG_QUALITY
from . ivataraccount.models import ConfirmedEmail, ConfirmedOpenId
from . ivataraccount.models import pil_format
class AvatarImageView(TemplateView): class AvatarImageView(TemplateView):
''' '''
View to return (binary) image, based for OpenID/Email (both by digest) View to return (binary) image, based on OpenID/Email (both by digest)
''' '''
# TODO: Do cache resize images!! Memcached?
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
''' '''
Override get from parent class Override get from parent class
''' '''
model = ConfirmedEmail model = ConfirmedEmail
size = 80
imgformat = 'png'
obj = None
if 's' in request.GET:
size = request.GET['s']
size = int(size)
if size > int(AVATAR_MAX_SIZE):
size = int(AVATAR_MAX_SIZE)
if len(kwargs['digest']) == 32: if len(kwargs['digest']) == 32:
# Fetch by digest from mail # Fetch by digest from mail
pass pass
elif len(kwargs['digest']) == 64: elif len(kwargs['digest']) == 64:
if ConfirmedOpenId.objects.filter( if ConfirmedOpenId.objects.filter( # pylint: disable=no-member
digest=kwargs['digest']).count(): # pylint: disable=no-member digest=kwargs['digest']).count():
# Fetch by digest from OpenID # Fetch by digest from OpenID
model = ConfirmedOpenId model = ConfirmedOpenId
else: # pragma: no cover else: # pragma: no cover
@@ -36,15 +49,26 @@ class AvatarImageView(TemplateView):
try: try:
obj = model.objects.get(digest_sha256=kwargs['digest']) obj = model.objects.get(digest_sha256=kwargs['digest'])
except ObjectDoesNotExist: except ObjectDoesNotExist:
# TODO: Use default!? pass
raise Exception('Mail/openid ("%s") does not exist"' %
kwargs['digest']) if not obj or not obj.photo:
if not obj.photo: static_img = path.join('static', 'img', 'mm', '%s%s' % (str(size), '.png'))
# That is hacky, but achieves what we want :-) if path.isfile(static_img):
attr = getattr(obj, 'email', obj.openid) photodata = Image.open(static_img)
# TODO: Use default!? else:
raise Exception('No photo assigned to "%s"' % attr) # TODO: Resize it!?
static_img = path.join('static', 'img', 'mm', '512.png')
else:
imgformat = obj.photo.format
photodata = Image.open(BytesIO(obj.photo.data))
photodata.thumbnail((size, size), Image.ANTIALIAS)
data = BytesIO()
photodata.save(data, pil_format(imgformat), quality=JPEG_QUALITY)
data.seek(0)
return HttpResponse( return HttpResponse(
io.BytesIO(obj.photo.data), data,
content_type='image/%s' % obj.photo.format) content_type='image/%s' % imgformat)
# One eventually also wants to check if the DATA is correct,
# not only the size