Skip to content

Commit 567449d

Browse files
committed
Merged in [17908] from rjsparks@nostrum.com:
Add used_roles to Group and default_used_roles to GroupFeatures. Dynamically build the group edit form to provide a field for all used_roles. Fixes ietf-tools#2785 and ietf-tools#2572. Partially addresses ietf-tools#2160. - Legacy-Id: 17960 Note: SVN reference [17908] has been migrated to Git commit 2862727
2 parents 980de4f + 2862727 commit 567449d

File tree

8 files changed

+137
-36
lines changed

8 files changed

+137
-36
lines changed

ietf/group/forms.py

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,32 +11,24 @@
1111
# Django imports
1212
from django import forms
1313
from django.utils.html import mark_safe # type:ignore
14+
from django.db.models import F
1415

1516
# IETF imports
16-
from ietf.group.models import Group, GroupHistory, GroupStateName
17-
from ietf.name.models import ReviewTypeName
17+
from ietf.group.models import Group, GroupHistory, GroupStateName, GroupFeatures
18+
from ietf.name.models import ReviewTypeName, RoleName
1819
from ietf.person.fields import SearchableEmailsField, PersonEmailChoiceField
19-
from ietf.person.models import Person
20+
from ietf.person.models import Person, Email
2021
from ietf.review.models import ReviewerSettings, UnavailablePeriod, ReviewSecretarySettings
2122
from ietf.review.policies import get_reviewer_queue_policy
2223
from ietf.review.utils import close_review_request_states
2324
from ietf.utils.textupload import get_cleaned_text_file_content
24-
from ietf.utils.text import strip_suffix
2525
#from ietf.utils.ordereddict import insert_after_in_ordered_dict
2626
from ietf.utils.fields import DatepickerDateField, MultiEmailField
2727

2828
# --- Constants --------------------------------------------------------
2929

3030
MAX_GROUP_DELEGATES = 3
3131

32-
# --- Utility Functions ------------------------------------------------
33-
34-
def roles_for_group_type(group_type):
35-
roles = ["chair", "secr", "techadv", "delegate", ]
36-
if group_type == "review":
37-
roles.append("reviewer")
38-
return roles
39-
4032
# --- Forms ------------------------------------------------------------
4133

4234
class StatusUpdateForm(forms.Form):
@@ -65,14 +57,7 @@ class GroupForm(forms.Form):
6557
name = forms.CharField(max_length=80, label="Name", required=True)
6658
acronym = forms.CharField(max_length=40, label="Acronym", required=True)
6759
state = forms.ModelChoiceField(GroupStateName.objects.all(), label="State", required=True)
68-
69-
# roles
70-
chair_roles = SearchableEmailsField(label="Chairs", required=False, only_users=True)
71-
secr_roles = SearchableEmailsField(label="Secretaries", required=False, only_users=True)
72-
techadv_roles = SearchableEmailsField(label="Technical Advisors", required=False, only_users=True)
73-
delegate_roles = SearchableEmailsField(label="Delegates", required=False, only_users=True, max_entries=MAX_GROUP_DELEGATES,
74-
help_text=mark_safe("Chairs can delegate the authority to update the state of group documents - at most %s persons at a given time." % MAX_GROUP_DELEGATES))
75-
reviewer_roles = SearchableEmailsField(label="Reviewers", required=False, only_users=True)
60+
# Note that __init__ will add role fields here
7661
ad = forms.ModelChoiceField(Person.objects.filter(role__name="ad", role__group__state="active", role__group__type='area').order_by('name'), label="Shepherding AD", empty_label="(None)", required=False)
7762

7863
parent = forms.ModelChoiceField(Group.objects.filter(state="active").order_by('name'), empty_label="(None)", required=False)
@@ -85,16 +70,39 @@ class GroupForm(forms.Form):
8570
def __init__(self, *args, **kwargs):
8671
self.group = kwargs.pop('group', None)
8772
self.group_type = kwargs.pop('group_type', False)
73+
if self.group:
74+
self.used_roles = self.group.used_roles or self.group.features.default_used_roles
75+
else:
76+
self.used_roles = GroupFeatures.objects.get(type=self.group_type).default_used_roles
8877
if "field" in kwargs:
8978
field = kwargs["field"]
9079
del kwargs["field"]
91-
if field in roles_for_group_type(self.group_type):
80+
if field in self.used_roles:
9281
field = field + "_roles"
9382
else:
9483
field = None
9584

9685
super(self.__class__, self).__init__(*args, **kwargs)
9786

87+
for role_slug in self.used_roles:
88+
role_name = RoleName.objects.get(slug=role_slug)
89+
fieldname = '%s_roles'%role_slug
90+
field_args = {
91+
'label' : role_name.name,
92+
'required' : False,
93+
'only_users' : True,
94+
}
95+
if fieldname == 'delegate_roles':
96+
field_args['max_entries'] = MAX_GROUP_DELEGATES
97+
field_args['help_text'] = mark_safe("Chairs can delegate the authority to update the state of group documents - at most %s persons at a given time." % MAX_GROUP_DELEGATES)
98+
self.fields[fieldname] = SearchableEmailsField(**field_args)
99+
self.fields[fieldname].initial = Email.objects.filter(person__role__name_id=role_slug,person__role__group=self.group,person__role__email__pk=F('pk')).distinct()
100+
101+
self.adjusted_field_order = ['name','acronym','state']
102+
for role_slug in self.used_roles:
103+
self.adjusted_field_order.append('%s_roles'%role_slug)
104+
self.order_fields(self.adjusted_field_order)
105+
98106
if self.group_type == "rg":
99107
self.fields["state"].queryset = self.fields["state"].queryset.exclude(slug__in=("bof", "bof-conc"))
100108

@@ -116,10 +124,6 @@ def __init__(self, *args, **kwargs):
116124
self.fields['parent'].queryset = self.fields['parent'].queryset.filter(type="area")
117125
self.fields['parent'].label = "IETF Area"
118126

119-
role_fields_to_remove = (set(strip_suffix(attr, "_roles") for attr in self.fields if attr.endswith("_roles"))
120-
- set(roles_for_group_type(self.group_type)))
121-
for r in role_fields_to_remove:
122-
del self.fields[r + "_roles"]
123127
if field:
124128
keys = list(self.fields.keys())
125129
for f in keys:
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Generated by Django 2.0.13 on 2020-05-22 12:00
2+
3+
from django.db import migrations
4+
import jsonfield.fields
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('group', '0028_add_robots'),
11+
]
12+
13+
operations = [
14+
migrations.AddField(
15+
model_name='group',
16+
name='used_roles',
17+
field=jsonfield.fields.JSONField(default=[], help_text="Leave an empty list to get the group_type's default used roles", max_length=128),
18+
),
19+
migrations.AddField(
20+
model_name='groupfeatures',
21+
name='default_used_roles',
22+
field=jsonfield.fields.JSONField(default=[], max_length=128),
23+
),
24+
migrations.AddField(
25+
model_name='grouphistory',
26+
name='used_roles',
27+
field=jsonfield.fields.JSONField(default=[], help_text="Leave an empty list to get the group_type's default used roles", max_length=128),
28+
),
29+
migrations.AddField(
30+
model_name='historicalgroupfeatures',
31+
name='default_used_roles',
32+
field=jsonfield.fields.JSONField(default=[], max_length=128),
33+
),
34+
]
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Generated by Django 2.0.13 on 2020-05-22 11:41
2+
3+
from django.db import migrations
4+
5+
grouptype_defaults = {
6+
'adhoc': ['matman', 'ad', 'chair', 'lead'],
7+
'admin': ['member', 'chair'],
8+
'ag': ['ad', 'chair', 'secr'],
9+
'area': ['ad'],
10+
'dir': ['ad', 'chair', 'reviewer', 'secr'],
11+
'review': ['ad', 'chair', 'reviewer', 'secr'],
12+
'iab': ['chair'],
13+
'iana': ['auth'],
14+
'iesg': [],
15+
'ietf': ['ad', 'member', 'comdir', 'delegate', 'execdir', 'recman', 'secr', 'trac-editor', 'trac-admin', 'chair'],
16+
'individ': ['ad'],
17+
'irtf': ['member', 'atlarge', 'chair'],
18+
'ise': ['chair'],
19+
'isoc': ['chair', 'ceo'],
20+
'nomcom': ['member', 'advisor', 'liaison', 'chair', 'techadv'],
21+
'program': ['member', 'chair', 'lead'],
22+
'rfcedtyp': ['auth', 'chair'],
23+
'rg': ['chair', 'techadv', 'secr', 'delegate'],
24+
'sdo': ['liaiman', 'ceo', 'coord', 'auth', 'chair'],
25+
'team': ['ad', 'member', 'delegate', 'secr', 'liaison', 'atlarge', 'chair', 'matman', 'techadv'],
26+
'wg': ['ad', 'editor', 'delegate', 'secr', 'chair', 'matman', 'techadv'],
27+
}
28+
29+
def forward(apps, schema_editor):
30+
GroupFeatures = apps.get_model('group','GroupFeatures')
31+
for type_id, roles in grouptype_defaults.items():
32+
GroupFeatures.objects.filter(type_id=type_id).update(default_used_roles=roles)
33+
34+
def reverse(apps, schema_editor):
35+
pass # intentional
36+
37+
class Migration(migrations.Migration):
38+
39+
dependencies = [
40+
('group', '0029_add_used_roles_and_default_used_roles'),
41+
('stats', '0003_meetingregistration_attended'),
42+
]
43+
44+
operations = [
45+
migrations.RunPython(forward, reverse),
46+
]

ietf/group/models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class GroupInfo(models.Model):
4343
unused_states = models.ManyToManyField('doc.State', help_text="Document states that have been disabled for the group.", blank=True)
4444
unused_tags = models.ManyToManyField(DocTagName, help_text="Document tags that have been disabled for the group.", blank=True)
4545

46+
used_roles = jsonfield.JSONField(max_length=128, blank=False, default=[], help_text="Leave an empty list to get the group_type's default used roles")
47+
4648
uses_milestone_dates = models.BooleanField(default=True)
4749

4850
def __str__(self):
@@ -232,6 +234,7 @@ class GroupFeatures(models.Model):
232234
about_page = models.CharField(max_length=64, blank=False, default="ietf.group.views.group_about" )
233235
default_tab = models.CharField(max_length=64, blank=False, default="ietf.group.views.group_about" )
234236
material_types = jsonfield.JSONField(max_length=64, blank=False, default=["slides"])
237+
default_used_roles = jsonfield.JSONField(max_length=128, blank=False, default=[])
235238
admin_roles = jsonfield.JSONField(max_length=64, blank=False, default=["chair"]) # Trac Admin
236239
docman_roles = jsonfield.JSONField(max_length=128, blank=False, default=["ad","chair","delegate","secr"])
237240
groupman_roles = jsonfield.JSONField(max_length=128, blank=False, default=["ad","chair",])

ietf/group/tests_info.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,8 @@ def test_edit_info(self):
567567
q = PyQuery(r.content)
568568
self.assertEqual(len(q('form select[name=parent]')), 1)
569569
self.assertEqual(len(q('form input[name=acronym]')), 1)
570+
for role_slug in group.used_roles or group.features.default_used_roles:
571+
self.assertEqual(len(q('form input[name=%s_roles]'%role_slug)),1)
570572

571573
# faulty post
572574
Group.objects.create(name="Collision Test Group", acronym="collide")

ietf/group/views.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -128,14 +128,6 @@
128128
def roles(group, role_name):
129129
return Role.objects.filter(group=group, name=role_name).select_related("email", "person")
130130

131-
def roles_for_group_type(group_type):
132-
roles = ["chair", "secr", "techadv", "delegate", ]
133-
if group_type == "review":
134-
roles.append("reviewer")
135-
return roles
136-
137-
138-
139131

140132
def fill_in_charter_info(group, include_drafts=False):
141133
group.areadirector = getattr(group.ad_role(),'email',None)
@@ -546,7 +538,7 @@ def group_about(request, acronym, group_type=None):
546538
"can_provide_status_update": can_provide_update,
547539
"status_update": status_update,
548540
"charter_submit_url": charter_submit_url,
549-
"editable_roles": roles_for_group_type(group_type),
541+
"editable_roles": group.used_roles or group.features.default_used_roles,
550542
"closing_note": e,
551543
}))
552544

@@ -1076,8 +1068,6 @@ def diff(attr, name):
10761068
closing_note = closing_note,
10771069
)
10781070

1079-
for slug in roles_for_group_type(group_type):
1080-
init[slug + "_roles"] = Email.objects.filter(role__group=group, role__name=slug).order_by('role__person__name')
10811071
else:
10821072
init = dict(ad=request.user.person.id if group_type == "wg" and has_role(request.user, "Area Director") else None,
10831073
)

0 commit comments

Comments
 (0)