Skip to content

Commit 9e46a05

Browse files
authored
ci: merge main to release (#8091)
2 parents 795fdfe + e72c365 commit 9e46a05

File tree

20 files changed

+118
-2102
lines changed

20 files changed

+118
-2102
lines changed

ietf/api/tests.py

Lines changed: 44 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@
3333
from ietf.meeting.models import Session
3434
from ietf.nomcom.models import Volunteer
3535
from ietf.nomcom.factories import NomComFactory, nomcom_kwargs_for_year
36-
from ietf.person.factories import PersonFactory, random_faker, EmailFactory
36+
from ietf.person.factories import PersonFactory, random_faker, EmailFactory, PersonalApiKeyFactory
3737
from ietf.person.models import Email, User
38-
from ietf.person.models import PersonalApiKey
3938
from ietf.stats.models import MeetingRegistration
4039
from ietf.utils.mail import empty_outbox, outbox, get_payload_text
4140
from ietf.utils.models import DumpInfo
@@ -71,15 +70,15 @@ def test_deprecated_api_set_session_video_url(self):
7170
meeting = MeetingFactory(type_id='ietf')
7271
session = SessionFactory(group__type_id='wg', meeting=meeting)
7372
group = session.group
74-
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman)
73+
apikey = PersonalApiKeyFactory(endpoint=url, person=recman)
7574
video = 'https://foo.example.com/bar/beer/'
7675

7776
# error cases
7877
r = self.client.post(url, {})
7978
self.assertContains(r, "Missing apikey parameter", status_code=400)
8079

8180
badrole = RoleFactory(group__type_id='ietf', name_id='ad')
82-
badapikey = PersonalApiKey.objects.create(endpoint=url, person=badrole.person)
81+
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
8382
badrole.person.user.last_login = timezone.now()
8483
badrole.person.user.save()
8584
r = self.client.post(url, {'apikey': badapikey.hash()} )
@@ -151,15 +150,15 @@ def test_api_set_session_video_url(self):
151150
recman = recmanrole.person
152151
meeting = MeetingFactory(type_id="ietf")
153152
session = SessionFactory(group__type_id="wg", meeting=meeting)
154-
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman)
153+
apikey = PersonalApiKeyFactory(endpoint=url, person=recman)
155154
video = "https://foo.example.com/bar/beer/"
156155

157156
# error cases
158157
r = self.client.post(url, {})
159158
self.assertContains(r, "Missing apikey parameter", status_code=400)
160159

161160
badrole = RoleFactory(group__type_id="ietf", name_id="ad")
162-
badapikey = PersonalApiKey.objects.create(endpoint=url, person=badrole.person)
161+
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
163162
badrole.person.user.last_login = timezone.now()
164163
badrole.person.user.save()
165164
r = self.client.post(url, {"apikey": badapikey.hash()})
@@ -228,15 +227,15 @@ def test_api_set_meetecho_recording_name(self):
228227
recman = recmanrole.person
229228
meeting = MeetingFactory(type_id="ietf")
230229
session = SessionFactory(group__type_id="wg", meeting=meeting)
231-
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman)
230+
apikey = PersonalApiKeyFactory(endpoint=url, person=recman)
232231
name = "testname"
233232

234233
# error cases
235234
r = self.client.post(url, {})
236235
self.assertContains(r, "Missing apikey parameter", status_code=400)
237236

238237
badrole = RoleFactory(group__type_id="ietf", name_id="ad")
239-
badapikey = PersonalApiKey.objects.create(endpoint=url, person=badrole.person)
238+
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
240239
badrole.person.user.last_login = timezone.now()
241240
badrole.person.user.save()
242241
r = self.client.post(url, {"apikey": badapikey.hash()})
@@ -295,10 +294,10 @@ def test_api_add_session_attendees_deprecated(self):
295294
recman = recmanrole.person
296295
meeting = MeetingFactory(type_id='ietf')
297296
session = SessionFactory(group__type_id='wg', meeting=meeting)
298-
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman)
297+
apikey = PersonalApiKeyFactory(endpoint=url, person=recman)
299298

300299
badrole = RoleFactory(group__type_id='ietf', name_id='ad')
301-
badapikey = PersonalApiKey.objects.create(endpoint=url, person=badrole.person)
300+
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
302301
badrole.person.user.last_login = timezone.now()
303302
badrole.person.user.save()
304303

@@ -361,10 +360,10 @@ def test_api_add_session_attendees(self):
361360
recman = recmanrole.person
362361
meeting = MeetingFactory(type_id="ietf")
363362
session = SessionFactory(group__type_id="wg", meeting=meeting)
364-
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman)
363+
apikey = PersonalApiKeyFactory(endpoint=url, person=recman)
365364

366365
badrole = RoleFactory(group__type_id="ietf", name_id="ad")
367-
badapikey = PersonalApiKey.objects.create(endpoint=url, person=badrole.person)
366+
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
368367
badrole.person.user.last_login = timezone.now()
369368
badrole.person.user.save()
370369

@@ -517,8 +516,8 @@ def test_api_upload_polls_and_chatlog(self):
517516
),
518517
):
519518
url = urlreverse(f"ietf.meeting.views.api_upload_{type_id}")
520-
apikey = PersonalApiKey.objects.create(endpoint=url, person=recmanrole.person)
521-
badapikey = PersonalApiKey.objects.create(endpoint=url, person=badrole.person)
519+
apikey = PersonalApiKeyFactory(endpoint=url, person=recmanrole.person)
520+
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
522521

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

567566
people = [
568567
{"name": "Andrea Andreotti", "affiliation": "Azienda"},
@@ -579,7 +578,7 @@ def test_deprecated_api_upload_bluesheet(self):
579578
self.assertContains(r, "Missing apikey parameter", status_code=400)
580579

581580
badrole = RoleFactory(group__type_id='ietf', name_id='ad')
582-
badapikey = PersonalApiKey.objects.create(endpoint=url, person=badrole.person)
581+
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
583582
badrole.person.user.last_login = timezone.now()
584583
badrole.person.user.save()
585584
r = self.client.post(url, {'apikey': badapikey.hash()})
@@ -654,7 +653,7 @@ def test_api_upload_bluesheet(self):
654653
meeting = MeetingFactory(type_id="ietf")
655654
session = SessionFactory(group__type_id="wg", meeting=meeting)
656655
group = session.group
657-
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman)
656+
apikey = PersonalApiKeyFactory(endpoint=url, person=recman)
658657

659658
people = [
660659
{"name": "Andrea Andreotti", "affiliation": "Azienda"},
@@ -671,7 +670,7 @@ def test_api_upload_bluesheet(self):
671670
self.assertContains(r, "Missing apikey parameter", status_code=400)
672671

673672
badrole = RoleFactory(group__type_id="ietf", name_id="ad")
674-
badapikey = PersonalApiKey.objects.create(endpoint=url, person=badrole.person)
673+
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
675674
badrole.person.user.last_login = timezone.now()
676675
badrole.person.user.save()
677676
r = self.client.post(url, {"apikey": badapikey.hash()})
@@ -781,14 +780,14 @@ def test_api_v2_person_export_view(self):
781780
url = urlreverse('ietf.api.views.ApiV2PersonExportView')
782781
robot = PersonFactory(user__is_staff=True)
783782
RoleFactory(name_id='robot', person=robot, email=robot.email(), group__acronym='secretariat')
784-
apikey = PersonalApiKey.objects.create(endpoint=url, person=robot)
783+
apikey = PersonalApiKeyFactory(endpoint=url, person=robot)
785784

786785
# error cases
787786
r = self.client.post(url, {})
788787
self.assertContains(r, "Missing apikey parameter", status_code=400)
789788

790789
badrole = RoleFactory(group__type_id='ietf', name_id='ad')
791-
badapikey = PersonalApiKey.objects.create(endpoint=url, person=badrole.person)
790+
badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
792791
badrole.person.user.last_login = timezone.now()
793792
badrole.person.user.save()
794793
r = self.client.post(url, {'apikey': badapikey.hash()})
@@ -827,7 +826,7 @@ def test_api_new_meeting_registration(self):
827826
oidcp = PersonFactory(user__is_staff=True)
828827
# Make sure 'oidcp' has an acceptable role
829828
RoleFactory(name_id='robot', person=oidcp, email=oidcp.email(), group__acronym='secretariat')
830-
key = PersonalApiKey.objects.create(person=oidcp, endpoint=url)
829+
key = PersonalApiKeyFactory(person=oidcp, endpoint=url)
831830
reg['apikey'] = key.hash()
832831
#
833832
# Test valid POST
@@ -911,7 +910,7 @@ def test_api_new_meeting_registration_nomcom_volunteer(self):
911910
oidcp = PersonFactory(user__is_staff=True)
912911
# Make sure 'oidcp' has an acceptable role
913912
RoleFactory(name_id='robot', person=oidcp, email=oidcp.email(), group__acronym='secretariat')
914-
key = PersonalApiKey.objects.create(person=oidcp, endpoint=url)
913+
key = PersonalApiKeyFactory(person=oidcp, endpoint=url)
915914
reg['apikey'] = key.hash()
916915

917916
# first test is_nomcom_volunteer False
@@ -945,28 +944,30 @@ def test_api_version(self):
945944

946945

947946
def test_api_appauth(self):
948-
url = urlreverse('ietf.api.views.app_auth')
949-
person = PersonFactory()
950-
apikey = PersonalApiKey.objects.create(endpoint=url, person=person)
951-
952-
self.client.login(username=person.user.username,password=f'{person.user.username}+password')
953-
self.client.logout()
954-
955-
# error cases
956-
# missing apikey
957-
r = self.client.post(url, {})
958-
self.assertContains(r, 'Missing apikey parameter', status_code=400)
959-
960-
# invalid apikey
961-
r = self.client.post(url, {'apikey': 'foobar'})
962-
self.assertContains(r, 'Invalid apikey', status_code=403)
963-
964-
# working case
965-
r = self.client.post(url, {'apikey': apikey.hash()})
966-
self.assertEqual(r.status_code, 200)
967-
jsondata = r.json()
968-
self.assertEqual(jsondata['success'], True)
947+
for app in ["authortools", "bibxml"]:
948+
url = urlreverse('ietf.api.views.app_auth', kwargs={"app": app})
949+
person = PersonFactory()
950+
apikey = PersonalApiKeyFactory(endpoint=url, person=person)
969951

952+
self.client.login(username=person.user.username,password=f'{person.user.username}+password')
953+
self.client.logout()
954+
955+
# error cases
956+
# missing apikey
957+
r = self.client.post(url, {})
958+
self.assertContains(r, 'Missing apikey parameter', status_code=400)
959+
960+
# invalid apikey
961+
r = self.client.post(url, {'apikey': 'foobar'})
962+
self.assertContains(r, 'Invalid apikey', status_code=403)
963+
964+
# working case
965+
r = self.client.post(url, {'apikey': apikey.hash()})
966+
self.assertEqual(r.status_code, 200)
967+
jsondata = r.json()
968+
self.assertEqual(jsondata['success'], True)
969+
self.client.logout()
970+
970971
def test_api_get_session_matherials_no_agenda_meeting_url(self):
971972
meeting = MeetingFactory(type_id='ietf')
972973
session = SessionFactory(meeting=meeting)

ietf/api/urls.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
# Datatracker version
7070
url(r'^version/?$', api_views.version),
7171
# Application authentication API key
72-
url(r'^appauth/[authortools|bibxml]', api_views.app_auth),
72+
url(r'^appauth/(?P<app>authortools|bibxml)$', api_views.app_auth),
7373
# latest versions
7474
url(r'^rfcdiff-latest-json/%(name)s(?:-%(rev)s)?(\.txt|\.html)?/?$' % settings.URL_REGEXPS, api_views.rfcdiff_latest_json),
7575
url(r'^rfcdiff-latest-json/(?P<name>[Rr][Ff][Cc] [0-9]+?)(\.txt|\.html)?/?$', api_views.rfcdiff_latest_json),

ietf/api/views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from tastypie.utils.mime import determine_format, build_content_type
3131
from textwrap import dedent
3232
from traceback import format_exception, extract_tb
33-
from typing import Iterable, Optional
33+
from typing import Iterable, Optional, Literal
3434

3535
import ietf
3636
from ietf.api import _api_list
@@ -251,7 +251,7 @@ def version(request):
251251

252252
@require_api_key
253253
@csrf_exempt
254-
def app_auth(request):
254+
def app_auth(request, app: Literal["authortools", "bibxml"]):
255255
return HttpResponse(
256256
json.dumps({'success': True}),
257257
content_type='application/json')

ietf/doc/tests_ballot.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
from ietf.ipr.factories import HolderIprDisclosureFactory
2828
from ietf.name.models import BallotPositionName
2929
from ietf.iesg.models import TelechatDate
30-
from ietf.person.models import Person, PersonalApiKey
31-
from ietf.person.factories import PersonFactory
30+
from ietf.person.models import Person
31+
from ietf.person.factories import PersonFactory, PersonalApiKeyFactory
3232
from ietf.person.utils import get_active_ads
3333
from ietf.utils.test_utils import TestCase, login_testing_unauthorized
3434
from ietf.utils.mail import outbox, empty_outbox, get_payload_text
@@ -111,7 +111,7 @@ def test_api_set_position(self):
111111
create_ballot_if_not_open(None, draft, ad, 'approve')
112112
ad.user.last_login = timezone.now()
113113
ad.user.save()
114-
apikey = PersonalApiKey.objects.create(endpoint=url, person=ad)
114+
apikey = PersonalApiKeyFactory(endpoint=url, person=ad)
115115

116116
# vote
117117
events_before = draft.docevent_set.count()

ietf/ietfauth/tests.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
from ietf.meeting.factories import MeetingFactory
3636
from ietf.nomcom.factories import NomComFactory
3737
from ietf.person.factories import PersonFactory, EmailFactory, UserFactory, PersonalApiKeyFactory
38-
from ietf.person.models import Person, Email, PersonalApiKey
38+
from ietf.person.models import Person, Email
3939
from ietf.person.tasks import send_apikey_usage_emails_task
4040
from ietf.review.factories import ReviewRequestFactory, ReviewAssignmentFactory
4141
from ietf.review.models import ReviewWish, UnavailablePeriod
@@ -788,9 +788,8 @@ def test_apikey_errors(self):
788788
self.assertContains(r, 'Invalid apikey', status_code=403)
789789

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

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

805804
# endpoint mismatch
806-
key2 = PersonalApiKey.objects.create(person=person, endpoint='/')
805+
key2 = PersonalApiKeyFactory(
806+
person=person,
807+
endpoint='/',
808+
validate_model=False, # allow invalid endpoint
809+
)
807810
r = self.client.post(key.endpoint, {'apikey':key2.hash(), 'dummy':'dummy',})
808811
self.assertContains(r, 'Apikey endpoint mismatch', status_code=400)
809812
key2.delete()

ietf/meeting/tests_views.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
from ietf.doc.models import Document, NewRevisionDocEvent
3939
from ietf.group.models import Group, Role, GroupFeatures
4040
from ietf.group.utils import can_manage_group
41-
from ietf.person.models import Person, PersonalApiKey
41+
from ietf.person.models import Person
4242
from ietf.meeting.helpers import can_approve_interim_request, can_request_interim_meeting, can_view_interim_request, preprocess_assignments_for_agenda
4343
from ietf.meeting.helpers import send_interim_approval_request, AgendaKeywordTagger
4444
from ietf.meeting.helpers import send_interim_meeting_cancellation_notice, send_interim_session_cancellation_notice
@@ -56,7 +56,7 @@
5656
from ietf.utils.test_utils import TestCase, login_testing_unauthorized, unicontent
5757
from ietf.utils.timezone import date_today, time_now
5858

59-
from ietf.person.factories import PersonFactory
59+
from ietf.person.factories import PersonFactory, PersonalApiKeyFactory
6060
from ietf.group.factories import GroupFactory, GroupEventFactory, RoleFactory
6161
from ietf.meeting.factories import (SessionFactory, ScheduleFactory,
6262
SessionPresentationFactory, MeetingFactory, FloorPlanFactory,
@@ -8743,7 +8743,7 @@ def test_session_attendance(self):
87438743
add_attendees_url = urlreverse('ietf.meeting.views.api_add_session_attendees')
87448744
recmanrole = RoleFactory(group__type_id='ietf', name_id='recman', person__user__last_login=timezone.now())
87458745
recman = recmanrole.person
8746-
apikey = PersonalApiKey.objects.create(endpoint=add_attendees_url, person=recman)
8746+
apikey = PersonalApiKeyFactory(endpoint=add_attendees_url, person=recman)
87478747
attendees = [person.user.pk for person in persons]
87488748
self.client.login(username='recman', password='recman+password')
87498749
r = self.client.post(add_attendees_url, {'apikey':apikey.hash(), 'attended':f'{{"session_id":{session.pk},"attendees":{attendees}}}'})

ietf/person/factories.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,22 @@ class Meta:
158158

159159
class PersonalApiKeyFactory(factory.django.DjangoModelFactory):
160160
person = factory.SubFactory(PersonFactory)
161-
endpoint = FuzzyChoice(PERSON_API_KEY_ENDPOINTS)
162-
161+
endpoint = FuzzyChoice(v for v, n in PERSON_API_KEY_ENDPOINTS)
162+
163163
class Meta:
164164
model = PersonalApiKey
165+
skip_postgeneration_save = True
166+
167+
@factory.post_generation
168+
def validate_model(obj, create, extracted, **kwargs):
169+
"""Validate the model after creation
170+
171+
Passing validate_model=False will disable the validation.
172+
"""
173+
do_clean = True if extracted is None else extracted
174+
if do_clean:
175+
obj.full_clean()
176+
165177

166178
class PersonApiKeyEventFactory(factory.django.DjangoModelFactory):
167179
key = factory.SubFactory(PersonalApiKeyFactory)

0 commit comments

Comments
 (0)