From 4a354adecc2302cc489dce614e5e3cc69938f8b2 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Wed, 8 Jun 2022 14:04:12 -0300 Subject: [PATCH 1/8] feat: show session requests for all "has_meetings" groups --- ietf/meeting/views.py | 10 ++++++++-- ietf/templates/meeting/requests.html | 8 ++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index 69219796371..76a42d1fc3b 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -2137,9 +2137,10 @@ def agenda_json(request, num=None): def meeting_requests(request, num=None): meeting = get_meeting(num) + groups_to_show = Group.objects.filter(state='Active', type__features__has_meetings=True) sessions = Session.objects.requests().filter( meeting__number=meeting.number, - group__parent__isnull=False + group__in=groups_to_show, ).with_current_status().with_requested_by().exclude( requested_by=0 ).order_by( @@ -2155,7 +2156,12 @@ def meeting_requests(request, num=None): s.current_status_name = status_names.get(s.current_status, s.current_status) s.requested_by_person = session_requesters.get(s.requested_by) - 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, diff --git a/ietf/templates/meeting/requests.html b/ietf/templates/meeting/requests.html index c2cbcc2561a..e9b14d59a7d 100644 --- a/ietf/templates/meeting/requests.html +++ b/ietf/templates/meeting/requests.html @@ -17,8 +17,12 @@

{% regroup sessions by group.parent 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 %} + Non-Area Groups + {% endif %}

No timeslot request received for: From 1583f0de51d2bdaecedd1a47aba93a1ba92d2a5b Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Fri, 10 Jun 2022 16:42:45 -0300 Subject: [PATCH 2/8] test: test changes to groups whose session requests are shown Note the change in capitalization for the 'active' group state fixes the test but does not seem to affect production (which I guess uses case insensitive matching?) --- ietf/meeting/tests_views.py | 30 ++++++++++++++++++++++++++++++ ietf/meeting/views.py | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/ietf/meeting/tests_views.py b/ietf/meeting/tests_views.py index 5c35da300e8..b94f03207aa 100644 --- a/ietf/meeting/tests_views.py +++ b/ietf/meeting/tests_views.py @@ -6406,17 +6406,47 @@ 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, + ) + not_has_meetings = SessionFactory( + meeting=meeting, + group__type_id=group_type_without_meetings, + status_id='schedw', + add_to_schedule=False, + ) + url = urlreverse('ietf.meeting.views.meeting_requests',kwargs={'num':meeting.number}) r = self.client.get(url) + print(r.content.decode()) self.assertContains(r, requested_session.group.acronym) self.assertContains(r, not_meeting.group.acronym) self.assertContains(r, requested_session.constraints().first().name) self.assertContains(r, conflicting_session.group.acronym) + self.assertContains(r, has_meetings.group.acronym) + self.assertContains(r, has_meetings_not_meeting.group.acronym) + self.assertNotContains(r, not_has_meetings.group.acronym) def test_request_minutes(self): meeting = MeetingFactory(type_id='ietf') diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index 76a42d1fc3b..36c62177f14 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -2137,7 +2137,7 @@ def agenda_json(request, num=None): def meeting_requests(request, num=None): meeting = get_meeting(num) - groups_to_show = Group.objects.filter(state='Active', type__features__has_meetings=True) + groups_to_show = Group.objects.filter(state_id='active', type__features__has_meetings=True) sessions = Session.objects.requests().filter( meeting__number=meeting.number, group__in=groups_to_show, From cb7aca35b8b941905cad1bab0b80d88e993fa300 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Mon, 27 Jun 2022 17:20:55 -0300 Subject: [PATCH 3/8] test: remove leftover debug statement --- ietf/meeting/tests_views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ietf/meeting/tests_views.py b/ietf/meeting/tests_views.py index df5640e87e6..2862a5e6443 100644 --- a/ietf/meeting/tests_views.py +++ b/ietf/meeting/tests_views.py @@ -6431,7 +6431,6 @@ def test_meeting_requests(self): url = urlreverse('ietf.meeting.views.meeting_requests',kwargs={'num':meeting.number}) r = self.client.get(url) - print(r.content.decode()) self.assertContains(r, requested_session.group.acronym) self.assertContains(r, not_meeting.group.acronym) self.assertContains(r, requested_session.constraints().first().name) From c87d4fea514620d0890bad330cb0d3012c1eb270 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Mon, 27 Jun 2022 17:33:44 -0300 Subject: [PATCH 4/8] feature: exclude admin/social sessions from meeting requests view --- ietf/meeting/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index 9c8b661596f..fad2d9c1e8f 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -2141,6 +2141,8 @@ def meeting_requests(request, num=None): sessions = 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 ).order_by( From 4f6f816843fd5f231786c9769639bafa1212b8ec Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Mon, 27 Jun 2022 17:34:13 -0300 Subject: [PATCH 5/8] test: test exclusion of admin/social sessions from meeting requests view --- ietf/meeting/tests_views.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/ietf/meeting/tests_views.py b/ietf/meeting/tests_views.py index 2862a5e6443..2e2b58cf3e8 100644 --- a/ietf/meeting/tests_views.py +++ b/ietf/meeting/tests_views.py @@ -6422,6 +6422,23 @@ def test_meeting_requests(self): 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, @@ -6429,10 +6446,28 @@ def test_meeting_requests(self): 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 + 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, has_meetings.group.acronym) From db33d2930426f2decf0d2681c1c59e46ae58faff Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Tue, 28 Jun 2022 14:50:01 -0300 Subject: [PATCH 6/8] feat: group all non-area groups as "other" on meeting requests page --- ietf/meeting/views.py | 45 +++++++++++++++++++--------- ietf/templates/meeting/requests.html | 6 ++-- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index fad2d9c1e8f..adc24eebffe 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -2138,17 +2138,17 @@ def agenda_json(request, num=None): def meeting_requests(request, num=None): meeting = get_meeting(num) groups_to_show = Group.objects.filter(state_id='active', type__features__has_meetings=True) - sessions = 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 - ).order_by( - "group__parent__acronym", "current_status", "group__acronym" - ).prefetch_related( - "group","group__ad_role__person" + 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()} @@ -2157,6 +2157,17 @@ 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 = groups_to_show.exclude( acronym__in = [session.group.acronym for session in sessions] @@ -2165,9 +2176,15 @@ def meeting_requests(request, num=None): "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 e9b14d59a7d..dca4d3e3a14 100644 --- a/ietf/templates/meeting/requests.html +++ b/ietf/templates/meeting/requests.html @@ -15,13 +15,13 @@

{% 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 %} -

+

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

From 447d7eb47fd56280b481756a456bdf19ef37faa4 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Tue, 28 Jun 2022 14:50:27 -0300 Subject: [PATCH 7/8] fix: prevent doubling of first section header --- ietf/templates/meeting/requests.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ietf/templates/meeting/requests.html b/ietf/templates/meeting/requests.html index dca4d3e3a14..1a4db6b9932 100644 --- a/ietf/templates/meeting/requests.html +++ b/ietf/templates/meeting/requests.html @@ -43,7 +43,7 @@

{% for session in area.list %} - {% ifchanged %} + {% ifchanged session.current_status_name %} {% if not forloop.first %}{% endif %} From 1cfc7b8471829c2fb22fb18fe82968cbbc77cc33 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Tue, 28 Jun 2022 16:52:47 -0300 Subject: [PATCH 8/8] test: verify that more of the sreqs are / are not linked --- ietf/meeting/tests_views.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ietf/meeting/tests_views.py b/ietf/meeting/tests_views.py index 2e2b58cf3e8..c984e1f15f8 100644 --- a/ietf/meeting/tests_views.py +++ b/ietf/meeting/tests_views.py @@ -6461,18 +6461,23 @@ def _sreq_edit_link(sess): 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 + # 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 + # 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')