Skip to content

Commit 07be1f8

Browse files
committed
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
1 parent 60a1e0f commit 07be1f8

3 files changed

Lines changed: 49 additions & 2 deletions

File tree

ietf/person/tests.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
import datetime
66

7+
from io import StringIO, BytesIO
8+
from PIL import Image
79
from pyquery import PyQuery
8-
from io import StringIO
10+
911

1012
from django.http import HttpRequest
1113
from django.urls import reverse as urlreverse
@@ -71,6 +73,25 @@ def test_person_profile(self):
7173
r = self.client.get(photo_url)
7274
self.assertEqual(r.status_code, 200)
7375

76+
def test_person_photo(self):
77+
person = PersonFactory(with_bio=True)
78+
79+
self.assertTrue(person.photo is not None)
80+
self.assertTrue(person.photo.name is not None)
81+
82+
url = urlreverse("ietf.person.views.photo", kwargs={ "email_or_name": person.email()})
83+
r = self.client.get(url)
84+
self.assertEqual(r['Content-Type'], 'image/jpg')
85+
self.assertEqual(r.status_code, 200)
86+
img = Image.open(BytesIO(r.content))
87+
self.assertEqual(img.width, 80)
88+
89+
r = self.client.get(url+'?size=200')
90+
self.assertEqual(r['Content-Type'], 'image/jpg')
91+
self.assertEqual(r.status_code, 200)
92+
img = Image.open(BytesIO(r.content))
93+
self.assertEqual(img.width, 200)
94+
7495
def test_name_methods(self):
7596
person = PersonFactory(name="Dr. Jens F. Möller", )
7697

ietf/person/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@
66
url(r'^search/(?P<model_name>(person|email))/$', views.ajax_select2_search),
77
url(r'^(?P<personid>[a-z0-9]+).json$', ajax.person_json),
88
url(r'^(?P<email_or_name>[^/]+)$', views.profile),
9+
url(r'^(?P<email_or_name>[^/]+)/photo/?$', views.photo),
910
]

ietf/person/views.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33

44

55
import datetime
6-
from io import StringIO
6+
from io import StringIO, BytesIO
7+
from PIL import Image
78

89
from django.contrib import messages
910
from django.db.models import Q
@@ -78,6 +79,30 @@ def profile(request, email_or_name):
7879
return render(request, 'person/profile.html', {'persons': persons, 'today':datetime.date.today()})
7980

8081

82+
def photo(request, email_or_name):
83+
if '@' in email_or_name:
84+
persons = [ get_object_or_404(Email, address=email_or_name).person, ]
85+
else:
86+
aliases = Alias.objects.filter(name=email_or_name)
87+
persons = list(set([ a.person for a in aliases ]))
88+
if not persons:
89+
raise Http404("No such person")
90+
if len(persons) > 1:
91+
return HttpResponse(r"\r\n".join([p.email() for p in persons]), status=300)
92+
person = persons[0]
93+
if not person.photo:
94+
raise Http404("No photo found")
95+
size = request.GET.get('s') or request.GET.get('size', '80')
96+
if not size.isdigit():
97+
return HttpResponse("Size must be integer", status=400)
98+
size = int(size)
99+
img = Image.open(person.photo)
100+
img = img.resize((size, img.height*size//img.width))
101+
bytes = BytesIO()
102+
img.save(bytes, format='JPEG')
103+
return HttpResponse(bytes.getvalue(), content_type='image/jpg')
104+
105+
81106
@role_required("Secretariat")
82107
def merge(request):
83108
form = MergeForm()

0 commit comments

Comments
 (0)