fix: add recording-name api key endpoint; appauth url fix (#8081)

* fix: add endpoint option for recording-name

* chore: migration

* test: validate PersonalApiKey when used in tests

* fix: limit /api/appauth URLs as intended

* test: fix tests

* chore: fix lint

* test: PersonalApiKey create -> factory

* chore: remove unused import
This commit is contained in:
Jennifer Richards 2024-10-25 10:52:09 -03:00 committed by GitHub
parent 0b4b26f9c3
commit 3130ecd9f5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 118 additions and 59 deletions

View file

@ -33,9 +33,8 @@ from ietf.meeting.factories import MeetingFactory, SessionFactory
from ietf.meeting.models import Session from ietf.meeting.models import Session
from ietf.nomcom.models import Volunteer from ietf.nomcom.models import Volunteer
from ietf.nomcom.factories import NomComFactory, nomcom_kwargs_for_year 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 Email, User
from ietf.person.models import PersonalApiKey
from ietf.stats.models import MeetingRegistration from ietf.stats.models import MeetingRegistration
from ietf.utils.mail import empty_outbox, outbox, get_payload_text from ietf.utils.mail import empty_outbox, outbox, get_payload_text
from ietf.utils.models import DumpInfo from ietf.utils.models import DumpInfo
@ -71,7 +70,7 @@ class CustomApiTests(TestCase):
meeting = MeetingFactory(type_id='ietf') meeting = MeetingFactory(type_id='ietf')
session = SessionFactory(group__type_id='wg', meeting=meeting) session = SessionFactory(group__type_id='wg', meeting=meeting)
group = session.group group = session.group
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman) apikey = PersonalApiKeyFactory(endpoint=url, person=recman)
video = 'https://foo.example.com/bar/beer/' video = 'https://foo.example.com/bar/beer/'
# error cases # error cases
@ -79,7 +78,7 @@ class CustomApiTests(TestCase):
self.assertContains(r, "Missing apikey parameter", status_code=400) self.assertContains(r, "Missing apikey parameter", status_code=400)
badrole = RoleFactory(group__type_id='ietf', name_id='ad') 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.last_login = timezone.now()
badrole.person.user.save() badrole.person.user.save()
r = self.client.post(url, {'apikey': badapikey.hash()} ) r = self.client.post(url, {'apikey': badapikey.hash()} )
@ -151,7 +150,7 @@ class CustomApiTests(TestCase):
recman = recmanrole.person recman = recmanrole.person
meeting = MeetingFactory(type_id="ietf") meeting = MeetingFactory(type_id="ietf")
session = SessionFactory(group__type_id="wg", meeting=meeting) 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/" video = "https://foo.example.com/bar/beer/"
# error cases # error cases
@ -159,7 +158,7 @@ class CustomApiTests(TestCase):
self.assertContains(r, "Missing apikey parameter", status_code=400) self.assertContains(r, "Missing apikey parameter", status_code=400)
badrole = RoleFactory(group__type_id="ietf", name_id="ad") 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.last_login = timezone.now()
badrole.person.user.save() badrole.person.user.save()
r = self.client.post(url, {"apikey": badapikey.hash()}) r = self.client.post(url, {"apikey": badapikey.hash()})
@ -228,7 +227,7 @@ class CustomApiTests(TestCase):
recman = recmanrole.person recman = recmanrole.person
meeting = MeetingFactory(type_id="ietf") meeting = MeetingFactory(type_id="ietf")
session = SessionFactory(group__type_id="wg", meeting=meeting) session = SessionFactory(group__type_id="wg", meeting=meeting)
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman) apikey = PersonalApiKeyFactory(endpoint=url, person=recman)
name = "testname" name = "testname"
# error cases # error cases
@ -236,7 +235,7 @@ class CustomApiTests(TestCase):
self.assertContains(r, "Missing apikey parameter", status_code=400) self.assertContains(r, "Missing apikey parameter", status_code=400)
badrole = RoleFactory(group__type_id="ietf", name_id="ad") 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.last_login = timezone.now()
badrole.person.user.save() badrole.person.user.save()
r = self.client.post(url, {"apikey": badapikey.hash()}) r = self.client.post(url, {"apikey": badapikey.hash()})
@ -295,10 +294,10 @@ class CustomApiTests(TestCase):
recman = recmanrole.person recman = recmanrole.person
meeting = MeetingFactory(type_id='ietf') meeting = MeetingFactory(type_id='ietf')
session = SessionFactory(group__type_id='wg', meeting=meeting) 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') 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.last_login = timezone.now()
badrole.person.user.save() badrole.person.user.save()
@ -361,10 +360,10 @@ class CustomApiTests(TestCase):
recman = recmanrole.person recman = recmanrole.person
meeting = MeetingFactory(type_id="ietf") meeting = MeetingFactory(type_id="ietf")
session = SessionFactory(group__type_id="wg", meeting=meeting) 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") 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.last_login = timezone.now()
badrole.person.user.save() badrole.person.user.save()
@ -517,8 +516,8 @@ class CustomApiTests(TestCase):
), ),
): ):
url = urlreverse(f"ietf.meeting.views.api_upload_{type_id}") url = urlreverse(f"ietf.meeting.views.api_upload_{type_id}")
apikey = PersonalApiKey.objects.create(endpoint=url, person=recmanrole.person) apikey = PersonalApiKeyFactory(endpoint=url, person=recmanrole.person)
badapikey = PersonalApiKey.objects.create(endpoint=url, person=badrole.person) badapikey = PersonalApiKeyFactory(endpoint=url, person=badrole.person)
r = self.client.post(url, {}) r = self.client.post(url, {})
self.assertContains(r, "Missing apikey parameter", status_code=400) self.assertContains(r, "Missing apikey parameter", status_code=400)
@ -562,7 +561,7 @@ class CustomApiTests(TestCase):
meeting = MeetingFactory(type_id='ietf') meeting = MeetingFactory(type_id='ietf')
session = SessionFactory(group__type_id='wg', meeting=meeting) session = SessionFactory(group__type_id='wg', meeting=meeting)
group = session.group group = session.group
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman) apikey = PersonalApiKeyFactory(endpoint=url, person=recman)
people = [ people = [
{"name": "Andrea Andreotti", "affiliation": "Azienda"}, {"name": "Andrea Andreotti", "affiliation": "Azienda"},
@ -579,7 +578,7 @@ class CustomApiTests(TestCase):
self.assertContains(r, "Missing apikey parameter", status_code=400) self.assertContains(r, "Missing apikey parameter", status_code=400)
badrole = RoleFactory(group__type_id='ietf', name_id='ad') 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.last_login = timezone.now()
badrole.person.user.save() badrole.person.user.save()
r = self.client.post(url, {'apikey': badapikey.hash()}) r = self.client.post(url, {'apikey': badapikey.hash()})
@ -654,7 +653,7 @@ class CustomApiTests(TestCase):
meeting = MeetingFactory(type_id="ietf") meeting = MeetingFactory(type_id="ietf")
session = SessionFactory(group__type_id="wg", meeting=meeting) session = SessionFactory(group__type_id="wg", meeting=meeting)
group = session.group group = session.group
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman) apikey = PersonalApiKeyFactory(endpoint=url, person=recman)
people = [ people = [
{"name": "Andrea Andreotti", "affiliation": "Azienda"}, {"name": "Andrea Andreotti", "affiliation": "Azienda"},
@ -671,7 +670,7 @@ class CustomApiTests(TestCase):
self.assertContains(r, "Missing apikey parameter", status_code=400) self.assertContains(r, "Missing apikey parameter", status_code=400)
badrole = RoleFactory(group__type_id="ietf", name_id="ad") 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.last_login = timezone.now()
badrole.person.user.save() badrole.person.user.save()
r = self.client.post(url, {"apikey": badapikey.hash()}) r = self.client.post(url, {"apikey": badapikey.hash()})
@ -781,14 +780,14 @@ class CustomApiTests(TestCase):
url = urlreverse('ietf.api.views.ApiV2PersonExportView') url = urlreverse('ietf.api.views.ApiV2PersonExportView')
robot = PersonFactory(user__is_staff=True) robot = PersonFactory(user__is_staff=True)
RoleFactory(name_id='robot', person=robot, email=robot.email(), group__acronym='secretariat') 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 # error cases
r = self.client.post(url, {}) r = self.client.post(url, {})
self.assertContains(r, "Missing apikey parameter", status_code=400) self.assertContains(r, "Missing apikey parameter", status_code=400)
badrole = RoleFactory(group__type_id='ietf', name_id='ad') 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.last_login = timezone.now()
badrole.person.user.save() badrole.person.user.save()
r = self.client.post(url, {'apikey': badapikey.hash()}) r = self.client.post(url, {'apikey': badapikey.hash()})
@ -827,7 +826,7 @@ class CustomApiTests(TestCase):
oidcp = PersonFactory(user__is_staff=True) oidcp = PersonFactory(user__is_staff=True)
# Make sure 'oidcp' has an acceptable role # Make sure 'oidcp' has an acceptable role
RoleFactory(name_id='robot', person=oidcp, email=oidcp.email(), group__acronym='secretariat') 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() reg['apikey'] = key.hash()
# #
# Test valid POST # Test valid POST
@ -911,7 +910,7 @@ class CustomApiTests(TestCase):
oidcp = PersonFactory(user__is_staff=True) oidcp = PersonFactory(user__is_staff=True)
# Make sure 'oidcp' has an acceptable role # Make sure 'oidcp' has an acceptable role
RoleFactory(name_id='robot', person=oidcp, email=oidcp.email(), group__acronym='secretariat') 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() reg['apikey'] = key.hash()
# first test is_nomcom_volunteer False # first test is_nomcom_volunteer False
@ -945,27 +944,29 @@ class CustomApiTests(TestCase):
def test_api_appauth(self): def test_api_appauth(self):
url = urlreverse('ietf.api.views.app_auth') for app in ["authortools", "bibxml"]:
person = PersonFactory() url = urlreverse('ietf.api.views.app_auth', kwargs={"app": app})
apikey = PersonalApiKey.objects.create(endpoint=url, person=person) person = PersonFactory()
apikey = PersonalApiKeyFactory(endpoint=url, person=person)
self.client.login(username=person.user.username,password=f'{person.user.username}+password') self.client.login(username=person.user.username,password=f'{person.user.username}+password')
self.client.logout() self.client.logout()
# error cases # error cases
# missing apikey # missing apikey
r = self.client.post(url, {}) r = self.client.post(url, {})
self.assertContains(r, 'Missing apikey parameter', status_code=400) self.assertContains(r, 'Missing apikey parameter', status_code=400)
# invalid apikey # invalid apikey
r = self.client.post(url, {'apikey': 'foobar'}) r = self.client.post(url, {'apikey': 'foobar'})
self.assertContains(r, 'Invalid apikey', status_code=403) self.assertContains(r, 'Invalid apikey', status_code=403)
# working case # working case
r = self.client.post(url, {'apikey': apikey.hash()}) r = self.client.post(url, {'apikey': apikey.hash()})
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
jsondata = r.json() jsondata = r.json()
self.assertEqual(jsondata['success'], True) self.assertEqual(jsondata['success'], True)
self.client.logout()
def test_api_get_session_matherials_no_agenda_meeting_url(self): def test_api_get_session_matherials_no_agenda_meeting_url(self):
meeting = MeetingFactory(type_id='ietf') meeting = MeetingFactory(type_id='ietf')

View file

@ -69,7 +69,7 @@ urlpatterns = [
# Datatracker version # Datatracker version
url(r'^version/?$', api_views.version), url(r'^version/?$', api_views.version),
# Application authentication API key # 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 # 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/%(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), url(r'^rfcdiff-latest-json/(?P<name>[Rr][Ff][Cc] [0-9]+?)(\.txt|\.html)?/?$', api_views.rfcdiff_latest_json),

View file

@ -30,7 +30,7 @@ from tastypie.utils import is_valid_jsonp_callback_value
from tastypie.utils.mime import determine_format, build_content_type from tastypie.utils.mime import determine_format, build_content_type
from textwrap import dedent from textwrap import dedent
from traceback import format_exception, extract_tb from traceback import format_exception, extract_tb
from typing import Iterable, Optional from typing import Iterable, Optional, Literal
import ietf import ietf
from ietf.api import _api_list from ietf.api import _api_list
@ -251,7 +251,7 @@ def version(request):
@require_api_key @require_api_key
@csrf_exempt @csrf_exempt
def app_auth(request): def app_auth(request, app: Literal["authortools", "bibxml"]):
return HttpResponse( return HttpResponse(
json.dumps({'success': True}), json.dumps({'success': True}),
content_type='application/json') content_type='application/json')

View file

@ -27,8 +27,8 @@ from ietf.group.factories import GroupFactory, RoleFactory, ReviewTeamFactory
from ietf.ipr.factories import HolderIprDisclosureFactory from ietf.ipr.factories import HolderIprDisclosureFactory
from ietf.name.models import BallotPositionName from ietf.name.models import BallotPositionName
from ietf.iesg.models import TelechatDate from ietf.iesg.models import TelechatDate
from ietf.person.models import Person, PersonalApiKey from ietf.person.models import Person
from ietf.person.factories import PersonFactory from ietf.person.factories import PersonFactory, PersonalApiKeyFactory
from ietf.person.utils import get_active_ads from ietf.person.utils import get_active_ads
from ietf.utils.test_utils import TestCase, login_testing_unauthorized from ietf.utils.test_utils import TestCase, login_testing_unauthorized
from ietf.utils.mail import outbox, empty_outbox, get_payload_text from ietf.utils.mail import outbox, empty_outbox, get_payload_text
@ -111,7 +111,7 @@ class EditPositionTests(TestCase):
create_ballot_if_not_open(None, draft, ad, 'approve') create_ballot_if_not_open(None, draft, ad, 'approve')
ad.user.last_login = timezone.now() ad.user.last_login = timezone.now()
ad.user.save() ad.user.save()
apikey = PersonalApiKey.objects.create(endpoint=url, person=ad) apikey = PersonalApiKeyFactory(endpoint=url, person=ad)
# vote # vote
events_before = draft.docevent_set.count() events_before = draft.docevent_set.count()

View file

@ -35,7 +35,7 @@ from ietf.ietfauth.utils import has_role
from ietf.meeting.factories import MeetingFactory from ietf.meeting.factories import MeetingFactory
from ietf.nomcom.factories import NomComFactory from ietf.nomcom.factories import NomComFactory
from ietf.person.factories import PersonFactory, EmailFactory, UserFactory, PersonalApiKeyFactory 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.person.tasks import send_apikey_usage_emails_task
from ietf.review.factories import ReviewRequestFactory, ReviewAssignmentFactory from ietf.review.factories import ReviewRequestFactory, ReviewAssignmentFactory
from ietf.review.models import ReviewWish, UnavailablePeriod from ietf.review.models import ReviewWish, UnavailablePeriod
@ -788,9 +788,8 @@ class IetfAuthTests(TestCase):
self.assertContains(r, 'Invalid apikey', status_code=403) self.assertContains(r, 'Invalid apikey', status_code=403)
# invalid apikey (invalidated api key) # invalid apikey (invalidated api key)
unauthorized_url = urlreverse('ietf.api.views.app_auth') unauthorized_url = urlreverse('ietf.api.views.app_auth', kwargs={'app': 'authortools'})
invalidated_apikey = PersonalApiKey.objects.create( invalidated_apikey = PersonalApiKeyFactory(endpoint=unauthorized_url, person=person, valid=False)
endpoint=unauthorized_url, person=person, valid=False)
r = self.client.post(unauthorized_url, {'apikey': invalidated_apikey.hash()}) r = self.client.post(unauthorized_url, {'apikey': invalidated_apikey.hash()})
self.assertContains(r, 'Invalid apikey', status_code=403) self.assertContains(r, 'Invalid apikey', status_code=403)
@ -803,7 +802,11 @@ class IetfAuthTests(TestCase):
person.user.save() person.user.save()
# endpoint mismatch # 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',}) r = self.client.post(key.endpoint, {'apikey':key2.hash(), 'dummy':'dummy',})
self.assertContains(r, 'Apikey endpoint mismatch', status_code=400) self.assertContains(r, 'Apikey endpoint mismatch', status_code=400)
key2.delete() key2.delete()

View file

@ -38,7 +38,7 @@ import debug # pyflakes:ignore
from ietf.doc.models import Document, NewRevisionDocEvent from ietf.doc.models import Document, NewRevisionDocEvent
from ietf.group.models import Group, Role, GroupFeatures from ietf.group.models import Group, Role, GroupFeatures
from ietf.group.utils import can_manage_group 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 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_approval_request, AgendaKeywordTagger
from ietf.meeting.helpers import send_interim_meeting_cancellation_notice, send_interim_session_cancellation_notice from ietf.meeting.helpers import send_interim_meeting_cancellation_notice, send_interim_session_cancellation_notice
@ -56,7 +56,7 @@ from ietf.utils.mail import outbox, empty_outbox, get_payload_text
from ietf.utils.test_utils import TestCase, login_testing_unauthorized, unicontent from ietf.utils.test_utils import TestCase, login_testing_unauthorized, unicontent
from ietf.utils.timezone import date_today, time_now 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.group.factories import GroupFactory, GroupEventFactory, RoleFactory
from ietf.meeting.factories import (SessionFactory, ScheduleFactory, from ietf.meeting.factories import (SessionFactory, ScheduleFactory,
SessionPresentationFactory, MeetingFactory, FloorPlanFactory, SessionPresentationFactory, MeetingFactory, FloorPlanFactory,
@ -8743,7 +8743,7 @@ class ProceedingsTests(BaseMeetingTestCase):
add_attendees_url = urlreverse('ietf.meeting.views.api_add_session_attendees') 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()) recmanrole = RoleFactory(group__type_id='ietf', name_id='recman', person__user__last_login=timezone.now())
recman = recmanrole.person 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] attendees = [person.user.pk for person in persons]
self.client.login(username='recman', password='recman+password') 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}}}'}) r = self.client.post(add_attendees_url, {'apikey':apikey.hash(), 'attended':f'{{"session_id":{session.pk},"attendees":{attendees}}}'})

View file

@ -158,10 +158,22 @@ class EmailFactory(factory.django.DjangoModelFactory):
class PersonalApiKeyFactory(factory.django.DjangoModelFactory): class PersonalApiKeyFactory(factory.django.DjangoModelFactory):
person = factory.SubFactory(PersonFactory) person = factory.SubFactory(PersonFactory)
endpoint = FuzzyChoice(PERSON_API_KEY_ENDPOINTS) endpoint = FuzzyChoice(v for v, n in PERSON_API_KEY_ENDPOINTS)
class Meta: class Meta:
model = PersonalApiKey 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): class PersonApiKeyEventFactory(factory.django.DjangoModelFactory):
key = factory.SubFactory(PersonalApiKeyFactory) key = factory.SubFactory(PersonalApiKeyFactory)

View file

@ -0,0 +1,42 @@
# Generated by Django 4.2.16 on 2024-10-24 21:39
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("person", "0002_alter_historicalperson_ascii_and_more"),
]
operations = [
migrations.AlterField(
model_name="personalapikey",
name="endpoint",
field=models.CharField(
choices=[
("/api/appauth/authortools", "/api/appauth/authortools"),
("/api/appauth/bibxml", "/api/appauth/bibxml"),
("/api/iesg/position", "/api/iesg/position"),
(
"/api/meeting/session/recording-name",
"/api/meeting/session/recording-name",
),
(
"/api/meeting/session/video/url",
"/api/meeting/session/video/url",
),
("/api/notify/meeting/bluesheet", "/api/notify/meeting/bluesheet"),
(
"/api/notify/meeting/registration",
"/api/notify/meeting/registration",
),
("/api/notify/session/attendees", "/api/notify/session/attendees"),
("/api/notify/session/chatlog", "/api/notify/session/chatlog"),
("/api/notify/session/polls", "/api/notify/session/polls"),
("/api/v2/person/person", "/api/v2/person/person"),
],
max_length=128,
),
),
]

View file

@ -376,6 +376,7 @@ PERSON_API_KEY_VALUES = [
("/api/iesg/position", "/api/iesg/position", "Area Director"), ("/api/iesg/position", "/api/iesg/position", "Area Director"),
("/api/v2/person/person", "/api/v2/person/person", "Robot"), ("/api/v2/person/person", "/api/v2/person/person", "Robot"),
("/api/meeting/session/video/url", "/api/meeting/session/video/url", "Recording Manager"), ("/api/meeting/session/video/url", "/api/meeting/session/video/url", "Recording Manager"),
("/api/meeting/session/recording-name", "/api/meeting/session/recording-name", "Recording Manager"),
("/api/notify/meeting/registration", "/api/notify/meeting/registration", "Robot"), ("/api/notify/meeting/registration", "/api/notify/meeting/registration", "Robot"),
("/api/notify/meeting/bluesheet", "/api/notify/meeting/bluesheet", "Recording Manager"), ("/api/notify/meeting/bluesheet", "/api/notify/meeting/bluesheet", "Recording Manager"),
("/api/notify/session/attendees", "/api/notify/session/attendees", "Recording Manager"), ("/api/notify/session/attendees", "/api/notify/session/attendees", "Recording Manager"),