Skip to content

Commit 8c7e751

Browse files
committed
Allow Secretariat to handle downrefs when they approve a document
- Legacy-Id: 16126
1 parent 746ed7a commit 8c7e751

5 files changed

Lines changed: 157 additions & 5 deletions

File tree

ietf/doc/tests_ballot.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,60 @@ def test_clear_ballot(self):
702702
self.assertEqual(ballot.ballotpositiondocevent_set.count(),0)
703703
self.assertNotEqual(old_ballot_id, ballot.id)
704704

705+
def test_ballot_downref_approve(self):
706+
ad = Person.objects.get(name="Areað Irector")
707+
draft = IndividualDraftFactory(ad=ad, intended_std_level_id='ps')
708+
draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="ann")) # make sure it's approved
709+
LastCallDocEvent.objects.create(
710+
by=Person.objects.get(name='(System)'),
711+
type='sent_last_call',
712+
doc=draft,
713+
rev=draft.rev,
714+
desc='issued last call',
715+
expires = datetime.datetime.now()-datetime.timedelta(days=14) )
716+
WriteupDocEvent.objects.create(
717+
by=Person.objects.get(name='(System)'),
718+
doc=draft,
719+
rev=draft.rev,
720+
type='changed_last_call_text',
721+
desc='Last call announcement was changed',
722+
text='this is simple last call text.' )
723+
rfc = IndividualRfcFactory.create(
724+
stream_id='ise',
725+
other_aliases=['rfc6666',],
726+
states=[('draft','rfc'),('draft-iesg','pub')],
727+
std_level_id='inf', )
728+
729+
url = urlreverse('ietf.doc.views_ballot.approve_downrefs', kwargs=dict(name=draft.name))
730+
731+
# Only Secretariat can use this URL
732+
login_testing_unauthorized(self, "ad", url)
733+
r = self.client.get(url)
734+
self.assertEqual(r.status_code, 403)
735+
self.assertTrue("Restricted to role Secretariat" in r.content)
736+
737+
# There are no downrefs, the page should say so
738+
login_testing_unauthorized(self, "secretary", url)
739+
r = self.client.get(url)
740+
self.assertEqual(r.status_code, 200)
741+
self.assertTrue("No downward references for" in r.content)
742+
743+
# Add a downref, the page should ask if it should be added to the registry
744+
rel = draft.relateddocument_set.create(target=rfc.docalias_set.get(name='rfc6666'),relationship_id='refnorm')
745+
d = [rdoc for rdoc in draft.relateddocument_set.all() if rel.is_approved_downref()]
746+
original_len = len(d)
747+
r = self.client.get(url)
748+
self.assertEqual(r.status_code, 200)
749+
self.assertTrue("normatively references rfc6666" in r.content)
750+
751+
# POST with the downref checked
752+
r = self.client.post(url, dict(checkboxes=rel.pk))
753+
self.assertEqual(r.status_code, 302)
754+
755+
# Confirm an entry was added to the downref registry
756+
d = [rdoc for rdoc in draft.relateddocument_set.all() if rel.is_approved_downref()]
757+
self.assertTrue(len(d) > original_len, "The downref approval was not added")
758+
705759
class MakeLastCallTests(TestCase):
706760
def test_make_last_call(self):
707761
ad = Person.objects.get(user__username="ad")

ietf/doc/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@
118118
url(r'^%(name)s/edit/ballotrfceditornote/$' % settings.URL_REGEXPS, views_ballot.ballot_rfceditornote),
119119
url(r'^%(name)s/edit/approvaltext/$' % settings.URL_REGEXPS, views_ballot.ballot_approvaltext),
120120
url(r'^%(name)s/edit/approveballot/$' % settings.URL_REGEXPS, views_ballot.approve_ballot),
121+
url(r'^%(name)s/edit/approvedownrefs/$' % settings.URL_REGEXPS, views_ballot.approve_downrefs),
121122
url(r'^%(name)s/edit/makelastcall/$' % settings.URL_REGEXPS, views_ballot.make_last_call),
122123
url(r'^%(name)s/edit/urls/$' % settings.URL_REGEXPS, views_draft.edit_document_urls),
123124

ietf/doc/views_ballot.py

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import debug # pyflakes:ignore
1717

1818
from ietf.doc.models import ( Document, State, DocEvent, BallotDocEvent, BallotPositionDocEvent,
19-
LastCallDocEvent, WriteupDocEvent, IESG_SUBSTATE_TAGS )
19+
LastCallDocEvent, WriteupDocEvent, IESG_SUBSTATE_TAGS, RelatedDocument )
2020
from ietf.doc.utils import ( add_state_change_event, close_ballot, close_open_ballots,
2121
create_ballot_if_not_open, update_telechat )
2222
from ietf.doc.mails import ( email_ballot_deferred, email_ballot_undeferred,
@@ -768,6 +768,7 @@ def ballot_approvaltext(request, name):
768768
need_intended_status=need_intended_status,
769769
))
770770

771+
771772
@role_required('Secretariat')
772773
def approve_ballot(request, name):
773774
"""Approve ballot, sending out announcement, changing state."""
@@ -871,14 +872,76 @@ def approve_ballot(request, name):
871872
msg.save()
872873
msg.related_docs.add(doc)
873874

874-
return HttpResponseRedirect(doc.get_absolute_url())
875+
downrefs = [rel for rel in doc.relateddocument_set.all() if rel.is_downref() and not rel.is_approved_downref()]
876+
if not downrefs:
877+
return HttpResponseRedirect(doc.get_absolute_url())
878+
else:
879+
return HttpResponseRedirect(doc.get_absolute_url()+'edit/approvedownrefs/')
875880

876881
return render(request, 'doc/ballot/approve_ballot.html',
877882
dict(doc=doc,
878883
action=action,
879884
announcement=announcement))
880885

881886

887+
class ApproveDownrefsForm(forms.Form):
888+
checkboxes = forms.ModelMultipleChoiceField(
889+
widget = forms.CheckboxSelectMultiple,
890+
queryset = RelatedDocument.objects.none(), )
891+
892+
893+
def __init__(self, queryset, *args, **kwargs):
894+
super(ApproveDownrefsForm, self).__init__(*args, **kwargs)
895+
self.fields['checkboxes'].queryset = queryset
896+
897+
def clean(self):
898+
if 'checkboxes' not in self.cleaned_data:
899+
raise forms.ValidationError("No RFCs were selected")
900+
901+
@role_required('Secretariat')
902+
def approve_downrefs(request, name):
903+
"""Document ballot was just approved; add the checked downwared references to the downref registry."""
904+
doc = get_object_or_404(Document, docalias__name=name)
905+
if not doc.get_state("draft-iesg"):
906+
raise Http404
907+
908+
login = request.user.person
909+
910+
downrefs_to_rfc = [rel for rel in doc.relateddocument_set.all() if rel.is_downref() and not rel.is_approved_downref() and rel.target.document.is_rfc()]
911+
912+
downrefs_to_rfc_qs = RelatedDocument.objects.filter(pk__in=[r.pk for r in downrefs_to_rfc])
913+
914+
last_call_text = doc.latest_event(WriteupDocEvent, type="changed_last_call_text").text.strip()
915+
916+
if request.method == 'POST':
917+
form = ApproveDownrefsForm(downrefs_to_rfc_qs, request.POST)
918+
if form.is_valid():
919+
for rel in form.cleaned_data['checkboxes']:
920+
RelatedDocument.objects.create(source=rel.source,
921+
target=rel.target, relationship_id='downref-approval')
922+
c = DocEvent(type="downref_approved", doc=rel.source,
923+
rev=rel.source.rev, by=login)
924+
c.desc = "Downref to RFC %s approved by Last Call for %s-%s" % (
925+
rel.target.document.rfc_number(), rel.source, rel.source.rev)
926+
c.save()
927+
c = DocEvent(type="downref_approved", doc=rel.target.document,
928+
rev=rel.target.document.rev, by=login)
929+
c.desc = "Downref to RFC %s approved by Last Call for %s-%s" % (
930+
rel.target.document.rfc_number(), rel.source, rel.source.rev)
931+
c.save()
932+
933+
return HttpResponseRedirect(doc.get_absolute_url())
934+
935+
else:
936+
form = ApproveDownrefsForm(downrefs_to_rfc_qs)
937+
938+
return render(request, 'doc/ballot/approve_downrefs.html',
939+
dict(doc=doc,
940+
approve_downrefs_form=form,
941+
last_call_text=last_call_text,
942+
downrefs_to_rfc=downrefs_to_rfc))
943+
944+
882945
class MakeLastCallForm(forms.Form):
883946
last_call_sent_date = forms.DateField(required=True)
884947
last_call_expiration_date = forms.DateField(required=True)

ietf/templates/doc/ballot/approve_ballot.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ <h1>Approve ballot<br><small><a href="{% url "ietf.doc.views_doc.document_main"
1616

1717
{% buttons %}
1818
{% if action == "to_announcement_list" %}
19-
<button class="btn btn-warningprimary" type="submit">Notify RFC Editor, send announcement & close ballot</button>
19+
<button class="btn btn-primary" type="submit">Notify RFC Editor, send announcement & close ballot</button>
2020
{% elif action == "to_rfc_editor" %}
21-
<button class="btn btn-warning" type="submit">Email RFC Editor & close ballot</button>
21+
<button class="btn btn-primary" type="submit">Email RFC Editor & close ballot</button>
2222
{% elif action == "do_not_publish" %}
23-
<button class="btn btn-warning" type="submit">Email RFC Editor (DNP) & close ballot"/>
23+
<button class="btn btn-primary" type="submit">Email RFC Editor (DNP) & close ballot"/>
2424
{% endif %}
2525
{% endbuttons %}
2626
</form>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{% extends "base.html" %}
2+
{# Copyright The IETF Trust 2019, All Rights Reserved #}
3+
{% load origin %}
4+
5+
{% load bootstrap3 %}
6+
7+
{% block title %}Approve downward references for {{ doc }}{% endblock %}
8+
9+
{% block content %}
10+
{% origin %}
11+
<h1>Approve downward references<br><small>The ballot for <a href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}">{{ doc }}</a> was just approved</small></h1>
12+
13+
{% if not downrefs_to_rfc %}
14+
<p>No downward references for <a href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}">{{ doc }}</a></p>
15+
{% else %}
16+
<p>Add downward references to RFCs to the downref registry, if they were identified in the IETF Last Call and approved by the Sponsoring Area Director.<p>
17+
<p><b>Last Call text for this document:</b><p>
18+
<pre>
19+
{{ last_call_text }}
20+
</pre>
21+
<p><b>This document has downward references to the following RFCs.<br>Which downward references, if any, are to be added to the downref registry?</b></p>
22+
<form action="" method="post">
23+
{% csrf_token %}
24+
{% bootstrap_form approve_downrefs_form %}
25+
{% buttons %}
26+
<p>
27+
<a class="btn btn-primary" href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}">Add no downref entries</a>
28+
<button type="submit" class="btn btn-warning" value="Save checked downrefs">Add checked downref entries</button>
29+
</p>
30+
{% endbuttons %}
31+
</form>
32+
{% endif %}
33+
34+
{% endblock %}

0 commit comments

Comments
 (0)