diff --git a/ietf/meeting/tests_views.py b/ietf/meeting/tests_views.py index f15f504c246..c984e1f15f8 100644 --- a/ietf/meeting/tests_views.py +++ b/ietf/meeting/tests_views.py @@ -6398,17 +6398,86 @@ class SessionTests(TestCase): def test_meeting_requests(self): meeting = MeetingFactory(type_id='ietf') + + # a couple non-wg group types, confirm that their has_meetings features are as expected + group_type_with_meetings = 'adhoc' + self.assertTrue(GroupFeatures.objects.get(pk=group_type_with_meetings).has_meetings) + group_type_without_meetings = 'editorial' + self.assertFalse(GroupFeatures.objects.get(pk=group_type_without_meetings).has_meetings) + area = GroupFactory(type_id='area') requested_session = SessionFactory(meeting=meeting,group__parent=area,status_id='schedw',add_to_schedule=False) conflicting_session = SessionFactory(meeting=meeting,group__parent=area,status_id='schedw',add_to_schedule=False) ConstraintFactory(name_id='key_participant',meeting=meeting,source=requested_session.group,target=conflicting_session.group) not_meeting = SessionFactory(meeting=meeting,group__parent=area,status_id='notmeet',add_to_schedule=False) + has_meetings = SessionFactory( + meeting=meeting, + group__type_id=group_type_with_meetings, + status_id='schedw', + add_to_schedule=False, + ) + has_meetings_not_meeting = SessionFactory( + meeting=meeting, + group__type_id=group_type_with_meetings, + status_id='notmeet', + add_to_schedule=False, + ) + # admin and social sessions are not to be shown on the requests page + has_meetings_admin_session = SessionFactory( + meeting=meeting, + group__type_id=group_type_with_meetings, + status_id='schedw', + purpose_id='admin', + type_id='other', + add_to_schedule=False, + ) + has_meetings_social_session = SessionFactory( + meeting=meeting, + group__type_id=group_type_with_meetings, + status_id='schedw', + purpose_id='social', + type_id='break', + add_to_schedule=False, + ) + not_has_meetings = SessionFactory( + meeting=meeting, + group__type_id=group_type_without_meetings, + status_id='schedw', + add_to_schedule=False, + ) + + def _sreq_edit_link(sess): + return urlreverse( + 'ietf.secr.sreq.views.edit', + kwargs={ + 'num': meeting.number, + 'acronym': sess.group.acronym, + }, + ) + url = urlreverse('ietf.meeting.views.meeting_requests',kwargs={'num':meeting.number}) r = self.client.get(url) + # requested_session group should be listed with a link to the request self.assertContains(r, requested_session.group.acronym) + self.assertContains(r, _sreq_edit_link(requested_session)) # link to the session request self.assertContains(r, not_meeting.group.acronym) + # The admin/social session groups should be listed under "no timeslot request received"; it's easier + # to check that the group is listed but that there is no link to the session request than to try to + # parse the HTML. If the view is changed to link to the "no timeslot request received" session requests, + # then need to revisit. + self.assertContains(r, has_meetings_admin_session.group.acronym) + self.assertNotContains(r, _sreq_edit_link(has_meetings_admin_session)) # no link to the session request + self.assertContains(r, has_meetings_social_session.group.acronym) + self.assertNotContains(r, _sreq_edit_link(has_meetings_social_session)) # no link to the session request self.assertContains(r, requested_session.constraints().first().name) self.assertContains(r, conflicting_session.group.acronym) + self.assertContains(r, _sreq_edit_link(conflicting_session)) # link to the session request + self.assertContains(r, has_meetings.group.acronym) + self.assertContains(r, _sreq_edit_link(has_meetings)) # link to the session request + self.assertContains(r, has_meetings_not_meeting.group.acronym) + self.assertContains(r, _sreq_edit_link(has_meetings_not_meeting)) # link to the session request + self.assertNotContains(r, not_has_meetings.group.acronym) + self.assertNotContains(r, _sreq_edit_link(not_has_meetings)) # no link to the session request def test_request_minutes(self): meeting = MeetingFactory(type_id='ietf') diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index 3967533c26e..adc24eebffe 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -2137,15 +2137,18 @@ def agenda_json(request, num=None): def meeting_requests(request, num=None): meeting = get_meeting(num) - sessions = Session.objects.requests().filter( - meeting__number=meeting.number, - group__parent__isnull=False - ).with_current_status().with_requested_by().exclude( - requested_by=0 - ).order_by( - "group__parent__acronym", "current_status", "group__acronym" - ).prefetch_related( - "group","group__ad_role__person" + groups_to_show = Group.objects.filter(state_id='active', type__features__has_meetings=True) + sessions = list( + Session.objects.requests().filter( + meeting__number=meeting.number, + group__in=groups_to_show, + ).exclude( + purpose__in=('admin', 'social'), + ).with_current_status().with_requested_by().exclude( + requested_by=0 + ).prefetch_related( + "group","group__ad_role__person" + ) ) status_names = {n.slug: n.name for n in SessionStatusName.objects.all()} @@ -2154,12 +2157,34 @@ def meeting_requests(request, num=None): for s in sessions: s.current_status_name = status_names.get(s.current_status, s.current_status) s.requested_by_person = session_requesters.get(s.requested_by) + if s.group.parent and s.group.parent.type.slug == 'area': + s.display_area = s.group.parent + else: + s.display_area = None + sessions.sort( + key=lambda s: ( + s.display_area.acronym if s.display_area is not None else 'zzzz', + s.current_status, + s.group.acronym, + ), + ) - groups_not_meeting = Group.objects.filter(state='Active',type__in=['wg','rg','ag','rag','bof','program']).exclude(acronym__in = [session.group.acronym for session in sessions]).order_by("parent__acronym","acronym").prefetch_related("parent") + groups_not_meeting = groups_to_show.exclude( + acronym__in = [session.group.acronym for session in sessions] + ).order_by( + "parent__acronym", + "acronym", + ).prefetch_related("parent") - return render(request, "meeting/requests.html", - {"meeting": meeting, "sessions":sessions, - "groups_not_meeting": groups_not_meeting}) + return render( + request, + "meeting/requests.html", + { + "meeting": meeting, + "sessions": sessions, + "groups_not_meeting": groups_not_meeting, + }, + ) def get_sessions(num, acronym): diff --git a/ietf/templates/meeting/requests.html b/ietf/templates/meeting/requests.html index c2cbcc2561a..1a4db6b9932 100644 --- a/ietf/templates/meeting/requests.html +++ b/ietf/templates/meeting/requests.html @@ -15,10 +15,14 @@

{% if meeting.venue_name %}– {{ meeting.venue_name }}{% endif %}

- {% regroup sessions by group.parent as area_sessions %} + {% regroup sessions by display_area as area_sessions %} {% for area in area_sessions %} -

- {{ area.grouper.acronym|upper }} {{ area.grouper.name }} +

+ {% if area.grouper is not None %} + {{ area.grouper.acronym|upper }} {{ area.grouper.name }} + {% else %} + Other Groups + {% endif %}

No timeslot request received for: @@ -39,7 +43,7 @@

{% for session in area.list %} - {% ifchanged %} + {% ifchanged session.current_status_name %} {% if not forloop.first %}{% endif %}