Skip to content

Commit 3d69b2c

Browse files
rpcrossrjsparks
andauthored
feat: add API for related emails (#8671)
* feat: add api for related emails. Fixes #8275 * fix: switch from querystring parameter to URL parameter * fix: exclude null character in URL regex --------- Co-authored-by: Robert Sparks <[email protected]>
1 parent be06d7c commit 3d69b2c

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

ietf/api/tests.py

+33
Original file line numberDiff line numberDiff line change
@@ -1164,6 +1164,39 @@ def test_active_email_list(self):
11641164
self.assertCountEqual(result.keys(), ["addresses"])
11651165
self.assertCountEqual(result["addresses"], Email.objects.filter(active=True).values_list("address", flat=True))
11661166

1167+
@override_settings(APP_API_TOKENS={"ietf.api.views.related_email_list": ["valid-token"]})
1168+
def test_related_email_list(self):
1169+
joe = EmailFactory(address='[email protected]')
1170+
EmailFactory(address='[email protected]', person=joe.person)
1171+
EmailFactory(address='jò[email protected]', person=joe.person)
1172+
url = urlreverse("ietf.api.views.related_email_list", kwargs={'email': '[email protected]'})
1173+
# no api key
1174+
r = self.client.get(url, headers={})
1175+
self.assertEqual(r.status_code, 403)
1176+
# invalid api key
1177+
r = self.client.get(url, headers={"X-Api-Key": "not-the-valid-token"})
1178+
self.assertEqual(r.status_code, 403)
1179+
# wrong method
1180+
r = self.client.post(url, headers={"X-Api-Key": "valid-token"})
1181+
self.assertEqual(r.status_code, 405)
1182+
# valid
1183+
r = self.client.get(url, headers={"X-Api-Key": "valid-token"})
1184+
self.assertEqual(r.status_code, 200)
1185+
self.assertEqual(r.headers["Content-Type"], "application/json")
1186+
result = json.loads(r.content)
1187+
self.assertCountEqual(result.keys(), ["addresses"])
1188+
self.assertCountEqual(result["addresses"], joe.person.email_set.exclude(address='[email protected]').values_list("address", flat=True))
1189+
# non-ascii
1190+
non_ascii_url = urlreverse("ietf.api.views.related_email_list", kwargs={'email': 'jò[email protected]'})
1191+
r = self.client.get(non_ascii_url, headers={"X-Api-Key": "valid-token"})
1192+
self.assertEqual(r.status_code, 200)
1193+
result = json.loads(r.content)
1194+
self.assertTrue('[email protected]' in result["addresses"])
1195+
# email not found
1196+
not_found_url = urlreverse("ietf.api.views.related_email_list", kwargs={'email': '[email protected]'})
1197+
r = self.client.get(not_found_url, headers={"X-Api-Key": "valid-token"})
1198+
self.assertEqual(r.status_code, 404)
1199+
11671200
@override_settings(APP_API_TOKENS={"ietf.api.views.role_holder_addresses": ["valid-token"]})
11681201
def test_role_holder_addresses(self):
11691202
url = urlreverse("ietf.api.views.role_holder_addresses")

ietf/api/urls.py

+2
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@
7373
url(r'^openid/', include('oidc_provider.urls', namespace='oidc_provider')),
7474
# Email alias listing
7575
url(r'^person/email/$', api_views.active_email_list),
76+
# Related Email listing
77+
url(r'^person/email/(?P<email>[^/\x00]+)/related/$', api_views.related_email_list),
7678
# Draft submission API
7779
url(r'^submit/?$', submit_views.api_submit_tombstone),
7880
# Draft upload API

ietf/api/views.py

+25
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,31 @@ def active_email_list(request):
691691
return HttpResponse(status=405)
692692

693693

694+
@requires_api_token
695+
@csrf_exempt
696+
def related_email_list(request, email):
697+
"""Given an email address, returns all other email addresses known
698+
to Datatracker, via Person object
699+
"""
700+
def _http_err(code, text):
701+
return HttpResponse(text, status=code, content_type="text/plain")
702+
703+
if request.method == "GET":
704+
try:
705+
email_obj = Email.objects.get(address=email)
706+
except Email.DoesNotExist:
707+
return _http_err(404, "Email not found")
708+
person = email_obj.person
709+
if not person:
710+
return JsonResponse({"addresses": []})
711+
return JsonResponse(
712+
{
713+
"addresses": list(person.email_set.exclude(address=email).values_list("address", flat=True)),
714+
}
715+
)
716+
return HttpResponse(status=405)
717+
718+
694719
@requires_api_token
695720
def role_holder_addresses(request):
696721
if request.method == "GET":

0 commit comments

Comments
 (0)