Skip to content

Commit 8f2ba33

Browse files
committed
Merged in [15263], [15264], [15265], [15287] from rcross@amsl.com:
Added new custom API endpoints for export of person data, restricted to secretariat use. Added a test for the new custom API. - Legacy-Id: 15543 Note: SVN reference [15263] has been migrated to Git commit 8e7e0fa Note: SVN reference [15264] has been migrated to Git commit e654963 Note: SVN reference [15265] has been migrated to Git commit 7c0e97f Note: SVN reference [15287] has been migrated to Git commit 7431bdf
1 parent a74055c commit 8f2ba33

5 files changed

Lines changed: 64 additions & 5 deletions

File tree

ietf/api/tests.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,9 @@ def test_api_set_session_video_url(self):
132132
event = doc.latest_event()
133133
self.assertEqual(event.by, recman)
134134

135-
136135
def test_person_export(self):
137136
person = PersonFactory()
138-
url = urlreverse('ietf.api.views.PersonExportView')
137+
url = urlreverse('ietf.api.views.PersonalInformationExportView')
139138
login_testing_unauthorized(self, person.user.username, url)
140139
r = self.client.get(url)
141140
jsondata = r.json()
@@ -144,6 +143,41 @@ def test_person_export(self):
144143
self.assertEqual(data['ascii'], person.ascii)
145144
self.assertEqual(data['user']['email'], person.user.email)
146145

146+
def test_api_v2_person_export_view(self):
147+
url = urlreverse('ietf.api.views.ApiV2PersonExportView')
148+
secretariat_role = RoleFactory(group__acronym='secretariat', name_id='secr')
149+
secretariat = secretariat_role.person
150+
apikey = PersonalApiKey.objects.create(endpoint=url, person=secretariat)
151+
152+
# error cases
153+
r = self.client.post(url, {})
154+
self.assertContains(r, "Missing apikey parameter", status_code=400)
155+
156+
badrole = RoleFactory(group__type_id='ietf', name_id='ad')
157+
badapikey = PersonalApiKey.objects.create(endpoint=url, person=badrole.person)
158+
badrole.person.user.last_login = timezone.now()
159+
badrole.person.user.save()
160+
r = self.client.post(url, {'apikey': badapikey.hash()})
161+
self.assertContains(r, "Restricted to role Secretariat", status_code=403)
162+
163+
r = self.client.post(url, {'apikey': apikey.hash()})
164+
self.assertContains(r, "Too long since last regular login", status_code=400)
165+
secretariat.user.last_login = timezone.now()
166+
secretariat.user.save()
167+
168+
r = self.client.post(url, {'apikey': apikey.hash()})
169+
self.assertContains(r, "No filters provided", status_code=400)
170+
171+
# working case
172+
r = self.client.post(url, {'apikey': apikey.hash(), 'email': secretariat.email().address, '_expand': 'user'})
173+
self.assertEqual(r.status_code, 200)
174+
jsondata = r.json()
175+
data = jsondata['person.person'][str(secretariat.id)]
176+
self.assertEqual(data['name'], secretariat.name)
177+
self.assertEqual(data['ascii'], secretariat.ascii)
178+
self.assertEqual(data['user']['email'], secretariat.user.email)
179+
180+
147181
class TastypieApiTestCase(ResourceTestCaseMixin, TestCase):
148182
def __init__(self, *args, **kwargs):
149183
self.apps = {}

ietf/api/urls.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
url(r'^meeting/session/video/url$', meeting_views.api_set_session_video_url),
2121
url(r'^submit/?$', submit_views.api_submit),
2222
url(r'^iesg/position', views_ballot.api_set_position),
23-
url(r'^export/person/$', api_views.PersonExportView.as_view()),
23+
url(r'^export/personal-information/$', api_views.PersonalInformationExportView.as_view()),
24+
url(r'^v2/person/person', api_views.ApiV2PersonExportView.as_view()),
2425
]
2526

2627
# Additional (standard) Tastypie endpoints

ietf/api/views.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from django.shortcuts import render, get_object_or_404
1212
from django.urls import reverse
1313
from django.utils.decorators import method_decorator
14+
from django.views.decorators.csrf import csrf_exempt
1415
from django.views.decorators.gzip import gzip_page
1516
from django.views.generic.detail import DetailView
1617

@@ -24,6 +25,9 @@
2425
from ietf.person.models import Person
2526
from ietf.api import _api_list
2627
from ietf.api.serializer import JsonExportMixin
28+
from ietf.utils.decorators import require_api_key
29+
from ietf.ietfauth.utils import role_required
30+
2731

2832
def top_level(request):
2933
available_resources = {}
@@ -59,10 +63,12 @@ def api_help(request):
5963

6064

6165
@method_decorator((login_required, gzip_page), name='dispatch')
62-
class PersonExportView(DetailView, JsonExportMixin):
66+
class PersonalInformationExportView(DetailView, JsonExportMixin):
67+
debug.mark()
6368
model = Person
6469

6570
def get(self, request):
71+
debug.mark()
6672
person = get_object_or_404(self.model, user=request.user)
6773
expand = ['searchrule', 'documentauthor', 'ad_document_set', 'ad_dochistory_set', 'docevent',
6874
'ballotpositiondocevent', 'deletedevent', 'email_set', 'groupevent', 'role', 'rolehistory', 'iprdisclosurebase',
@@ -71,5 +77,22 @@ def get(self, request):
7177
'reviewersettings', 'reviewsecretarysettings', 'unavailableperiod', 'reviewwish',
7278
'nextreviewerinteam', 'reviewrequest', 'meetingregistration', 'submissionevent', 'preapproval',
7379
'user', 'user__communitylist', ]
80+
debug.mark()
7481
return self.json_view(request, filter={'id':person.id}, expand=expand)
7582

83+
84+
@method_decorator((csrf_exempt, require_api_key, role_required('Secretariat')), name='dispatch')
85+
class ApiV2PersonExportView(DetailView, JsonExportMixin):
86+
model = Person
87+
88+
def err(self, code, text):
89+
return HttpResponse(text, status=code, content_type='text/plain')
90+
91+
def post(self, request):
92+
querydict = request.POST.copy()
93+
querydict.pop('apikey', None)
94+
expand = querydict.pop('_expand', [])
95+
if not querydict:
96+
return self.err(400, "No filters provided")
97+
98+
return self.json_view(request, filter=querydict.dict(), expand=expand)

ietf/person/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ def salt():
319319
# Manual maintenance: List all endpoints that use @require_api_key here
320320
PERSON_API_KEY_ENDPOINTS = [
321321
("/api/iesg/position", "/api/iesg/position"),
322+
("/api/v2/person/person", "/api/v2/person/person"),
322323
("/api/meeting/session/video/url", "/api/meeting/session/video/url"),
323324
]
324325

ietf/templates/registration/edit_profile.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ <h1>Profile for {{ user.username }}</h1>
3838

3939
All the information the datatracker has that is coupled to this account and visible
4040
on this page or otherwise related to your work on ietf documents, is also available
41-
to you as a <a href="{% url 'ietf.api.views.PersonExportView' %}">JSON blob</a> when
41+
to you as a <a href="{% url 'ietf.api.views.PersonalInformationExportView' %}">JSON blob</a> when
4242
you are logged in.
4343

4444
</p>

0 commit comments

Comments
 (0)