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 8e7e0faf529db057ac4f7496d0bc84fb05f0625d

Note: SVN reference [15264] has been migrated to Git commit e6549635650d4d9f9a9de7c5b4711f5a4a25c42c

Note: SVN reference [15265] has been migrated to Git commit 7c0e97f824b874763550adf1647841129017bf5a

Note: SVN reference [15287] has been migrated to Git commit 7431bdfcd9f2213c812a9004162ca576ae230a94
This commit is contained in:
Henrik Levkowetz 2018-10-08 14:23:51 +00:00
parent a74055c922
commit 8f2ba33059
5 changed files with 64 additions and 5 deletions

View file

@ -132,10 +132,9 @@ class CustomApiTestCase(TestCase):
event = doc.latest_event()
self.assertEqual(event.by, recman)
def test_person_export(self):
person = PersonFactory()
url = urlreverse('ietf.api.views.PersonExportView')
url = urlreverse('ietf.api.views.PersonalInformationExportView')
login_testing_unauthorized(self, person.user.username, url)
r = self.client.get(url)
jsondata = r.json()
@ -144,6 +143,41 @@ class CustomApiTestCase(TestCase):
self.assertEqual(data['ascii'], person.ascii)
self.assertEqual(data['user']['email'], person.user.email)
def test_api_v2_person_export_view(self):
url = urlreverse('ietf.api.views.ApiV2PersonExportView')
secretariat_role = RoleFactory(group__acronym='secretariat', name_id='secr')
secretariat = secretariat_role.person
apikey = PersonalApiKey.objects.create(endpoint=url, person=secretariat)
# error cases
r = self.client.post(url, {})
self.assertContains(r, "Missing apikey parameter", status_code=400)
badrole = RoleFactory(group__type_id='ietf', name_id='ad')
badapikey = PersonalApiKey.objects.create(endpoint=url, person=badrole.person)
badrole.person.user.last_login = timezone.now()
badrole.person.user.save()
r = self.client.post(url, {'apikey': badapikey.hash()})
self.assertContains(r, "Restricted to role Secretariat", status_code=403)
r = self.client.post(url, {'apikey': apikey.hash()})
self.assertContains(r, "Too long since last regular login", status_code=400)
secretariat.user.last_login = timezone.now()
secretariat.user.save()
r = self.client.post(url, {'apikey': apikey.hash()})
self.assertContains(r, "No filters provided", status_code=400)
# working case
r = self.client.post(url, {'apikey': apikey.hash(), 'email': secretariat.email().address, '_expand': 'user'})
self.assertEqual(r.status_code, 200)
jsondata = r.json()
data = jsondata['person.person'][str(secretariat.id)]
self.assertEqual(data['name'], secretariat.name)
self.assertEqual(data['ascii'], secretariat.ascii)
self.assertEqual(data['user']['email'], secretariat.user.email)
class TastypieApiTestCase(ResourceTestCaseMixin, TestCase):
def __init__(self, *args, **kwargs):
self.apps = {}

View file

@ -20,7 +20,8 @@ urlpatterns = [
url(r'^meeting/session/video/url$', meeting_views.api_set_session_video_url),
url(r'^submit/?$', submit_views.api_submit),
url(r'^iesg/position', views_ballot.api_set_position),
url(r'^export/person/$', api_views.PersonExportView.as_view()),
url(r'^export/personal-information/$', api_views.PersonalInformationExportView.as_view()),
url(r'^v2/person/person', api_views.ApiV2PersonExportView.as_view()),
]
# Additional (standard) Tastypie endpoints

View file

@ -11,6 +11,7 @@ from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.gzip import gzip_page
from django.views.generic.detail import DetailView
@ -24,6 +25,9 @@ import debug # pyflakes:ignore
from ietf.person.models import Person
from ietf.api import _api_list
from ietf.api.serializer import JsonExportMixin
from ietf.utils.decorators import require_api_key
from ietf.ietfauth.utils import role_required
def top_level(request):
available_resources = {}
@ -59,10 +63,12 @@ def api_help(request):
@method_decorator((login_required, gzip_page), name='dispatch')
class PersonExportView(DetailView, JsonExportMixin):
class PersonalInformationExportView(DetailView, JsonExportMixin):
debug.mark()
model = Person
def get(self, request):
debug.mark()
person = get_object_or_404(self.model, user=request.user)
expand = ['searchrule', 'documentauthor', 'ad_document_set', 'ad_dochistory_set', 'docevent',
'ballotpositiondocevent', 'deletedevent', 'email_set', 'groupevent', 'role', 'rolehistory', 'iprdisclosurebase',
@ -71,5 +77,22 @@ class PersonExportView(DetailView, JsonExportMixin):
'reviewersettings', 'reviewsecretarysettings', 'unavailableperiod', 'reviewwish',
'nextreviewerinteam', 'reviewrequest', 'meetingregistration', 'submissionevent', 'preapproval',
'user', 'user__communitylist', ]
debug.mark()
return self.json_view(request, filter={'id':person.id}, expand=expand)
@method_decorator((csrf_exempt, require_api_key, role_required('Secretariat')), name='dispatch')
class ApiV2PersonExportView(DetailView, JsonExportMixin):
model = Person
def err(self, code, text):
return HttpResponse(text, status=code, content_type='text/plain')
def post(self, request):
querydict = request.POST.copy()
querydict.pop('apikey', None)
expand = querydict.pop('_expand', [])
if not querydict:
return self.err(400, "No filters provided")
return self.json_view(request, filter=querydict.dict(), expand=expand)

View file

@ -319,6 +319,7 @@ def salt():
# Manual maintenance: List all endpoints that use @require_api_key here
PERSON_API_KEY_ENDPOINTS = [
("/api/iesg/position", "/api/iesg/position"),
("/api/v2/person/person", "/api/v2/person/person"),
("/api/meeting/session/video/url", "/api/meeting/session/video/url"),
]

View file

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