Refined the GUI for personal API endpoints so that endpoints for which one does not have the right Roles do not show in the GUI, and added a supporting method on Person objects. Updated tests accordingly.

- Legacy-Id: 17643
This commit is contained in:
Henrik Levkowetz 2020-04-15 17:22:06 +00:00
parent eedd48d455
commit 69a5d0817d
3 changed files with 29 additions and 19 deletions

View file

@ -21,7 +21,7 @@ from ietf.group.models import Group, Role, RoleName
from ietf.group.factories import GroupFactory, RoleFactory
from ietf.ietfauth.htpasswd import update_htpasswd_file
from ietf.mailinglists.models import Subscribed
from ietf.person.models import Person, Email, PersonalApiKey, PERSON_API_KEY_ENDPOINTS
from ietf.person.models import Person, Email, PersonalApiKey
from ietf.person.factories import PersonFactory, EmailFactory
from ietf.review.factories import ReviewRequestFactory, ReviewAssignmentFactory
from ietf.review.models import ReviewWish, UnavailablePeriod
@ -531,18 +531,19 @@ class IetfAuthTests(TestCase):
self.assertContains(r, 'Endpoint')
# Add 2 keys
for endpoint, display in PERSON_API_KEY_ENDPOINTS:
endpoints = person.available_api_endpoints()
for endpoint, display in endpoints:
r = self.client.post(url, {'endpoint': endpoint})
self.assertRedirects(r, urlreverse('ietf.ietfauth.views.apikey_index'))
# Check api key list content
url = urlreverse('ietf.ietfauth.views.apikey_index')
r = self.client.get(url)
for endpoint, display in PERSON_API_KEY_ENDPOINTS:
for endpoint, display in endpoints:
self.assertContains(r, endpoint)
q = PyQuery(r.content)
self.assertEqual(len(q('td code')), len(PERSON_API_KEY_ENDPOINTS)) # hash
self.assertEqual(len(q('td a:contains("Disable")')), len(PERSON_API_KEY_ENDPOINTS))
self.assertEqual(len(q('td code')), len(endpoints)) # hash
self.assertEqual(len(q('td a:contains("Disable")')), len(endpoints))
# Get one of the keys
key = person.apikeys.first()
@ -562,8 +563,8 @@ class IetfAuthTests(TestCase):
url = urlreverse('ietf.ietfauth.views.apikey_index')
r = self.client.get(url)
q = PyQuery(r.content)
self.assertEqual(len(q('td code')), len(PERSON_API_KEY_ENDPOINTS)) # key hash
self.assertEqual(len(q('td a:contains("Disable")')), len(PERSON_API_KEY_ENDPOINTS)-1)
self.assertEqual(len(q('td code')), len(endpoints)) # key hash
self.assertEqual(len(q('td a:contains("Disable")')), len(endpoints)-1)
def test_apikey_errors(self):
BAD_KEY = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
@ -577,7 +578,7 @@ class IetfAuthTests(TestCase):
login_testing_unauthorized(self, person.user.username, url)
# Add keys
for endpoint, display in PERSON_API_KEY_ENDPOINTS:
for endpoint, display in person.available_api_endpoints():
r = self.client.post(url, {'endpoint': endpoint})
self.assertRedirects(r, urlreverse('ietf.ietfauth.views.apikey_index'))
@ -620,7 +621,8 @@ class IetfAuthTests(TestCase):
login_testing_unauthorized(self, person.user.username, url)
# Add keys
for endpoint, display in PERSON_API_KEY_ENDPOINTS:
endpoints = person.available_api_endpoints()
for endpoint, display in endpoints:
r = self.client.post(url, {'endpoint': endpoint})
self.assertRedirects(r, urlreverse('ietf.ietfauth.views.apikey_index'))
@ -639,7 +641,7 @@ class IetfAuthTests(TestCase):
cmd = Command()
cmd.handle(verbosity=0, days=7)
self.assertEqual(len(outbox), len(PERSON_API_KEY_ENDPOINTS))
self.assertEqual(len(outbox), len(endpoints))
for mail in outbox:
body = mail.get_payload(decode=True).decode('utf-8')
self.assertIn("API key usage", mail['subject'])

View file

@ -65,9 +65,9 @@ from ietf.ietfauth.forms import ( RegistrationForm, PasswordForm, ResetPasswordF
WhitelistForm, ChangePasswordForm, get_person_form, RoleEmailForm,
NewEmailForm, ChangeUsernameForm, PersonPasswordForm)
from ietf.ietfauth.htpasswd import update_htpasswd_file
from ietf.ietfauth.utils import role_required
from ietf.ietfauth.utils import role_required, has_role
from ietf.mailinglists.models import Subscribed, Whitelisted
from ietf.person.models import Person, Email, Alias, PersonalApiKey
from ietf.person.models import Person, Email, Alias, PersonalApiKey, PERSON_API_KEY_VALUES
from ietf.review.models import ReviewerSettings, ReviewWish, ReviewAssignment
from ietf.review.utils import unavailable_periods_to_list, get_default_filter_re
from ietf.doc.fields import SearchableDocumentField
@ -650,7 +650,10 @@ def apikey_index(request):
@login_required
@person_required
def apikey_create(request):
endpoints = [('', '----------')] + [ (v, n) for (v, n, r) in PERSON_API_KEY_VALUES if r==None or has_role(request.user, r) ]
class ApiKeyForm(forms.ModelForm):
endpoint = forms.ChoiceField(choices=endpoints)
class Meta:
model = PersonalApiKey
fields = ['endpoint']

View file

@ -234,6 +234,11 @@ class Person(models.Model):
ct1['ascii'] = self.ascii
return ct1
def available_api_endpoints(self):
from ietf.ietfauth.utils import has_role
return [ (v, n) for (v, n, r) in PERSON_API_KEY_VALUES if r==None or has_role(self.user, r) ]
@python_2_unicode_compatible
class Alias(models.Model):
"""This is used for alternative forms of a name. This is the
@ -328,13 +333,13 @@ def salt():
return uuid.uuid4().bytes[:12]
# Manual maintenance: List all endpoints that use @require_api_key here
PERSON_API_KEY_ENDPOINTS = [
("/api/iesg/position", "/api/iesg/position"),
# This requires secretariat role, and need not be listed generally:
# ("/api/v2/person/person", "/api/v2/person/person"),
("/api/meeting/session/video/url", "/api/meeting/session/video/url"),
("/api/v2/person/access/meetecho", "/api/v2/person/access/meetecho"),
PERSON_API_KEY_VALUES = [
("/api/iesg/position", "/api/iesg/position", "Area Director"),
("/api/v2/person/person", "/api/v2/person/person", "Secretariat"),
("/api/meeting/session/video/url", "/api/meeting/session/video/url", "Recording Manager"),
("/api/person/access/meetecho", "/api/person/access/meetecho", None),
]
PERSON_API_KEY_ENDPOINTS = [ (v, n) for (v, n, r) in PERSON_API_KEY_VALUES ]
@python_2_unicode_compatible
class PersonalApiKey(models.Model):
@ -375,7 +380,7 @@ class PersonalApiKey(models.Model):
return self._cached_hash
def __str__(self):
return "%s (%s): %s ..." % (self.endpoint, self.created.strftime("%Y-%m-%d %H:%M"), self.hash()[:16])
return "%s %-24s %-32s(%6d): %s ..." % (self.created.strftime("%Y-%m-%d %H:%M"), self.person.name, self.endpoint, self.count, self.hash()[:16])
PERSON_EVENT_CHOICES = [
("apikey_login", "API key login"),