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:
parent
a74055c922
commit
8f2ba33059
|
@ -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 = {}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"),
|
||||
]
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue