Skip to content

Commit 2ab4caa

Browse files
committed
Merged in [12722] from rjsparks@nostrum.com:
Added programs to the datatracker. Added use of restructuredtext for group about pages. Generalized several places where code handles different group types. Improved testing of group about. - Legacy-Id: 12725 Note: SVN reference [12722] has been migrated to Git commit e0ea8b0
2 parents 79c44d2 + e0ea8b0 commit 2ab4caa

16 files changed

Lines changed: 894 additions & 68 deletions

File tree

ietf/community/tests.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
from ietf.utils.test_data import make_test_data
1717
from ietf.utils.test_utils import login_testing_unauthorized, TestCase
1818
from ietf.utils.mail import outbox
19+
from ietf.group.factories import GroupFactory
20+
from ietf.person.factories import PersonFactory
1921

2022
class CommunityListTests(TestCase):
2123
def test_rule_matching(self):
@@ -158,6 +160,19 @@ def test_manage_group_list(self):
158160
r = self.client.get(url)
159161
self.assertEqual(r.status_code, 200)
160162

163+
# Verify GET also works with non-WG and RG groups
164+
for gtype in ['area','program']:
165+
g = GroupFactory.create(type_id=gtype)
166+
# make sure the group's features have been initialized to improve coverage
167+
_ = g.features # pyflakes:ignore
168+
p = PersonFactory()
169+
g.role_set.create(name_id={'area':'ad','program':'lead'}[gtype],person=p, email=p.email())
170+
url = urlreverse(ietf.community.views.manage_list, kwargs={ "acronym": g.acronym })
171+
setup_default_community_list_for_group(g)
172+
self.client.login(username=p.user.username,password=p.user.username+"+password")
173+
r = self.client.get(url)
174+
self.assertEqual(r.status_code, 200)
175+
161176
def test_track_untrack_document(self):
162177
draft = make_test_data()
163178

ietf/community/utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ def can_manage_community_list(user, clist):
4949
return Role.objects.filter(name__slug='ad', person__user=user, group=clist.group).exists()
5050
elif clist.group.type_id in ('wg', 'rg'):
5151
return Role.objects.filter(name__slug='chair', person__user=user, group=clist.group).exists()
52+
elif clist.group.type_id in ('program'):
53+
return Role.objects.filter(name__slug='lead', person__user=user, group=clist.group).exists()
5254

5355
return False
5456

ietf/doc/templatetags/active_groups_menu.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
@register.simple_tag
99
def active_groups_menu():
10-
parents = GroupTypeName.objects.filter(slug__in=['ag','area','team','dir'])
10+
parents = GroupTypeName.objects.filter(slug__in=['ag','area','team','dir','program'])
1111
for p in parents:
1212
p.menu_url = '/%s/'%p.slug
1313
return render_to_string('base/menu_active_groups.html', { 'parents': parents })

ietf/group/features.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ class GroupFeatures(object):
55
has_milestones = False
66
has_chartering_process = False
77
has_documents = False # i.e. drafts/RFCs
8+
has_dependencies = False # Do dependency graphs for group documents make sense?
89
has_materials = False
910
has_reviews = False
11+
has_default_jabber = False
1012
customize_workflow = False
1113
about_page = "group_about"
1214
default_tab = about_page
@@ -19,10 +21,18 @@ def __init__(self, group):
1921
self.has_chartering_process = True
2022
self.has_documents = True
2123
self.customize_workflow = True
24+
self.has_default_jabber = True
25+
self.has_dependencies = True
2226
self.default_tab = "group_docs"
2327
elif group.type_id in ("team",):
2428
self.has_materials = True
2529
self.default_tab = "group_about"
30+
elif group.type_id in ("program",):
31+
self.has_documents = True
32+
self.has_milestones = True
33+
self.admin_roles = ["lead",]
34+
elif group.type_id == "dir":
35+
self.admin_roles = ["chair", "secr"]
2636

2737
if self.has_chartering_process:
2838
self.about_page = "group_charter"
@@ -33,5 +43,3 @@ def __init__(self, group):
3343
import ietf.group.views
3444
self.default_tab = ietf.group.views_review.review_requests
3545

36-
if group.type_id == "dir":
37-
self.admin_roles = ["chair", "secr"]

ietf/group/migrations/0010_iab_programs.py

Lines changed: 689 additions & 0 deletions
Large diffs are not rendered by default.

ietf/group/milestones.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ def edit_milestones(request, acronym, group_type=None, milestone_set="current"):
101101
if milestone_set == "current":
102102
needs_review = True
103103
else:
104-
return HttpResponseForbidden("You don't have permission to access this view")
104+
return HttpResponseForbidden("You are not authorized to edit the milestones of this group.")
105105

106106
if milestone_set == "current":
107107
title = "Edit milestones for %s %s" % (group.acronym, group.type.name)
@@ -333,7 +333,7 @@ def reset_charter_milestones(request, group_type, acronym):
333333
raise Http404
334334

335335
if not can_manage_group(request.user, group):
336-
return HttpResponseForbidden("You don't have permission to access this view")
336+
return HttpResponseForbidden("You are not authorized to change the milestones for this group.")
337337

338338
current_milestones = group.groupmilestone_set.filter(state="active")
339339
charter_milestones = group.groupmilestone_set.filter(state="charter")

ietf/group/tests_info.py

Lines changed: 71 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@
2828
from ietf.meeting.factories import SessionFactory
2929
from ietf.name.models import DocTagName, GroupStateName, GroupTypeName
3030
from ietf.person.models import Person, Email
31+
from ietf.person.factories import PersonFactory
3132
from ietf.utils.mail import outbox, empty_outbox
32-
from ietf.utils.test_data import make_test_data, create_person, make_review_data
33+
from ietf.utils.test_data import make_test_data, make_review_data
3334
from ietf.utils.test_utils import login_testing_unauthorized, TestCase, unicontent, reload_db_objects
3435

3536
def group_urlreverse_list(group, viewname):
@@ -62,30 +63,15 @@ def test_active_groups(self):
6263
self.assertTrue(group.name in unicontent(r))
6364
self.assertTrue(group.ad_role().person.plain_name() in unicontent(r))
6465

65-
url = urlreverse('ietf.group.views.active_groups', kwargs=dict(group_type="rg"))
66-
r = self.client.get(url)
67-
self.assertEqual(r.status_code, 200)
68-
self.assertTrue('Active research groups' in unicontent(r))
69-
70-
url = urlreverse('ietf.group.views.active_groups', kwargs=dict(group_type="area"))
71-
r = self.client.get(url)
72-
self.assertEqual(r.status_code, 200)
73-
self.assertTrue("Far Future (farfut)" in unicontent(r))
74-
75-
url = urlreverse('ietf.group.views.active_groups', kwargs=dict(group_type="ag"))
76-
r = self.client.get(url)
77-
self.assertEqual(r.status_code, 200)
78-
self.assertTrue("Active area groups" in unicontent(r))
79-
80-
url = urlreverse('ietf.group.views.active_groups', kwargs=dict(group_type="dir"))
81-
r = self.client.get(url)
82-
self.assertEqual(r.status_code, 200)
83-
self.assertTrue("Active directorates" in unicontent(r))
84-
85-
url = urlreverse('ietf.group.views.active_groups', kwargs=dict(group_type="team"))
86-
r = self.client.get(url)
87-
self.assertEqual(r.status_code, 200)
88-
self.assertTrue("Active teams" in unicontent(r))
66+
for t in ('rg','area','ag','dir','team','program'):
67+
g = GroupFactory.create(type_id=t,state_id='active')
68+
if t=='dir':
69+
g.parent = GroupFactory.create(type_id='area',state_id='active')
70+
g.save()
71+
url = urlreverse('ietf.group.views.active_groups', kwargs=dict(group_type=t))
72+
r = self.client.get(url)
73+
self.assertEqual(r.status_code, 200)
74+
self.assertTrue(g.acronym in unicontent(r))
8975

9076
url = urlreverse('ietf.group.views.active_groups', kwargs=dict())
9177
r = self.client.get(url)
@@ -269,42 +255,72 @@ def test_group_charter(self):
269255

270256
def test_group_about(self):
271257

272-
def verify_cannot_edit_group(url, username):
273-
self.client.login(username=username, password=username+"+password")
274-
r = self.client.get(url)
275-
self.assertEqual(r.status_code, 403)
258+
make_test_data()
276259

277-
def verify_can_edit_group(url, username):
278-
self.client.login(username=username, password=username+"+password")
279-
r = self.client.get(url)
280-
self.assertEqual(r.status_code, 200)
260+
p = PersonFactory(user__username='iab-member')
261+
Group.objects.get(acronym='iab').role_set.create(name_id='member',person=p,email=p.email())
281262

282-
make_test_data()
283-
group = Group.objects.create(
284-
type_id="team",
285-
acronym="testteam",
286-
name="Test Team",
287-
description="The test team is testing.",
288-
state_id="active",
289-
parent = Group.objects.get(acronym="farfut"),
290-
)
291-
create_person(group, "chair", name="Testteam Chairman", username="teamchairman")
263+
interesting_users = [ 'plain','iana','iab-chair','irtf-chair', 'marschairman', 'teamchairman','ad', 'iab-member', 'secretary', ]
292264

293-
for url in [group.about_url(),] + group_urlreverse_list(group, 'ietf.group.views.group_about'):
294-
url = group.about_url()
295-
r = self.client.get(url)
296-
self.assertEqual(r.status_code, 200)
297-
self.assertTrue(group.name in unicontent(r))
298-
self.assertTrue(group.acronym in unicontent(r))
299-
self.assertTrue(group.description in unicontent(r))
265+
can_edit = {
266+
'wg' : ['secretary','ad'],
267+
'rg' : ['secretary','irtf-chair'],
268+
'ag' : ['secretary', ],
269+
'team' : ['secretary',], # The code currently doesn't let ads edit teams or directorates. Maybe it should.
270+
'dir' : ['secretary',],
271+
'program' : ['secretary', 'iab-member'],
272+
}
300273

301-
for url in group_urlreverse_list(group, 'ietf.group.views_edit.edit'):
274+
def setup_role(group, role_id):
275+
p = PersonFactory(user__username="%s_%s"%(group.acronym,role_id))
276+
group.role_set.create(name_id=role_id,person=p,email=p.email())
277+
can_edit[group.type_id].append(p.user.username)
278+
interesting_users.append(p.user.username)
302279

303-
for username in ['plain','iana','iab chair','irtf chair','marschairman']:
304-
verify_cannot_edit_group(url, username)
280+
test_groups = []
305281

306-
for username in ['secretary','teamchairman','ad']:
307-
verify_can_edit_group(url, username)
282+
for t in ['wg','rg','ag','team']:
283+
g = GroupFactory(type_id=t)
284+
setup_role(g,'chair')
285+
test_groups.append(g)
286+
287+
g = GroupFactory(type_id='dir')
288+
setup_role(g,'secr')
289+
test_groups.append(g)
290+
291+
g = GroupFactory(type_id='program')
292+
setup_role(g, 'lead')
293+
test_groups.append(g)
294+
295+
def verify_cannot_edit_group(url, group, username):
296+
self.client.logout()
297+
self.client.login(username=username, password=username+"+password")
298+
r = self.client.get(url)
299+
self.assertTrue(r.status_code in (302,403),"%s should not be able to edit %s of type %s"%(username,group.acronym,group.type_id))
300+
301+
def verify_can_edit_group(url, group, username):
302+
self.client.logout()
303+
self.client.login(username=username, password=username+"+password")
304+
r = self.client.get(url)
305+
self.assertEqual(r.status_code, 200, "%s should be able to edit %s of type %s"%(username,group.acronym,group.type_id))
306+
307+
for group in test_groups:
308+
309+
for url in [group.about_url(),] + group_urlreverse_list(group, 'ietf.group.views.group_about'):
310+
url = group.about_url()
311+
r = self.client.get(url)
312+
self.assertEqual(r.status_code, 200)
313+
self.assertTrue(group.name in unicontent(r))
314+
self.assertTrue(group.acronym in unicontent(r))
315+
self.assertTrue(group.description in unicontent(r))
316+
317+
for url in group_urlreverse_list(group, 'ietf.group.views_edit.edit'):
318+
319+
for username in can_edit[group.type_id]:
320+
verify_can_edit_group(url, group, username)
321+
322+
for username in list(set(interesting_users)-set(can_edit[group.type_id])):
323+
verify_cannot_edit_group(url, group, username)
308324

309325
def test_materials(self):
310326
make_test_data()

ietf/group/utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ def can_manage_group_type(user, group):
9999
return has_role(user, ('Area Director', 'Secretariat'))
100100
elif group.is_decendant_of("irtf"):
101101
return has_role(user, ('IRTF Chair', 'Secretariat'))
102+
elif group.type_id == "program":
103+
return has_role(user, ('IAB', 'Secretariat',))
102104
return has_role(user, ('Secretariat'))
103105

104106
def can_manage_group(user, group):

ietf/group/views.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,11 +219,13 @@ def active_groups(request, group_type=None):
219219
return active_teams(request)
220220
elif group_type == "dir":
221221
return active_dirs(request)
222+
elif group_type == "program":
223+
return active_programs(request)
222224
else:
223225
raise Http404
224226

225227
def active_group_types(request):
226-
grouptypes = GroupTypeName.objects.filter(slug__in=['wg','rg','ag','team','dir','area'])
228+
grouptypes = GroupTypeName.objects.filter(slug__in=['wg','rg','ag','team','dir','area','program'])
227229
return render(request, 'group/active_groups.html', {'grouptypes':grouptypes})
228230

229231
def active_dirs(request):
@@ -240,6 +242,12 @@ def active_teams(request):
240242
group.chairs = sorted(roles(group, "chair"), key=extract_last_name)
241243
return render(request, 'group/active_teams.html', {'teams' : teams })
242244

245+
def active_programs(request):
246+
programs = Group.objects.filter(type="program", state="active").order_by("name")
247+
for group in programs:
248+
group.leads = sorted(roles(group, "lead"), key=extract_last_name)
249+
return render(request, 'group/active_programs.html', {'programs' : programs })
250+
243251
def active_areas(request):
244252
areas = Group.objects.filter(type="area", state="active").order_by("name")
245253
return render(request, 'group/active_areas.html', {'areas': areas })

ietf/group/views_edit.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,11 @@ def conclude(request, acronym, group_type=None):
416416
e.desc = "Requested closing group"
417417
e.save()
418418

419-
return redirect(group.features.about_page, group_type=group_type, acronym=group.acronym)
419+
kwargs = {'acronym':group.acronym}
420+
if group_type:
421+
kwargs['group_type'] = group_type
422+
423+
return redirect(group.features.about_page, **kwargs)
420424
else:
421425
form = ConcludeForm()
422426

0 commit comments

Comments
 (0)