Added a view to retrieve profile photos, in order to support Meetecho's need for such, at /person/{email}/photo. The default is to supply images with 80px width. Image scaling is available using the same query argument as Gravatar: ?size=200 or ?s=200 for 200-pixel wide images.

- Legacy-Id: 18483
This commit is contained in:
Henrik Levkowetz 2020-09-10 21:41:01 +00:00
parent 60a1e0fe3d
commit 07be1f8516
3 changed files with 49 additions and 2 deletions

View file

@ -4,8 +4,10 @@
import datetime import datetime
from io import StringIO, BytesIO
from PIL import Image
from pyquery import PyQuery from pyquery import PyQuery
from io import StringIO
from django.http import HttpRequest from django.http import HttpRequest
from django.urls import reverse as urlreverse from django.urls import reverse as urlreverse
@ -71,6 +73,25 @@ class PersonTests(TestCase):
r = self.client.get(photo_url) r = self.client.get(photo_url)
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
def test_person_photo(self):
person = PersonFactory(with_bio=True)
self.assertTrue(person.photo is not None)
self.assertTrue(person.photo.name is not None)
url = urlreverse("ietf.person.views.photo", kwargs={ "email_or_name": person.email()})
r = self.client.get(url)
self.assertEqual(r['Content-Type'], 'image/jpg')
self.assertEqual(r.status_code, 200)
img = Image.open(BytesIO(r.content))
self.assertEqual(img.width, 80)
r = self.client.get(url+'?size=200')
self.assertEqual(r['Content-Type'], 'image/jpg')
self.assertEqual(r.status_code, 200)
img = Image.open(BytesIO(r.content))
self.assertEqual(img.width, 200)
def test_name_methods(self): def test_name_methods(self):
person = PersonFactory(name="Dr. Jens F. Möller", ) person = PersonFactory(name="Dr. Jens F. Möller", )

View file

@ -6,4 +6,5 @@ urlpatterns = [
url(r'^search/(?P<model_name>(person|email))/$', views.ajax_select2_search), url(r'^search/(?P<model_name>(person|email))/$', views.ajax_select2_search),
url(r'^(?P<personid>[a-z0-9]+).json$', ajax.person_json), url(r'^(?P<personid>[a-z0-9]+).json$', ajax.person_json),
url(r'^(?P<email_or_name>[^/]+)$', views.profile), url(r'^(?P<email_or_name>[^/]+)$', views.profile),
url(r'^(?P<email_or_name>[^/]+)/photo/?$', views.photo),
] ]

View file

@ -3,7 +3,8 @@
import datetime import datetime
from io import StringIO from io import StringIO, BytesIO
from PIL import Image
from django.contrib import messages from django.contrib import messages
from django.db.models import Q from django.db.models import Q
@ -78,6 +79,30 @@ def profile(request, email_or_name):
return render(request, 'person/profile.html', {'persons': persons, 'today':datetime.date.today()}) return render(request, 'person/profile.html', {'persons': persons, 'today':datetime.date.today()})
def photo(request, email_or_name):
if '@' in email_or_name:
persons = [ get_object_or_404(Email, address=email_or_name).person, ]
else:
aliases = Alias.objects.filter(name=email_or_name)
persons = list(set([ a.person for a in aliases ]))
if not persons:
raise Http404("No such person")
if len(persons) > 1:
return HttpResponse(r"\r\n".join([p.email() for p in persons]), status=300)
person = persons[0]
if not person.photo:
raise Http404("No photo found")
size = request.GET.get('s') or request.GET.get('size', '80')
if not size.isdigit():
return HttpResponse("Size must be integer", status=400)
size = int(size)
img = Image.open(person.photo)
img = img.resize((size, img.height*size//img.width))
bytes = BytesIO()
img.save(bytes, format='JPEG')
return HttpResponse(bytes.getvalue(), content_type='image/jpg')
@role_required("Secretariat") @role_required("Secretariat")
def merge(request): def merge(request):
form = MergeForm() form = MergeForm()