Skip to content

Commit

Permalink
ci: merge main to release (#8091)
Browse files Browse the repository at this point in the history
  • Loading branch information
rjsparks authored Oct 25, 2024
2 parents 795fdfe + e72c365 commit 9e46a05
Show file tree
Hide file tree
Showing 20 changed files with 118 additions and 2,102 deletions.
87 changes: 44 additions & 43 deletions ietf/api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,8 @@
from ietf.meeting.models import Session
from ietf.nomcom.models import Volunteer
from ietf.nomcom.factories import NomComFactory, nomcom_kwargs_for_year
from ietf.person.factories import PersonFactory, random_faker, EmailFactory
from ietf.person.factories import PersonFactory, random_faker, EmailFactory, PersonalApiKeyFactory
from ietf.person.models import Email, User
from ietf.person.models import PersonalApiKey
from ietf.stats.models import MeetingRegistration
from ietf.utils.mail import empty_outbox, outbox, get_payload_text
from ietf.utils.models import DumpInfo
Expand Down Expand Up @@ -71,15 +70,15 @@ def test_deprecated_api_set_session_video_url(self):
meeting = MeetingFactory(type_id='ietf')
session = SessionFactory(group__type_id='wg', meeting=meeting)
group = session.group
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman)
apikey = PersonalApiKeyFactory(endpoint=url, person=recman)
video = 'https://foo.example.com/bar/beer/'

# 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)
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
badrole.person.user.last_login = timezone.now()
badrole.person.user.save()
r = self.client.post(url, {'apikey': badapikey.hash()} )
Expand Down Expand Up @@ -151,15 +150,15 @@ def test_api_set_session_video_url(self):
recman = recmanrole.person
meeting = MeetingFactory(type_id="ietf")
session = SessionFactory(group__type_id="wg", meeting=meeting)
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman)
apikey = PersonalApiKeyFactory(endpoint=url, person=recman)
video = "https://foo.example.com/bar/beer/"

# 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)
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
badrole.person.user.last_login = timezone.now()
badrole.person.user.save()
r = self.client.post(url, {"apikey": badapikey.hash()})
Expand Down Expand Up @@ -228,15 +227,15 @@ def test_api_set_meetecho_recording_name(self):
recman = recmanrole.person
meeting = MeetingFactory(type_id="ietf")
session = SessionFactory(group__type_id="wg", meeting=meeting)
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman)
apikey = PersonalApiKeyFactory(endpoint=url, person=recman)
name = "testname"

# 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)
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
badrole.person.user.last_login = timezone.now()
badrole.person.user.save()
r = self.client.post(url, {"apikey": badapikey.hash()})
Expand Down Expand Up @@ -295,10 +294,10 @@ def test_api_add_session_attendees_deprecated(self):
recman = recmanrole.person
meeting = MeetingFactory(type_id='ietf')
session = SessionFactory(group__type_id='wg', meeting=meeting)
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman)
apikey = PersonalApiKeyFactory(endpoint=url, person=recman)

badrole = RoleFactory(group__type_id='ietf', name_id='ad')
badapikey = PersonalApiKey.objects.create(endpoint=url, person=badrole.person)
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
badrole.person.user.last_login = timezone.now()
badrole.person.user.save()

Expand Down Expand Up @@ -361,10 +360,10 @@ def test_api_add_session_attendees(self):
recman = recmanrole.person
meeting = MeetingFactory(type_id="ietf")
session = SessionFactory(group__type_id="wg", meeting=meeting)
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman)
apikey = PersonalApiKeyFactory(endpoint=url, person=recman)

badrole = RoleFactory(group__type_id="ietf", name_id="ad")
badapikey = PersonalApiKey.objects.create(endpoint=url, person=badrole.person)
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
badrole.person.user.last_login = timezone.now()
badrole.person.user.save()

Expand Down Expand Up @@ -517,8 +516,8 @@ def test_api_upload_polls_and_chatlog(self):
),
):
url = urlreverse(f"ietf.meeting.views.api_upload_{type_id}")
apikey = PersonalApiKey.objects.create(endpoint=url, person=recmanrole.person)
badapikey = PersonalApiKey.objects.create(endpoint=url, person=badrole.person)
apikey = PersonalApiKeyFactory(endpoint=url, person=recmanrole.person)
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)

r = self.client.post(url, {})
self.assertContains(r, "Missing apikey parameter", status_code=400)
Expand Down Expand Up @@ -562,7 +561,7 @@ def test_deprecated_api_upload_bluesheet(self):
meeting = MeetingFactory(type_id='ietf')
session = SessionFactory(group__type_id='wg', meeting=meeting)
group = session.group
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman)
apikey = PersonalApiKeyFactory(endpoint=url, person=recman)

people = [
{"name": "Andrea Andreotti", "affiliation": "Azienda"},
Expand All @@ -579,7 +578,7 @@ def test_deprecated_api_upload_bluesheet(self):
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)
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
badrole.person.user.last_login = timezone.now()
badrole.person.user.save()
r = self.client.post(url, {'apikey': badapikey.hash()})
Expand Down Expand Up @@ -654,7 +653,7 @@ def test_api_upload_bluesheet(self):
meeting = MeetingFactory(type_id="ietf")
session = SessionFactory(group__type_id="wg", meeting=meeting)
group = session.group
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman)
apikey = PersonalApiKeyFactory(endpoint=url, person=recman)

people = [
{"name": "Andrea Andreotti", "affiliation": "Azienda"},
Expand All @@ -671,7 +670,7 @@ def test_api_upload_bluesheet(self):
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)
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
badrole.person.user.last_login = timezone.now()
badrole.person.user.save()
r = self.client.post(url, {"apikey": badapikey.hash()})
Expand Down Expand Up @@ -781,14 +780,14 @@ def test_api_v2_person_export_view(self):
url = urlreverse('ietf.api.views.ApiV2PersonExportView')
robot = PersonFactory(user__is_staff=True)
RoleFactory(name_id='robot', person=robot, email=robot.email(), group__acronym='secretariat')
apikey = PersonalApiKey.objects.create(endpoint=url, person=robot)
apikey = PersonalApiKeyFactory(endpoint=url, person=robot)

# 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)
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
badrole.person.user.last_login = timezone.now()
badrole.person.user.save()
r = self.client.post(url, {'apikey': badapikey.hash()})
Expand Down Expand Up @@ -827,7 +826,7 @@ def test_api_new_meeting_registration(self):
oidcp = PersonFactory(user__is_staff=True)
# Make sure 'oidcp' has an acceptable role
RoleFactory(name_id='robot', person=oidcp, email=oidcp.email(), group__acronym='secretariat')
key = PersonalApiKey.objects.create(person=oidcp, endpoint=url)
key = PersonalApiKeyFactory(person=oidcp, endpoint=url)
reg['apikey'] = key.hash()
#
# Test valid POST
Expand Down Expand Up @@ -911,7 +910,7 @@ def test_api_new_meeting_registration_nomcom_volunteer(self):
oidcp = PersonFactory(user__is_staff=True)
# Make sure 'oidcp' has an acceptable role
RoleFactory(name_id='robot', person=oidcp, email=oidcp.email(), group__acronym='secretariat')
key = PersonalApiKey.objects.create(person=oidcp, endpoint=url)
key = PersonalApiKeyFactory(person=oidcp, endpoint=url)
reg['apikey'] = key.hash()

# first test is_nomcom_volunteer False
Expand Down Expand Up @@ -945,28 +944,30 @@ def test_api_version(self):


def test_api_appauth(self):
url = urlreverse('ietf.api.views.app_auth')
person = PersonFactory()
apikey = PersonalApiKey.objects.create(endpoint=url, person=person)

self.client.login(username=person.user.username,password=f'{person.user.username}+password')
self.client.logout()

# error cases
# missing apikey
r = self.client.post(url, {})
self.assertContains(r, 'Missing apikey parameter', status_code=400)

# invalid apikey
r = self.client.post(url, {'apikey': 'foobar'})
self.assertContains(r, 'Invalid apikey', status_code=403)

# working case
r = self.client.post(url, {'apikey': apikey.hash()})
self.assertEqual(r.status_code, 200)
jsondata = r.json()
self.assertEqual(jsondata['success'], True)
for app in ["authortools", "bibxml"]:
url = urlreverse('ietf.api.views.app_auth', kwargs={"app": app})
person = PersonFactory()
apikey = PersonalApiKeyFactory(endpoint=url, person=person)

self.client.login(username=person.user.username,password=f'{person.user.username}+password')
self.client.logout()

# error cases
# missing apikey
r = self.client.post(url, {})
self.assertContains(r, 'Missing apikey parameter', status_code=400)

# invalid apikey
r = self.client.post(url, {'apikey': 'foobar'})
self.assertContains(r, 'Invalid apikey', status_code=403)

# working case
r = self.client.post(url, {'apikey': apikey.hash()})
self.assertEqual(r.status_code, 200)
jsondata = r.json()
self.assertEqual(jsondata['success'], True)
self.client.logout()

def test_api_get_session_matherials_no_agenda_meeting_url(self):
meeting = MeetingFactory(type_id='ietf')
session = SessionFactory(meeting=meeting)
Expand Down
2 changes: 1 addition & 1 deletion ietf/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
# Datatracker version
url(r'^version/?$', api_views.version),
# Application authentication API key
url(r'^appauth/[authortools|bibxml]', api_views.app_auth),
url(r'^appauth/(?P<app>authortools|bibxml)$', api_views.app_auth),
# latest versions
url(r'^rfcdiff-latest-json/%(name)s(?:-%(rev)s)?(\.txt|\.html)?/?$' % settings.URL_REGEXPS, api_views.rfcdiff_latest_json),
url(r'^rfcdiff-latest-json/(?P<name>[Rr][Ff][Cc] [0-9]+?)(\.txt|\.html)?/?$', api_views.rfcdiff_latest_json),
Expand Down
4 changes: 2 additions & 2 deletions ietf/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from tastypie.utils.mime import determine_format, build_content_type
from textwrap import dedent
from traceback import format_exception, extract_tb
from typing import Iterable, Optional
from typing import Iterable, Optional, Literal

import ietf
from ietf.api import _api_list
Expand Down Expand Up @@ -251,7 +251,7 @@ def version(request):

@require_api_key
@csrf_exempt
def app_auth(request):
def app_auth(request, app: Literal["authortools", "bibxml"]):
return HttpResponse(
json.dumps({'success': True}),
content_type='application/json')
Expand Down
6 changes: 3 additions & 3 deletions ietf/doc/tests_ballot.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
from ietf.ipr.factories import HolderIprDisclosureFactory
from ietf.name.models import BallotPositionName
from ietf.iesg.models import TelechatDate
from ietf.person.models import Person, PersonalApiKey
from ietf.person.factories import PersonFactory
from ietf.person.models import Person
from ietf.person.factories import PersonFactory, PersonalApiKeyFactory
from ietf.person.utils import get_active_ads
from ietf.utils.test_utils import TestCase, login_testing_unauthorized
from ietf.utils.mail import outbox, empty_outbox, get_payload_text
Expand Down Expand Up @@ -111,7 +111,7 @@ def test_api_set_position(self):
create_ballot_if_not_open(None, draft, ad, 'approve')
ad.user.last_login = timezone.now()
ad.user.save()
apikey = PersonalApiKey.objects.create(endpoint=url, person=ad)
apikey = PersonalApiKeyFactory(endpoint=url, person=ad)

# vote
events_before = draft.docevent_set.count()
Expand Down
13 changes: 8 additions & 5 deletions ietf/ietfauth/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from ietf.meeting.factories import MeetingFactory
from ietf.nomcom.factories import NomComFactory
from ietf.person.factories import PersonFactory, EmailFactory, UserFactory, PersonalApiKeyFactory
from ietf.person.models import Person, Email, PersonalApiKey
from ietf.person.models import Person, Email
from ietf.person.tasks import send_apikey_usage_emails_task
from ietf.review.factories import ReviewRequestFactory, ReviewAssignmentFactory
from ietf.review.models import ReviewWish, UnavailablePeriod
Expand Down Expand Up @@ -788,9 +788,8 @@ def test_apikey_errors(self):
self.assertContains(r, 'Invalid apikey', status_code=403)

# invalid apikey (invalidated api key)
unauthorized_url = urlreverse('ietf.api.views.app_auth')
invalidated_apikey = PersonalApiKey.objects.create(
endpoint=unauthorized_url, person=person, valid=False)
unauthorized_url = urlreverse('ietf.api.views.app_auth', kwargs={'app': 'authortools'})
invalidated_apikey = PersonalApiKeyFactory(endpoint=unauthorized_url, person=person, valid=False)
r = self.client.post(unauthorized_url, {'apikey': invalidated_apikey.hash()})
self.assertContains(r, 'Invalid apikey', status_code=403)

Expand All @@ -803,7 +802,11 @@ def test_apikey_errors(self):
person.user.save()

# endpoint mismatch
key2 = PersonalApiKey.objects.create(person=person, endpoint='/')
key2 = PersonalApiKeyFactory(
person=person,
endpoint='/',
validate_model=False, # allow invalid endpoint
)
r = self.client.post(key.endpoint, {'apikey':key2.hash(), 'dummy':'dummy',})
self.assertContains(r, 'Apikey endpoint mismatch', status_code=400)
key2.delete()
Expand Down
6 changes: 3 additions & 3 deletions ietf/meeting/tests_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
from ietf.doc.models import Document, NewRevisionDocEvent
from ietf.group.models import Group, Role, GroupFeatures
from ietf.group.utils import can_manage_group
from ietf.person.models import Person, PersonalApiKey
from ietf.person.models import Person
from ietf.meeting.helpers import can_approve_interim_request, can_request_interim_meeting, can_view_interim_request, preprocess_assignments_for_agenda
from ietf.meeting.helpers import send_interim_approval_request, AgendaKeywordTagger
from ietf.meeting.helpers import send_interim_meeting_cancellation_notice, send_interim_session_cancellation_notice
Expand All @@ -56,7 +56,7 @@
from ietf.utils.test_utils import TestCase, login_testing_unauthorized, unicontent
from ietf.utils.timezone import date_today, time_now

from ietf.person.factories import PersonFactory
from ietf.person.factories import PersonFactory, PersonalApiKeyFactory
from ietf.group.factories import GroupFactory, GroupEventFactory, RoleFactory
from ietf.meeting.factories import (SessionFactory, ScheduleFactory,
SessionPresentationFactory, MeetingFactory, FloorPlanFactory,
Expand Down Expand Up @@ -8743,7 +8743,7 @@ def test_session_attendance(self):
add_attendees_url = urlreverse('ietf.meeting.views.api_add_session_attendees')
recmanrole = RoleFactory(group__type_id='ietf', name_id='recman', person__user__last_login=timezone.now())
recman = recmanrole.person
apikey = PersonalApiKey.objects.create(endpoint=add_attendees_url, person=recman)
apikey = PersonalApiKeyFactory(endpoint=add_attendees_url, person=recman)
attendees = [person.user.pk for person in persons]
self.client.login(username='recman', password='recman+password')
r = self.client.post(add_attendees_url, {'apikey':apikey.hash(), 'attended':f'{{"session_id":{session.pk},"attendees":{attendees}}}'})
Expand Down
16 changes: 14 additions & 2 deletions ietf/person/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,22 @@ class Meta:

class PersonalApiKeyFactory(factory.django.DjangoModelFactory):
person = factory.SubFactory(PersonFactory)
endpoint = FuzzyChoice(PERSON_API_KEY_ENDPOINTS)

endpoint = FuzzyChoice(v for v, n in PERSON_API_KEY_ENDPOINTS)
class Meta:
model = PersonalApiKey
skip_postgeneration_save = True

@factory.post_generation
def validate_model(obj, create, extracted, **kwargs):
"""Validate the model after creation
Passing validate_model=False will disable the validation.
"""
do_clean = True if extracted is None else extracted
if do_clean:
obj.full_clean()


class PersonApiKeyEventFactory(factory.django.DjangoModelFactory):
key = factory.SubFactory(PersonalApiKeyFactory)
Expand Down
Loading

0 comments on commit 9e46a05

Please sign in to comment.