The secretariat and the Team Chair can now edit team groups. In addition, if the team in within the IETF, Area Directors can edit it. And, if the team is within the IRTF, the IRTF Chair can edit it. Fixes #1915.

- Legacy-Id: 11064
This commit is contained in:
Russ Housley 2016-04-02 15:10:10 +00:00
parent 9f90441aa6
commit 1c509cd64c
5 changed files with 54 additions and 9 deletions

View file

@ -16,7 +16,7 @@ from ietf.doc.utils import get_tags_for_stream_id
from ietf.doc.utils_charter import charter_name_for_group
from ietf.group.models import ( Group, Role, GroupEvent, GroupHistory, GroupStateName,
GroupStateTransitions, GroupTypeName, GroupURL, ChangeStateGroupEvent )
from ietf.group.utils import save_group_in_history, can_manage_group_type
from ietf.group.utils import save_group_in_history, can_manage_group_type, can_manage_team_group
from ietf.group.utils import get_group_or_404
from ietf.ietfauth.utils import has_role
from ietf.person.fields import SearchableEmailsField
@ -199,11 +199,19 @@ def submit_initial_charter(request, group_type=None, acronym=None):
def edit(request, group_type=None, acronym=None, action="edit"):
"""Edit or create a group, notifying parties as
necessary and logging changes as group events."""
if not can_manage_group_type(request.user, group_type):
group = get_group_or_404(acronym, group_type)
if not group_type and group:
group_type = group.type_id
if group_type == "team":
can_edit = can_manage_team_group(request.user, group) or group.has_role(request.user, "chair")
else:
can_edit = can_manage_group_type(request.user, group_type)
if not can_edit:
return HttpResponseForbidden("You don't have permission to access this view")
if action == "edit":
group = get_object_or_404(Group, acronym=acronym)
new_group = False
elif action in ("create","charter"):
group = None
@ -211,9 +219,6 @@ def edit(request, group_type=None, acronym=None, action="edit"):
else:
raise Http404
if not group_type and group:
group_type = group.type_id
if request.method == 'POST':
form = GroupForm(request.POST, group=group, group_type=group_type)
if form.is_valid():

View file

@ -55,7 +55,7 @@ from ietf.doc.utils import get_chartering_type
from ietf.doc.templatetags.ietf_filters import clean_whitespace
from ietf.group.models import Group, Role, ChangeStateGroupEvent
from ietf.name.models import GroupTypeName
from ietf.group.utils import get_charter_text, can_manage_group_type, milestone_reviewer_for_group_type, can_provide_status_update
from ietf.group.utils import get_charter_text, can_manage_group_type, can_manage_team_group, milestone_reviewer_for_group_type, can_provide_status_update
from ietf.group.utils import can_manage_materials, get_group_or_404
from ietf.utils.pipe import pipe
from ietf.utils.textupload import get_cleaned_text_file_content
@ -366,6 +366,8 @@ def construct_group_menu_context(request, group, selected, group_type, others):
is_chair = group.has_role(request.user, "chair")
can_manage = can_manage_group_type(request.user, group.type_id)
if group.type_id == "team":
can_manage = can_manage_team_group(request.user, group)
if group.features.has_milestones:
if group.state_id != "proposed" and (is_chair or can_manage):
@ -374,7 +376,7 @@ def construct_group_menu_context(request, group, selected, group_type, others):
if group.features.has_materials and can_manage_materials(request.user, group):
actions.append((u"Upload material", urlreverse("ietf.doc.views_material.choose_material_type", kwargs=kwargs)))
if group.type_id in ("rg", "wg") and group.state_id != "conclude" and can_manage:
if group.state_id != "conclude" and (is_chair or can_manage):
actions.append((u"Edit group", urlreverse("group_edit", kwargs=kwargs)))
if group.features.customize_workflow and (is_chair or can_manage):

View file

@ -80,6 +80,14 @@ class Group(GroupInfo):
role_names = [role_names]
return user.is_authenticated() and self.role_set.filter(name__in=role_names, person__user=user).exists()
def is_decendant_of(self, sought_parent):
p = self.parent
while (p != None):
if p.acronym == sought_parent:
return True
p = p.parent
return False
def is_bof(self):
return (self.state.slug in ["bof", "bof-conc"])

View file

@ -25,7 +25,7 @@ from ietf.name.models import DocTagName, GroupStateName, GroupTypeName
from ietf.person.models import Person, Email
from ietf.utils.test_utils import TestCase, unicontent
from ietf.utils.mail import outbox, empty_outbox
from ietf.utils.test_data import make_test_data
from ietf.utils.test_data import make_test_data, create_person
from ietf.utils.test_utils import login_testing_unauthorized
from ietf.group.factories import GroupFactory, RoleFactory, GroupEventFactory
from ietf.meeting.factories import SessionFactory
@ -240,6 +240,17 @@ class GroupPagesTests(TestCase):
self.assertTrue(milestone.docs.all()[0].name in unicontent(r))
def test_group_about(self):
def verify_cannot_edit_group(username):
self.client.login(username=username, password=username+"+password")
r = self.client.get(url)
self.assertEqual(r.status_code, 403)
def verify_can_edit_group(username):
self.client.login(username=username, password=username+"+password")
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
make_test_data()
group = Group.objects.create(
type_id="team",
@ -247,7 +258,9 @@ class GroupPagesTests(TestCase):
name="Test Team",
description="The test team is testing.",
state_id="active",
parent = Group.objects.get(acronym="farfut"),
)
create_person(group, "chair", name="Testteam Chairman", username="teamchairman")
for url in [group.about_url(),
urlreverse('ietf.group.info.group_about',kwargs=dict(acronym=group.acronym)),
@ -260,6 +273,14 @@ class GroupPagesTests(TestCase):
self.assertTrue(group.acronym in unicontent(r))
self.assertTrue(group.description in unicontent(r))
url = urlreverse('ietf.group.edit.edit', kwargs=dict(acronym=group.acronym))
for username in ['plain','iana','iab chair','irtf chair','marschairman']:
verify_cannot_edit_group(username)
for username in ['secretary','teamchairman','ad']:
verify_can_edit_group(username)
def test_materials(self):
make_test_data()
group = Group.objects.create(type_id="team", acronym="testteam", name="Test Team", state_id="active")

View file

@ -91,6 +91,15 @@ def can_manage_group_type(user, group_type):
return has_role(user, 'Secretariat')
def can_manage_team_group(user, group):
if group.type_id != "team":
return False
elif group.is_decendant_of("ietf") and has_role(user, ('Area Director', 'Secretariat')):
return True
elif group.is_decendant_of("irtf") and has_role(user, ('IRTF Chair', 'Secretariat')):
return True
return has_role(user, ('Secretariat'))
def milestone_reviewer_for_group_type(group_type):
if group_type == "rg":
return "IRTF Chair"