feat: API to list role-holder addresses (#7291)
* feat: API to list role-holder addresses * test: Test new API endpoint * fix: role_holder_addresses gets own API token * refactor: Move role_holder_addresses to ietf.api.views * test: test for group.utils.role_holder_emails * test: Clean up test_role_holder_addresses * fix: Missed a change in urls.py * refactor: Remove old view * chore: Remove unused import * chore: Remove unused import
This commit is contained in:
parent
8d7e8d6830
commit
6b4a806e42
|
@ -991,6 +991,28 @@ class CustomApiTests(TestCase):
|
||||||
self.assertCountEqual(result.keys(), ["addresses"])
|
self.assertCountEqual(result.keys(), ["addresses"])
|
||||||
self.assertCountEqual(result["addresses"], Email.objects.filter(active=True).values_list("address", flat=True))
|
self.assertCountEqual(result["addresses"], Email.objects.filter(active=True).values_list("address", flat=True))
|
||||||
|
|
||||||
|
@override_settings(APP_API_TOKENS={"ietf.api.views.role_holder_addresses": ["valid-token"]})
|
||||||
|
def test_role_holder_addresses(self):
|
||||||
|
url = urlreverse("ietf.api.views.role_holder_addresses")
|
||||||
|
r = self.client.get(url, headers={})
|
||||||
|
self.assertEqual(r.status_code, 403, "No api token, no access")
|
||||||
|
r = self.client.get(url, headers={"X-Api-Key": "not-valid-token"})
|
||||||
|
self.assertEqual(r.status_code, 403, "Bad api token, no access")
|
||||||
|
r = self.client.post(url, headers={"X-Api-Key": "valid-token"})
|
||||||
|
self.assertEqual(r.status_code, 405, "Bad method, no access")
|
||||||
|
|
||||||
|
emails = EmailFactory.create_batch(5)
|
||||||
|
email_queryset = Email.objects.filter(pk__in=[e.pk for e in emails])
|
||||||
|
with mock.patch("ietf.api.views.role_holder_emails", return_value=email_queryset):
|
||||||
|
r = self.client.get(url, headers={"X-Api-Key": "valid-token"})
|
||||||
|
self.assertEqual(r.status_code, 200, "Good api token and method, access")
|
||||||
|
content_dict = json.loads(r.content)
|
||||||
|
self.assertCountEqual(content_dict.keys(), ["addresses"])
|
||||||
|
self.assertEqual(
|
||||||
|
content_dict["addresses"],
|
||||||
|
sorted(e.address for e in emails),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DirectAuthApiTests(TestCase):
|
class DirectAuthApiTests(TestCase):
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,8 @@ urlpatterns = [
|
||||||
url(r'^export/personal-information/$', api_views.PersonalInformationExportView.as_view()),
|
url(r'^export/personal-information/$', api_views.PersonalInformationExportView.as_view()),
|
||||||
# Email alias information for groups
|
# Email alias information for groups
|
||||||
url(r'^group/group-aliases/$', api_views.group_aliases),
|
url(r'^group/group-aliases/$', api_views.group_aliases),
|
||||||
|
# Email addresses belonging to role holders
|
||||||
|
url(r'^group/role-holder-addresses/$', api_views.role_holder_addresses),
|
||||||
# Let IESG members set positions programmatically
|
# Let IESG members set positions programmatically
|
||||||
url(r'^iesg/position', views_ballot.api_set_position),
|
url(r'^iesg/position', views_ballot.api_set_position),
|
||||||
# Let Meetecho set session video URLs
|
# Let Meetecho set session video URLs
|
||||||
|
|
|
@ -29,7 +29,7 @@ from ietf.api import _api_list
|
||||||
from ietf.api.ietf_utils import is_valid_token, requires_api_token
|
from ietf.api.ietf_utils import is_valid_token, requires_api_token
|
||||||
from ietf.api.serializer import JsonExportMixin
|
from ietf.api.serializer import JsonExportMixin
|
||||||
from ietf.doc.utils import DraftAliasGenerator, fuzzy_find_documents
|
from ietf.doc.utils import DraftAliasGenerator, fuzzy_find_documents
|
||||||
from ietf.group.utils import GroupAliasGenerator
|
from ietf.group.utils import GroupAliasGenerator, role_holder_emails
|
||||||
from ietf.ietfauth.utils import role_required
|
from ietf.ietfauth.utils import role_required
|
||||||
from ietf.ietfauth.views import send_account_creation_email
|
from ietf.ietfauth.views import send_account_creation_email
|
||||||
from ietf.meeting.models import Meeting
|
from ietf.meeting.models import Meeting
|
||||||
|
@ -500,3 +500,18 @@ def active_email_list(request):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return HttpResponse(status=405)
|
return HttpResponse(status=405)
|
||||||
|
|
||||||
|
|
||||||
|
@requires_api_token
|
||||||
|
def role_holder_addresses(request):
|
||||||
|
if request.method == "GET":
|
||||||
|
return JsonResponse(
|
||||||
|
{
|
||||||
|
"addresses": list(
|
||||||
|
role_holder_emails()
|
||||||
|
.order_by("address")
|
||||||
|
.values_list("address", flat=True)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return HttpResponse(status=405)
|
||||||
|
|
|
@ -18,10 +18,16 @@ import debug # pyflakes:ignore
|
||||||
from ietf.doc.factories import DocumentFactory, WgDraftFactory, EditorialDraftFactory
|
from ietf.doc.factories import DocumentFactory, WgDraftFactory, EditorialDraftFactory
|
||||||
from ietf.doc.models import DocEvent, RelatedDocument, Document
|
from ietf.doc.models import DocEvent, RelatedDocument, Document
|
||||||
from ietf.group.models import Role, Group
|
from ietf.group.models import Role, Group
|
||||||
from ietf.group.utils import get_group_role_emails, get_child_group_role_emails, get_group_ad_emails, GroupAliasGenerator
|
from ietf.group.utils import (
|
||||||
|
get_group_role_emails,
|
||||||
|
get_child_group_role_emails,
|
||||||
|
get_group_ad_emails,
|
||||||
|
GroupAliasGenerator,
|
||||||
|
role_holder_emails,
|
||||||
|
)
|
||||||
from ietf.group.factories import GroupFactory, RoleFactory
|
from ietf.group.factories import GroupFactory, RoleFactory
|
||||||
from ietf.person.factories import PersonFactory, EmailFactory
|
from ietf.person.factories import PersonFactory, EmailFactory
|
||||||
from ietf.person.models import Person
|
from ietf.person.models import Email, Person
|
||||||
from ietf.utils.test_utils import login_testing_unauthorized, TestCase
|
from ietf.utils.test_utils import login_testing_unauthorized, TestCase
|
||||||
|
|
||||||
class StreamTests(TestCase):
|
class StreamTests(TestCase):
|
||||||
|
@ -240,3 +246,41 @@ class GroupRoleEmailTests(TestCase):
|
||||||
self.assertGreater(len(emails), 0)
|
self.assertGreater(len(emails), 0)
|
||||||
for item in emails:
|
for item in emails:
|
||||||
self.assertIn('@', item)
|
self.assertIn('@', item)
|
||||||
|
|
||||||
|
def test_role_holder_emails(self):
|
||||||
|
# The test fixtures create a bunch of addresses that pollute this test's results - disable them
|
||||||
|
Email.objects.update(active=False)
|
||||||
|
|
||||||
|
role_holders = [
|
||||||
|
RoleFactory(name_id="member", group__type_id=gt).person
|
||||||
|
for gt in [
|
||||||
|
"ag",
|
||||||
|
"area",
|
||||||
|
"dir",
|
||||||
|
"iab",
|
||||||
|
"ietf",
|
||||||
|
"irtf",
|
||||||
|
"nomcom",
|
||||||
|
"rg",
|
||||||
|
"team",
|
||||||
|
"wg",
|
||||||
|
"rag",
|
||||||
|
]
|
||||||
|
]
|
||||||
|
# Expect an additional active email to be included
|
||||||
|
EmailFactory(
|
||||||
|
person=role_holders[0],
|
||||||
|
active=True,
|
||||||
|
)
|
||||||
|
# Do not expect an inactive email to be included
|
||||||
|
EmailFactory(
|
||||||
|
person=role_holders[1],
|
||||||
|
active=False,
|
||||||
|
)
|
||||||
|
# Do not expect address on a role-holder for a different group type
|
||||||
|
RoleFactory(name_id="member", group__type_id="adhoc") # arbitrary type not in the of-interest list
|
||||||
|
|
||||||
|
self.assertCountEqual(
|
||||||
|
role_holder_emails(),
|
||||||
|
Email.objects.filter(active=True, person__in=role_holders),
|
||||||
|
)
|
||||||
|
|
|
@ -425,3 +425,28 @@ class GroupAliasGenerator:
|
||||||
chair_emails = get_group_role_emails(group, ["chair", "delegate"])
|
chair_emails = get_group_role_emails(group, ["chair", "delegate"])
|
||||||
if chair_emails:
|
if chair_emails:
|
||||||
yield group.acronym + "-chairs", ["ietf"], list(chair_emails)
|
yield group.acronym + "-chairs", ["ietf"], list(chair_emails)
|
||||||
|
|
||||||
|
|
||||||
|
def role_holder_emails():
|
||||||
|
"""Get queryset of active Emails for group role holders"""
|
||||||
|
group_types_of_interest = [
|
||||||
|
"ag",
|
||||||
|
"area",
|
||||||
|
"dir",
|
||||||
|
"iab",
|
||||||
|
"ietf",
|
||||||
|
"irtf",
|
||||||
|
"nomcom",
|
||||||
|
"rg",
|
||||||
|
"team",
|
||||||
|
"wg",
|
||||||
|
"rag",
|
||||||
|
]
|
||||||
|
roles = Role.objects.filter(
|
||||||
|
group__state__slug="active",
|
||||||
|
group__type__in=group_types_of_interest,
|
||||||
|
)
|
||||||
|
emails = Email.objects.filter(active=True).exclude(
|
||||||
|
address__startswith="unknown-email-"
|
||||||
|
)
|
||||||
|
return emails.filter(person__role__in=roles).distinct()
|
||||||
|
|
Loading…
Reference in a new issue