Skip to content

Commit 9a9f3fa

Browse files
committed
Merged in [18798] from jennifer@painless-security.com:
Improve handling of submissions for closed working groups. Fixes ietf-tools#3058. - Legacy-Id: 18807 Note: SVN reference [18798] has been migrated to Git commit 233bff8
2 parents 7c1f28c + 233bff8 commit 9a9f3fa

14 files changed

Lines changed: 872 additions & 121 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', '0019_email_iana_expert_review_state_changed'),
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

ietf/name/fixtures/names.json

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4890,6 +4890,17 @@
48904890
"model": "mailtrigger.mailtrigger",
48914891
"pk": "sub_confirmation_requested"
48924892
},
4893+
{
4894+
"fields": {
4895+
"cc": [],
4896+
"desc": "Recipients for a message requesting AD approval of a revised draft submission",
4897+
"to": [
4898+
"sub_group_parent_directors"
4899+
]
4900+
},
4901+
"model": "mailtrigger.mailtrigger",
4902+
"pk": "sub_director_approval_requested"
4903+
},
48934904
{
48944905
"fields": {
48954906
"cc": [],
@@ -4942,6 +4953,28 @@
49424953
"model": "mailtrigger.mailtrigger",
49434954
"pk": "sub_new_wg_00"
49444955
},
4956+
{
4957+
"fields": {
4958+
"cc": [],
4959+
"desc": "Recipients for a message requesting chair approval of a replaced WG document",
4960+
"to": [
4961+
"doc_group_chairs"
4962+
]
4963+
},
4964+
"model": "mailtrigger.mailtrigger",
4965+
"pk": "sub_replaced_doc_chair_approval_requested"
4966+
},
4967+
{
4968+
"fields": {
4969+
"cc": [],
4970+
"desc": "Recipients for a message requesting AD approval of a replaced WG document",
4971+
"to": [
4972+
"doc_group_parent_directors"
4973+
]
4974+
},
4975+
"model": "mailtrigger.mailtrigger",
4976+
"pk": "sub_replaced_doc_director_approval_requested"
4977+
},
49454978
{
49464979
"fields": {
49474980
"desc": "The person providing a comment to nomcom",
@@ -5046,6 +5079,14 @@
50465079
"model": "mailtrigger.recipient",
50475080
"pk": "doc_group_mail_list"
50485081
},
5082+
{
5083+
"fields": {
5084+
"desc": "ADs for the parent group of a doc",
5085+
"template": null
5086+
},
5087+
"model": "mailtrigger.recipient",
5088+
"pk": "doc_group_parent_directors"
5089+
},
50495090
{
50505091
"fields": {
50515092
"desc": "The document's group's responsible AD(s) or IRTF chair",
@@ -5534,6 +5575,14 @@
55345575
"model": "mailtrigger.recipient",
55355576
"pk": "stream_managers"
55365577
},
5578+
{
5579+
"fields": {
5580+
"desc": "ADs for the parent group of a submission",
5581+
"template": null
5582+
},
5583+
"model": "mailtrigger.recipient",
5584+
"pk": "sub_group_parent_directors"
5585+
},
55375586
{
55385587
"fields": {
55395588
"desc": "The authors of a submitted draft",
@@ -9702,6 +9751,20 @@
97029751
"model": "name.docurltagname",
97039752
"pk": "yang-module-metadata"
97049753
},
9754+
{
9755+
"fields": {
9756+
"desc": "",
9757+
"name": "Awaiting AD Approval",
9758+
"next_states": [
9759+
"cancel",
9760+
"posted"
9761+
],
9762+
"order": 5,
9763+
"used": true
9764+
},
9765+
"model": "name.draftsubmissionstatename",
9766+
"pk": "ad-appr"
9767+
},
97059768
{
97069769
"fields": {
97079770
"desc": "",
@@ -9737,7 +9800,7 @@
97379800
"desc": "",
97389801
"name": "Cancelled",
97399802
"next_states": [],
9740-
"order": 6,
9803+
"order": 7,
97419804
"used": true
97429805
},
97439806
"model": "name.draftsubmissionstatename",
@@ -9779,7 +9842,7 @@
97799842
"cancel",
97809843
"posted"
97819844
],
9782-
"order": 5,
9845+
"order": 6,
97839846
"used": true
97849847
},
97859848
"model": "name.draftsubmissionstatename",
@@ -9790,7 +9853,7 @@
97909853
"desc": "",
97919854
"name": "Posted",
97929855
"next_states": [],
9793-
"order": 7,
9856+
"order": 8,
97949857
"used": true
97959858
},
97969859
"model": "name.draftsubmissionstatename",
@@ -9821,7 +9884,7 @@
98219884
"cancel",
98229885
"posted"
98239886
],
9824-
"order": 8,
9887+
"order": 9,
98259888
"used": true
98269889
},
98279890
"model": "name.draftsubmissionstatename",

0 commit comments

Comments
 (0)