Skip to content

Commit 233bff8

Browse files
Improve handling of submissions for closed working groups. Fixes ietf-tools#3058. Commit ready for merge.
- Legacy-Id: 18798
1 parent 6c953bd commit 233bff8

14 files changed

Lines changed: 879 additions & 127 deletions

File tree

ietf/group/models.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class GroupInfo(models.Model):
4949

5050
uses_milestone_dates = models.BooleanField(default=True)
5151

52+
ACTIVE_STATE_IDS = ('active', 'bof', 'proposed') # states considered "active"
53+
5254
def __str__(self):
5355
return self.name
5456

@@ -72,12 +74,39 @@ def about_url(self):
7274
def is_bof(self):
7375
return self.state_id in ["bof", "bof-conc"]
7476

77+
@property
78+
def is_wg(self):
79+
return self.type_id == 'wg'
80+
81+
@property
82+
def is_active(self):
83+
# N.B., this has only been thought about for groups of type WG!
84+
return self.state_id in self.ACTIVE_STATE_IDS
85+
86+
@property
87+
def is_individual(self):
88+
return self.acronym == 'none'
89+
90+
@property
91+
def area(self):
92+
if self.type_id == 'area':
93+
return self
94+
elif not self.is_individual and self.parent:
95+
return self.parent
96+
return None
97+
7598
class Meta:
7699
abstract = True
77100

78101
class GroupManager(models.Manager):
102+
def wgs(self):
103+
return self.get_queryset().filter(type='wg')
104+
79105
def active_wgs(self):
80-
return self.get_queryset().filter(type='wg', state__in=('bof','proposed','active'))
106+
return self.wgs().filter(state__in=Group.ACTIVE_STATE_IDS)
107+
108+
def closed_wgs(self):
109+
return self.wgs().exclude(state__in=Group.ACTIVE_STATE_IDS)
81110

82111
class Group(GroupInfo):
83112
objects = GroupManager()
@@ -114,6 +143,13 @@ def get_chair(self):
114143
chair = self.role_set.filter(name__slug='chair')[:1]
115144
return chair and chair[0] or None
116145

146+
@property
147+
def ads(self):
148+
return sorted(
149+
self.role_set.filter(name="ad").select_related("email", "person"),
150+
key=lambda role: role.person.name_parts()[3], # gets last name
151+
)
152+
117153
# these are copied to Group because it is still proxied.
118154
@property
119155
def upcase_acronym(self):

ietf/group/views.py

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,6 @@ def wg_summary_area(request, group_type):
221221
raise Http404
222222
areas = Group.objects.filter(type="area", state="active").order_by("name")
223223
for area in areas:
224-
area.ads = sorted(roles(area, "ad"), key=extract_last_name)
225224
area.groups = Group.objects.filter(parent=area, type="wg", state="active").order_by("acronym")
226225
for group in area.groups:
227226
group.chairs = sorted(roles(group, "chair"), key=extract_last_name)
@@ -250,13 +249,11 @@ def wg_charters(request, group_type):
250249
raise Http404
251250
areas = Group.objects.filter(type="area", state="active").order_by("name")
252251
for area in areas:
253-
area.ads = sorted(roles(area, "ad"), key=extract_last_name)
254252
area.groups = Group.objects.filter(parent=area, type="wg", state="active").order_by("name")
255253
for group in area.groups:
256254
fill_in_charter_info(group)
257255
fill_in_wg_roles(group)
258256
fill_in_wg_drafts(group)
259-
group.area = area
260257
return render(request, 'group/1wg-charters.txt',
261258
{ 'areas': areas },
262259
content_type='text/plain; charset=UTF-8')
@@ -265,17 +262,12 @@ def wg_charters(request, group_type):
265262
def wg_charters_by_acronym(request, group_type):
266263
if group_type != "wg":
267264
raise Http404
268-
areas = dict((a.id, a) for a in Group.objects.filter(type="area", state="active").order_by("name"))
269-
270-
for area in areas.values():
271-
area.ads = sorted(roles(area, "ad"), key=extract_last_name)
272265

273266
groups = Group.objects.filter(type="wg", state="active").exclude(parent=None).order_by("acronym")
274267
for group in groups:
275268
fill_in_charter_info(group)
276269
fill_in_wg_roles(group)
277270
fill_in_wg_drafts(group)
278-
group.area = areas.get(group.parent_id)
279271
return render(request, 'group/1wg-charters-by-acronym.txt',
280272
{ 'groups': groups },
281273
content_type='text/plain; charset=UTF-8')
@@ -313,15 +305,13 @@ def active_dirs(request):
313305
dirs = Group.objects.filter(type__in=['dir', 'review'], state="active").order_by("name")
314306
for group in dirs:
315307
group.chairs = sorted(roles(group, "chair"), key=extract_last_name)
316-
group.ads = sorted(roles(group, "ad"), key=extract_last_name)
317308
group.secretaries = sorted(roles(group, "secr"), key=extract_last_name)
318309
return render(request, 'group/active_dirs.html', {'dirs' : dirs })
319310

320311
def active_review_dirs(request):
321312
dirs = Group.objects.filter(type="review", state="active").order_by("name")
322313
for group in dirs:
323314
group.chairs = sorted(roles(group, "chair"), key=extract_last_name)
324-
group.ads = sorted(roles(group, "ad"), key=extract_last_name)
325315
group.secretaries = sorted(roles(group, "secr"), key=extract_last_name)
326316
return render(request, 'group/active_review_dirs.html', {'dirs' : dirs })
327317

@@ -345,14 +335,15 @@ def active_wgs(request):
345335
areas = Group.objects.filter(type="area", state="active").order_by("name")
346336
for area in areas:
347337
# dig out information for template
348-
area.ads = (list(sorted(roles(area, "ad"), key=extract_last_name))
349-
+ list(sorted(roles(area, "pre-ad"), key=extract_last_name)))
338+
area.ads_and_pre_ads = (
339+
list(area.ads) + list(sorted(roles(area, "pre-ad"), key=extract_last_name))
340+
)
350341

351342
area.groups = Group.objects.filter(parent=area, type="wg", state="active").order_by("acronym")
352343
area.urls = area.groupextresource_set.all().order_by("name")
353344
for group in area.groups:
354345
group.chairs = sorted(roles(group, "chair"), key=extract_last_name)
355-
group.ad_out_of_area = group.ad_role() and group.ad_role().person not in [role.person for role in area.ads]
346+
group.ad_out_of_area = group.ad_role() and group.ad_role().person not in [role.person for role in area.ads_and_pre_ads]
356347
# get the url for mailing list subscription
357348
if group.list_subscribe.startswith('http'):
358349
group.list_subscribe_url = group.list_subscribe
@@ -378,7 +369,6 @@ def active_ags(request):
378369
groups = Group.objects.filter(type="ag", state="active").order_by("acronym")
379370
for group in groups:
380371
group.chairs = sorted(roles(group, "chair"), key=extract_last_name)
381-
group.ads = sorted(roles(group, "ad"), key=extract_last_name)
382372

383373
return render(request, 'group/active_ags.html', { 'groups': groups })
384374

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Generated by Django 2.2.17 on 2020-11-23 09:54
2+
3+
from django.db import migrations
4+
5+
6+
def forward(apps, schema_editor):
7+
"""Add new MailTrigger and Recipients, remove the one being replaced"""
8+
MailTrigger = apps.get_model('mailtrigger', 'MailTrigger')
9+
Recipient = apps.get_model('mailtrigger', 'Recipient')
10+
11+
MailTrigger.objects.create(
12+
slug='sub_director_approval_requested',
13+
desc='Recipients for a message requesting AD approval of a revised draft submission',
14+
).to.add(
15+
Recipient.objects.create(
16+
pk='sub_group_parent_directors',
17+
desc="ADs for the parent group of a submission"
18+
)
19+
)
20+
21+
MailTrigger.objects.create(
22+
slug='sub_replaced_doc_chair_approval_requested',
23+
desc='Recipients for a message requesting chair approval of a replaced WG document',
24+
).to.add(
25+
Recipient.objects.get(pk='doc_group_chairs')
26+
)
27+
28+
MailTrigger.objects.create(
29+
slug='sub_replaced_doc_director_approval_requested',
30+
desc='Recipients for a message requesting AD approval of a replaced WG document',
31+
).to.add(
32+
Recipient.objects.create(
33+
pk='doc_group_parent_directors',
34+
desc='ADs for the parent group of a doc'
35+
)
36+
)
37+
38+
39+
def reverse(apps, schema_editor):
40+
"""Remove the MailTrigger and Recipient created in the forward migration"""
41+
MailTrigger = apps.get_model('mailtrigger', 'MailTrigger')
42+
MailTrigger.objects.filter(slug='sub_director_approval_requested').delete()
43+
MailTrigger.objects.filter(slug='sub_replaced_doc_chair_approval_requested').delete()
44+
MailTrigger.objects.filter(slug='sub_replaced_doc_director_approval_requested').delete()
45+
Recipient = apps.get_model('mailtrigger', 'Recipient')
46+
Recipient.objects.filter(pk='sub_group_parent_directors').delete()
47+
Recipient.objects.filter(pk='doc_group_parent_directors').delete()
48+
49+
50+
class Migration(migrations.Migration):
51+
52+
dependencies = [
53+
('mailtrigger', '0018_interim_approve_announce'),
54+
]
55+
56+
operations = [
57+
migrations.RunPython(forward, reverse)
58+
]

ietf/mailtrigger/models.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,27 @@ def gather_submission_group_chairs(self, **kwargs):
242242
addrs.extend(Recipient.objects.get(slug='group_chairs').gather(**{'group':submission.group}))
243243
return addrs
244244

245+
def gather_sub_group_parent_directors(self, **kwargs):
246+
addrs = []
247+
if 'submission' in kwargs:
248+
submission = kwargs['submission']
249+
if submission.group and submission.group.parent:
250+
addrs.extend(
251+
Recipient.objects.get(
252+
slug='group_responsible_directors').gather(group=submission.group.parent)
253+
)
254+
return addrs
255+
256+
def gather_doc_group_parent_directors(self, **kwargs):
257+
addrs = []
258+
doc = kwargs.get('doc')
259+
if doc and doc.group and doc.group.parent:
260+
addrs.extend(
261+
Recipient.objects.get(
262+
slug='group_responsible_directors').gather(group=doc.group.parent)
263+
)
264+
return addrs
265+
245266
def gather_submission_confirmers(self, **kwargs):
246267
"""If a submitted document is revising an existing document, the confirmers
247268
are the authors of that existing document, and the chairs if the document is

0 commit comments

Comments
 (0)