Repository: ietf-tools/datatracker

Issue:
Generating volunteer list
### Description

It would be nice to have an option to generate the volunteer list that just output text/plain with numbering.
```
1. Rich Salz
2. Robert Sparks
3. ...
```


### Code of Conduct

- [X] I agree to follow the [IETF's Code of Conduct](https://github.com/ietf-tools/.github/blob/main/CODE_OF_CONDUCT.md)


Discussion:

Resolving patch:
diff --git a/ietf/nomcom/urls.py b/ietf/nomcom/urls.py
--- a/ietf/nomcom/urls.py
+++ b/ietf/nomcom/urls.py
@@ -41,6 +41,7 @@
     url(r'^(?P<year>\d{4})/private/chair/eligible/$', views.private_eligible),
     url(r'^(?P<year>\d{4})/private/chair/volunteers/$', views.private_volunteers),
     url(r'^(?P<year>\d{4})/private/chair/volunteers/csv/$', views.private_volunteers_csv),
+    url(r'^(?P<year>\d{4})/private/chair/volunteers/announce-list/$', views.qualified_volunteer_list_for_announcement),
 
     url(r'^(?P<year>\d{4})/$', views.year_index),
     url(r'^(?P<year>\d{4})/requirements/$', views.requirements),
diff --git a/ietf/nomcom/views.py b/ietf/nomcom/views.py
--- a/ietf/nomcom/views.py
+++ b/ietf/nomcom/views.py
@@ -1333,3 +1333,12 @@ def private_volunteers_csv(request, year, public=False):
         writer.writerow([v.person.last_name(), v.person.first_name(), v.person.ascii_name(), v.affiliation, v.person.email(), v.qualifications, v.eligible])
     return response
 
+@role_required("Nomcom Chair", "Nomcom Advisor", "Secretariat")
+def qualified_volunteer_list_for_announcement(request, year, public=False):
+    _, volunteers = extract_volunteers(year)
+    qualified_volunteers = [v for v in volunteers if v.eligible]
+    return render(request, 'nomcom/qualified_volunteer_list_for_announcement.txt',
+                dict(volunteers=qualified_volunteers),
+                content_type="text/plain; charset=%s"%settings.DEFAULT_CHARSET)
+
+


Test patch:
diff --git a/ietf/nomcom/tests.py b/ietf/nomcom/tests.py
--- a/ietf/nomcom/tests.py
+++ b/ietf/nomcom/tests.py
@@ -1489,7 +1489,10 @@ class NewActiveNomComTests(TestCase):
     def setUp(self):
         super().setUp()
         setup_test_public_keys_dir(self)
-        self.nc = NomComFactory.create(**nomcom_kwargs_for_year(year=random.randint(1992,2100)))
+        # Pin nomcom years to be after 2008 or later so that ietf.nomcom.utils.list_eligible can 
+        # return something other than empty. Note that anything after 2022 is suspect, and that
+        # we should revisit this when implementing RFC 9389.
+        self.nc = NomComFactory.create(**nomcom_kwargs_for_year(year=random.randint(2008,2100)))
         self.chair = self.nc.group.role_set.filter(name='chair').first().person
         self.saved_days_to_expire_nomination_link = settings.DAYS_TO_EXPIRE_NOMINATION_LINK
 
@@ -1929,7 +1932,7 @@ def first_meeting_of_year(year):
         for number in range(meeting_start, meeting_start+8):
             m = MeetingFactory.create(type_id='ietf', number=number)
             for p in people:
-                m.meetingregistration_set.create(person=p)
+                m.meetingregistration_set.create(person=p, reg_type="onsite", checkedin=True, attended=True)
         for p in people:
             self.nc.volunteer_set.create(person=p,affiliation='something')
         for view in ('public_volunteers','private_volunteers'):
@@ -1947,6 +1950,14 @@ def first_meeting_of_year(year):
         login_testing_unauthorized(self,self.chair.user.username,url)
         response = self.client.get(url)
         self.assertContains(response,people[-1].email(),status_code=200)
+        unqualified_person = PersonFactory()
+        url = reverse('ietf.nomcom.views.qualified_volunteer_list_for_announcement',kwargs={'year':year})
+        self.client.logout()
+        login_testing_unauthorized(self,self.chair.user.username,url)
+        response = self.client.get(url)
+        self.assertContains(response, people[-1].plain_name(), status_code=200)
+        self.assertNotContains(response, unqualified_person.plain_name())
+