feat: Capture volunteers from the registration system (#6605)

* feat: Capture volunteers from the registration system. Fixes #5938

* fix: allow withdrawn field to be null

* docs: add explanatory code comments

* fix: identify current nomcom by is_accepting_volunteers

* fix: use auto_now_add instead of auto_now

* fix: update migration

---------

Co-authored-by: Robert Sparks <rjsparks@nostrum.com>
This commit is contained in:
Ryan Cross 2023-12-14 11:46:27 -08:00 committed by GitHub
parent 20d7e8c490
commit e9d44d41f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 93 additions and 3 deletions

View file

@ -28,6 +28,8 @@ from ietf.doc.factories import IndividualDraftFactory, WgDraftFactory, WgRfcFact
from ietf.group.factories import RoleFactory
from ietf.meeting.factories import MeetingFactory, SessionFactory
from ietf.meeting.models import Session
from ietf.nomcom.models import Volunteer, NomCom
from ietf.nomcom.factories import NomComFactory, nomcom_kwargs_for_year
from ietf.person.factories import PersonFactory, random_faker
from ietf.person.models import User
from ietf.person.models import PersonalApiKey
@ -630,6 +632,7 @@ class CustomApiTests(TestCase):
'reg_type': 'hackathon',
'ticket_type': '',
'checkedin': 'False',
'is_nomcom_volunteer': 'False',
}
url = urlreverse('ietf.api.views.api_new_meeting_registration')
r = self.client.post(url, reg)
@ -691,6 +694,50 @@ class CustomApiTests(TestCase):
missing_fields = [f.strip() for f in fields.split(',')]
self.assertEqual(set(missing_fields), set(drop_fields))
def test_api_new_meeting_registration_nomcom_volunteer(self):
'''Test that Volunteer is created if is_nomcom_volunteer=True
is submitted to API
'''
meeting = MeetingFactory(type_id='ietf')
reg = {
'apikey': 'invalid',
'affiliation': "Alguma Corporação",
'country_code': 'PT',
'meeting': meeting.number,
'reg_type': 'onsite',
'ticket_type': '',
'checkedin': 'False',
'is_nomcom_volunteer': 'True',
}
person = PersonFactory()
reg['email'] = person.email().address
reg['first_name'] = person.first_name()
reg['last_name'] = person.last_name()
now = datetime.datetime.now()
if now.month > 10:
year = now.year + 1
else:
year = now.year
# create appropriate group and nomcom objects
nomcom = NomComFactory.create(is_accepting_volunteers=True, **nomcom_kwargs_for_year(year))
url = urlreverse('ietf.api.views.api_new_meeting_registration')
r = self.client.post(url, reg)
self.assertContains(r, 'Invalid apikey', status_code=403)
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)
reg['apikey'] = key.hash()
r = self.client.post(url, reg)
nomcom = NomCom.objects.last()
self.assertContains(r, "Accepted, New registration", status_code=202)
# assert Volunteer exists
self.assertEqual(Volunteer.objects.count(), 1)
volunteer = Volunteer.objects.last()
self.assertEqual(volunteer.person, person)
self.assertEqual(volunteer.nomcom, nomcom)
self.assertEqual(volunteer.origin, 'registration')
def test_api_version(self):
DumpInfo.objects.create(date=timezone.datetime(2022,8,31,7,10,1,tzinfo=datetime.timezone.utc), host='testapi.example.com',tz='UTC')
url = urlreverse('ietf.api.views.version')

View file

@ -1,7 +1,6 @@
# Copyright The IETF Trust 2017-2020, All Rights Reserved
# -*- coding: utf-8 -*-
import json
import pytz
import re
@ -38,6 +37,7 @@ from ietf.doc.utils import fuzzy_find_documents
from ietf.ietfauth.views import send_account_creation_email
from ietf.ietfauth.utils import role_required
from ietf.meeting.models import Meeting
from ietf.nomcom.models import Volunteer, NomCom
from ietf.stats.models import MeetingRegistration
from ietf.utils import log
from ietf.utils.decorators import require_api_key
@ -140,7 +140,7 @@ def api_new_meeting_registration(request):
def err(code, text):
return HttpResponse(text, status=code, content_type='text/plain')
required_fields = [ 'meeting', 'first_name', 'last_name', 'affiliation', 'country_code',
'email', 'reg_type', 'ticket_type', 'checkedin']
'email', 'reg_type', 'ticket_type', 'checkedin', 'is_nomcom_volunteer']
fields = required_fields + []
if request.method == 'POST':
# parameters:
@ -202,6 +202,19 @@ def api_new_meeting_registration(request):
else:
send_account_creation_email(request, email)
response += ", Email sent"
# handle nomcom volunteer
if data['is_nomcom_volunteer'] and object.person:
try:
nomcom = NomCom.objects.get(is_accepting_volunteers=True)
except (NomCom.DoesNotExist, NomCom.MultipleObjectsReturned):
nomcom = None
if nomcom:
Volunteer.objects.create(
nomcom=nomcom,
person=object.person,
affiliation=data['affiliation'],
origin='registration')
return HttpResponse(response, status=202, content_type='text/plain')
else:
return HttpResponse(status=405)

View file

@ -0,0 +1,27 @@
# Generated by Django 4.2.7 on 2023-11-05 09:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("nomcom", "0003_alter_nomination_share_nominator"),
]
operations = [
migrations.AddField(
model_name="volunteer",
name="origin",
field=models.CharField(default="datatracker", max_length=32),
),
migrations.AddField(
model_name="volunteer",
name="time",
field=models.DateTimeField(auto_now_add=True, null=True, blank=True),
),
migrations.AddField(
model_name="volunteer",
name="withdrawn",
field=models.DateTimeField(blank=True, null=True),
),
]

View file

@ -327,7 +327,10 @@ class Volunteer(models.Model):
nomcom = ForeignKey('NomCom')
person = ForeignKey(Person)
affiliation = models.CharField(blank=True, max_length=255)
time = models.DateTimeField(auto_now_add=True, null=True, blank=True)
origin = models.CharField(max_length=32, default='datatracker')
withdrawn = models.DateTimeField(blank=True, null=True)
def __str__(self):
return f'{self.person} for {self.nomcom}'