Merged [7210] from rjsparks@nostrum.com: Allow the IRTF Chair and the ISE to request a conflict review directly through the tracker.
Notify the Secretariat when someone other than the secretariat initiates a conflict review.
Notify IANA when anyone initiates a conflict review.
Fixes tickets #1287 and #1289
- Legacy-Id: 7225
Note: SVN reference [7210] has been migrated to Git commit a0fd974c92
This commit is contained in:
parent
c83ef0c30b
commit
295b484bea
|
@ -23,7 +23,7 @@ from ietf.iesg.models import TelechatDate
|
|||
|
||||
|
||||
class ConflictReviewTests(TestCase):
|
||||
def test_start_review(self):
|
||||
def test_start_review_as_secretary(self):
|
||||
|
||||
doc = Document.objects.get(name='draft-imaginary-independent-submission')
|
||||
url = urlreverse('conflict_review_start',kwargs=dict(name=doc.name))
|
||||
|
@ -71,11 +71,59 @@ class ConflictReviewTests(TestCase):
|
|||
|
||||
self.assertTrue(review_doc.latest_event(DocEvent,type="added_comment").desc.startswith("IETF conflict review requested"))
|
||||
self.assertTrue(doc.latest_event(DocEvent,type="added_comment").desc.startswith("IETF conflict review initiated"))
|
||||
self.assertTrue('Conflict Review requested' in outbox[-1]['Subject'])
|
||||
self.assertTrue(settings.IANA_EVAL_EMAIL in outbox[-1]['To'])
|
||||
|
||||
# verify you can't start a review when a review is already in progress
|
||||
r = self.client.post(url,dict(ad="Aread Irector",create_in_state="Needs Shepherd",notify='ipu@ietf.org'))
|
||||
self.assertEqual(r.status_code, 404)
|
||||
|
||||
|
||||
def test_start_review_as_stream_owner(self):
|
||||
|
||||
doc = Document.objects.get(name='draft-imaginary-independent-submission')
|
||||
url = urlreverse('conflict_review_start',kwargs=dict(name=doc.name))
|
||||
|
||||
login_testing_unauthorized(self, "ise-chair", url)
|
||||
|
||||
# can't start conflict reviews on documents not in a stream
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 404)
|
||||
|
||||
|
||||
# can't start conflict reviews on documents in some other stream
|
||||
doc.stream=StreamName.objects.get(slug='irtf')
|
||||
doc.save()
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 404)
|
||||
|
||||
# successful get
|
||||
doc.stream=StreamName.objects.get(slug='ise')
|
||||
doc.save()
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('form input[name=notify]')),1)
|
||||
self.assertEquals(len(q('form select[name=ad]')),0)
|
||||
|
||||
# successfully starts a review, and notifies the secretariat
|
||||
messages_before = len(outbox)
|
||||
r = self.client.post(url,dict(notify='ipu@ietf.org'))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
review_doc = Document.objects.get(name='conflict-review-imaginary-independent-submission')
|
||||
self.assertEquals(review_doc.get_state('conflrev').slug,'needshep')
|
||||
self.assertEquals(review_doc.rev,u'00')
|
||||
self.assertEquals(review_doc.telechat_date(),None)
|
||||
self.assertEquals(review_doc.ad.name,u'Ietf Chair')
|
||||
self.assertEquals(review_doc.notify,u'ipu@ietf.org')
|
||||
doc = Document.objects.get(name='draft-imaginary-independent-submission')
|
||||
self.assertTrue(doc in [x.target.document for x in review_doc.relateddocument_set.filter(relationship__slug='conflrev')])
|
||||
self.assertEqual(len(outbox), messages_before + 2)
|
||||
self.assertTrue('Conflict Review requested' in outbox[-1]['Subject'])
|
||||
self.assertTrue(any('iesg-secretary@ietf.org' in x['To'] for x in outbox[-2:]))
|
||||
self.assertTrue(any(settings.IANA_EVAL_EMAIL in x['To'] for x in outbox[-2:]))
|
||||
|
||||
|
||||
def test_change_state(self):
|
||||
|
||||
doc = Document.objects.get(name='conflict-review-imaginary-irtf-submission')
|
||||
|
|
|
@ -11,7 +11,7 @@ from django.conf import settings
|
|||
from ietf.doc.utils import add_state_change_event, update_telechat
|
||||
from ietf.doc.models import save_document_in_history
|
||||
from ietf.doc.utils import create_ballot_if_not_open, close_open_ballots, get_document_content
|
||||
from ietf.ietfauth.utils import has_role, role_required
|
||||
from ietf.ietfauth.utils import has_role, role_required, is_authorized_in_doc_stream
|
||||
from ietf.utils.textupload import get_cleaned_text_file_content
|
||||
from ietf.utils.mail import send_mail_preformatted
|
||||
from ietf.doc.mails import email_iana
|
||||
|
@ -88,6 +88,22 @@ def change_state(request, name, option=None):
|
|||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def send_conflict_review_started_email(request, review):
|
||||
msg = render_to_string("doc/conflict_review/review_started.txt",
|
||||
dict(frm = settings.DEFAULT_FROM_EMAIL,
|
||||
by = request.user.person,
|
||||
review = review,
|
||||
reviewed_doc = review.relateddocument_set.get(relationship__slug='conflrev').target.document,
|
||||
review_url = settings.IDTRACKER_BASE_URL+review.get_absolute_url(),
|
||||
)
|
||||
)
|
||||
if not has_role(request.user,"Secretariat"):
|
||||
send_mail_preformatted(request,msg)
|
||||
email_iana(request,
|
||||
review.relateddocument_set.get(relationship__slug='conflrev').target.document,
|
||||
settings.IANA_EVAL_EMAIL,
|
||||
msg)
|
||||
|
||||
def send_conflict_eval_email(request,review):
|
||||
msg = render_to_string("doc/eval_email.txt",
|
||||
dict(doc=review,
|
||||
|
@ -345,6 +361,9 @@ def approve(request, name):
|
|||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
class SimpleStartReviewForm(forms.Form):
|
||||
notify = forms.CharField(max_length=255, label="Notice emails", help_text="Separate email addresses with commas", required=False)
|
||||
|
||||
class StartReviewForm(forms.Form):
|
||||
ad = forms.ModelChoiceField(Person.objects.filter(role__name="ad", role__group__state="active").order_by('name'),
|
||||
label="Shepherding AD", empty_label="(None)", required=True)
|
||||
|
@ -363,73 +382,96 @@ class StartReviewForm(forms.Form):
|
|||
|
||||
self.fields['telechat_date'].choices = [("", "(not on agenda)")] + [(d, d.strftime("%Y-%m-%d")) for d in dates]
|
||||
|
||||
@role_required("Secretariat")
|
||||
@role_required("Secretariat","IRTF Chair","ISE")
|
||||
def start_review(request, name):
|
||||
"""Start the conflict review process, setting the initial shepherding AD, and possibly putting the review on a telechat."""
|
||||
if has_role(request.user,"Secretariat"):
|
||||
return start_review_as_secretariat(request,name)
|
||||
else:
|
||||
return start_review_as_stream_owner(request,name)
|
||||
|
||||
def start_review_sanity_check(request, name):
|
||||
doc_to_review = get_object_or_404(Document, type="draft", name=name)
|
||||
|
||||
if not doc_to_review.stream_id in ('ise','irtf'):
|
||||
if ( not doc_to_review.stream_id in ('ise','irtf') ) or ( not is_authorized_in_doc_stream(request.user,doc_to_review)):
|
||||
raise Http404
|
||||
|
||||
# sanity check that there's not already a conflict review document for this document
|
||||
if [ rel.source for alias in doc_to_review.docalias_set.all() for rel in alias.relateddocument_set.filter(relationship='conflrev') ]:
|
||||
raise Http404
|
||||
|
||||
login = request.user.person
|
||||
return doc_to_review
|
||||
|
||||
def build_notify_addresses(doc_to_review):
|
||||
# Take care to do the right thing during ietf chair and stream owner transitions
|
||||
notify_addresses = []
|
||||
notify_addresses.extend([x.person.formatted_email() for x in Role.objects.filter(group__acronym=doc_to_review.stream.slug,name='chair')])
|
||||
notify_addresses.append("%s@%s" % (doc_to_review.name, settings.TOOLS_SERVER))
|
||||
return notify_addresses
|
||||
|
||||
def build_conflict_review_document(login, doc_to_review, ad, notify, create_in_state):
|
||||
if doc_to_review.name.startswith('draft-'):
|
||||
review_name = 'conflict-review-'+doc_to_review.name[6:]
|
||||
else:
|
||||
# This is a failsafe - and might be treated better as an error
|
||||
review_name = 'conflict-review-'+doc_to_review.name
|
||||
|
||||
iesg_group = Group.objects.get(acronym='iesg')
|
||||
|
||||
conflict_review=Document( type_id = "conflrev",
|
||||
title = "IETF conflict review for %s" % doc_to_review.name,
|
||||
name = review_name,
|
||||
rev = "00",
|
||||
ad = ad,
|
||||
notify = notify,
|
||||
stream_id = 'ietf',
|
||||
group = iesg_group,
|
||||
)
|
||||
conflict_review.save()
|
||||
conflict_review.set_state(create_in_state)
|
||||
|
||||
DocAlias.objects.create( name=review_name , document=conflict_review )
|
||||
|
||||
conflict_review.relateddocument_set.create(target=DocAlias.objects.get(name=doc_to_review.name),relationship_id='conflrev')
|
||||
|
||||
c = DocEvent(type="added_comment", doc=conflict_review, by=login)
|
||||
c.desc = "IETF conflict review requested"
|
||||
c.save()
|
||||
|
||||
c = DocEvent(type="added_comment", doc=doc_to_review, by=login)
|
||||
# Is it really OK to put html tags into comment text?
|
||||
c.desc = 'IETF conflict review initiated - see <a href="%s">%s</a>' % (reverse('doc_view', kwargs={'name':conflict_review.name}),conflict_review.name)
|
||||
c.save()
|
||||
|
||||
return conflict_review
|
||||
|
||||
def start_review_as_secretariat(request, name):
|
||||
"""Start the conflict review process, setting the initial shepherding AD, and possibly putting the review on a telechat."""
|
||||
|
||||
doc_to_review = start_review_sanity_check(request, name)
|
||||
|
||||
login = request.user.person
|
||||
|
||||
if request.method == 'POST':
|
||||
form = StartReviewForm(request.POST)
|
||||
if form.is_valid():
|
||||
conflict_review = build_conflict_review_document(login = login,
|
||||
doc_to_review = doc_to_review,
|
||||
ad = form.cleaned_data['ad'],
|
||||
notify = form.cleaned_data['notify'],
|
||||
create_in_state = form.cleaned_data['create_in_state']
|
||||
)
|
||||
|
||||
if doc_to_review.name.startswith('draft-'):
|
||||
review_name = 'conflict-review-'+doc_to_review.name[6:]
|
||||
else:
|
||||
# This is a failsafe - and might be treated better as an error
|
||||
review_name = 'conflict-review-'+doc_to_review.name
|
||||
|
||||
iesg_group = Group.objects.get(acronym='iesg')
|
||||
|
||||
conflict_review=Document( type_id = "conflrev",
|
||||
title = "IETF conflict review for %s" % doc_to_review.name,
|
||||
name = review_name,
|
||||
rev = "00",
|
||||
ad = form.cleaned_data['ad'],
|
||||
notify = form.cleaned_data['notify'],
|
||||
stream_id = 'ietf',
|
||||
group = iesg_group,
|
||||
)
|
||||
conflict_review.save()
|
||||
conflict_review.set_state(form.cleaned_data['create_in_state'])
|
||||
|
||||
DocAlias.objects.create( name=review_name , document=conflict_review )
|
||||
|
||||
conflict_review.relateddocument_set.create(target=DocAlias.objects.get(name=doc_to_review.name),relationship_id='conflrev')
|
||||
|
||||
c = DocEvent(type="added_comment", doc=conflict_review, by=login)
|
||||
c.desc = "IETF conflict review requested"
|
||||
c.save()
|
||||
|
||||
c = DocEvent(type="added_comment", doc=doc_to_review, by=login)
|
||||
# Is it really OK to put html tags into comment text?
|
||||
c.desc = 'IETF conflict review initiated - see <a href="%s">%s</a>' % (reverse('doc_view', kwargs={'name':conflict_review.name}),conflict_review.name)
|
||||
c.save()
|
||||
|
||||
tc_date = form.cleaned_data['telechat_date']
|
||||
if tc_date:
|
||||
update_telechat(request, conflict_review, login, tc_date)
|
||||
|
||||
send_conflict_review_started_email(request, conflict_review)
|
||||
|
||||
return HttpResponseRedirect(conflict_review.get_absolute_url())
|
||||
else:
|
||||
# Take care to do the right thing during ietf chair and stream owner transitions
|
||||
ietf_chair_id = Role.objects.filter(group__acronym='ietf',name='chair')[0].person.id
|
||||
notify_addresses = []
|
||||
notify_addresses.extend([x.person.formatted_email() for x in Role.objects.filter(group__acronym=doc_to_review.stream.slug,name='chair')])
|
||||
notify_addresses.append("%s@%s" % (name, settings.TOOLS_SERVER))
|
||||
|
||||
notify_addresses = build_notify_addresses(doc_to_review)
|
||||
init = {
|
||||
"ad" : ietf_chair_id,
|
||||
"ad" : Role.objects.filter(group__acronym='ietf',name='chair')[0].person.id,
|
||||
"notify" : u', '.join(notify_addresses),
|
||||
}
|
||||
form = StartReviewForm(initial=init)
|
||||
|
@ -440,6 +482,39 @@ def start_review(request, name):
|
|||
},
|
||||
context_instance = RequestContext(request))
|
||||
|
||||
def start_review_as_stream_owner(request, name):
|
||||
"""Start the conflict review process using defaults for everything but notify and let the secretariat know"""
|
||||
|
||||
doc_to_review = start_review_sanity_check(request, name)
|
||||
|
||||
login = request.user.person
|
||||
|
||||
if request.method == 'POST':
|
||||
form = SimpleStartReviewForm(request.POST)
|
||||
if form.is_valid():
|
||||
conflict_review = build_conflict_review_document(login = login,
|
||||
doc_to_review = doc_to_review,
|
||||
ad = Role.objects.filter(group__acronym='ietf',name='chair')[0].person,
|
||||
notify = form.cleaned_data['notify'],
|
||||
create_in_state = State.objects.get(used=True,type='conflrev',slug='needshep')
|
||||
)
|
||||
|
||||
send_conflict_review_started_email(request, conflict_review)
|
||||
|
||||
return HttpResponseRedirect(conflict_review.get_absolute_url())
|
||||
else:
|
||||
notify_addresses = build_notify_addresses(doc_to_review)
|
||||
|
||||
init = {
|
||||
"notify" : u', '.join(notify_addresses),
|
||||
}
|
||||
form = SimpleStartReviewForm(initial=init)
|
||||
|
||||
return render_to_response('doc/conflict_review/start.html',
|
||||
{'form': form,
|
||||
'doc_to_review': doc_to_review,
|
||||
},
|
||||
context_instance = RequestContext(request))
|
||||
|
||||
@role_required("Area Director", "Secretariat")
|
||||
def telechat_date(request, name):
|
||||
|
|
|
@ -294,7 +294,7 @@ def document_main(request, name, rev=None):
|
|||
actions.append(("Resurrect", urlreverse('doc_resurrect', kwargs=dict(name=doc.name))))
|
||||
|
||||
if (doc.get_state_slug() != "expired" and doc.stream_id in ("ise", "irtf")
|
||||
and has_role(request.user, ("Secretariat",)) and not conflict_reviews):
|
||||
and can_edit_stream_info and not conflict_reviews):
|
||||
label = "Begin IETF Conflict Review"
|
||||
if not doc.intended_std_level:
|
||||
label += " (note that intended status is not set)"
|
||||
|
|
|
@ -46,6 +46,7 @@ def has_role(user, role_names, *args, **kwargs):
|
|||
"Secretariat": Q(person=person, name="secr", group__acronym="secretariat"),
|
||||
"IANA": Q(person=person, name="auth", group__acronym="iana"),
|
||||
"RFC Editor": Q(person=person, name="auth", group__acronym="rfceditor"),
|
||||
"ISE" : Q(person=person, name="chair", group__acronym="ise"),
|
||||
"IAD": Q(person=person, name="admdir", group__acronym="ietf"),
|
||||
"IETF Chair": Q(person=person, name="chair", group__acronym="ietf"),
|
||||
"IRTF Chair": Q(person=person, name="chair", group__acronym="irtf"),
|
||||
|
|
11
ietf/templates/doc/conflict_review/review_started.txt
Normal file
11
ietf/templates/doc/conflict_review/review_started.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
{% load mail_filters %}{% autoescape off %}To: IESG Secretary <iesg-secretary@ietf.org>
|
||||
From: {{ frm }}
|
||||
Subject: Conflict Review requested for {{reviewed_doc.name}}
|
||||
|
||||
{{ by.name }} has requested a conflict review for:
|
||||
{{ reviewed_doc.name }}
|
||||
{{ reviewed_doc.title }}
|
||||
|
||||
The conflict review is being tracked at <{{ review_url }}>
|
||||
|
||||
{% endautoescape%}
|
|
@ -1,5 +1,7 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load ietf_filters %}
|
||||
|
||||
{% block title %}Begin IETF conflict review : {{doc_to_review.canonical_name}}-{{doc_to_review.rev}}{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
|
@ -18,7 +20,9 @@ form.start-conflict-review .actions {
|
|||
{% block content %}
|
||||
<h1>Begin IETF conflict review for {{doc_to_review.canonical_name}}-{{doc_to_review.rev}}</h1>
|
||||
|
||||
{% if user|has_role:"Secretariat" %}
|
||||
<p class="helptext">For help on the initial state choice, see the <a href="{% url "state_help" type="conflict-review" %}">state table</a>.</p>
|
||||
{% endif %}
|
||||
|
||||
<form class="start-conflict-review" action="" method="post">{% csrf_token %}
|
||||
<table>
|
||||
|
|
Loading…
Reference in a new issue