diff --git a/ietf/doc/tests_ballot.py b/ietf/doc/tests_ballot.py index e18b2abfd9..034ba6f4b2 100644 --- a/ietf/doc/tests_ballot.py +++ b/ietf/doc/tests_ballot.py @@ -806,7 +806,7 @@ def test_clear_ballot(self): ballot = create_ballot_if_not_open(None, draft, ad, 'approve') old_ballot_id = ballot.id draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="iesg-eva")) - url = urlreverse('ietf.doc.views_ballot.clear_ballot', kwargs=dict(name=draft.name,ballot_type_slug=draft.ballot_open('approve').ballot_type.slug)) + url = urlreverse('ietf.doc.views_ballot.clear_ballot', kwargs=dict(name=draft.name,ballot_type_slug="approve")) login_testing_unauthorized(self, "secretary", url) r = self.client.get(url) self.assertEqual(r.status_code, 200) @@ -816,6 +816,11 @@ def test_clear_ballot(self): self.assertIsNotNone(ballot) self.assertEqual(ballot.ballotpositiondocevent_set.count(),0) self.assertNotEqual(old_ballot_id, ballot.id) + # It's not valid to clear a ballot of a type where there's no matching state + url = urlreverse('ietf.doc.views_ballot.clear_ballot', kwargs=dict(name=draft.name,ballot_type_slug="statchg")) + r = self.client.post(url,{}) + self.assertEqual(r.status_code, 404) + def test_ballot_downref_approve(self): ad = Person.objects.get(name="AreaĆ° Irector") diff --git a/ietf/doc/tests_status_change.py b/ietf/doc/tests_status_change.py index 229390447c..bec48ed4ef 100644 --- a/ietf/doc/tests_status_change.py +++ b/ietf/doc/tests_status_change.py @@ -484,7 +484,47 @@ def verify_relations(doc,target_name,status): verify_relations(doc,'rfc9998','tobcp' ) verify_relations(doc,'rfc14' ,'tohist') self.assertTrue(doc.latest_event(DocEvent,type="added_comment").desc.startswith('Affected RFC list changed.')) + + def test_clear_ballot(self): + doc = Document.objects.get(name='status-change-imaginary-mid-review') + url = urlreverse('ietf.doc.views_ballot.clear_ballot',kwargs=dict(name=doc.name, ballot_type_slug="statchg")) + login_testing_unauthorized(self, "secretary", url) + + # Some additional setup + doc.relateddocument_set.create(target=Document.objects.get(name='rfc9999'),relationship_id='tois') + doc.relateddocument_set.create(target=Document.objects.get(name='rfc9998'),relationship_id='tohist') + create_ballot_if_not_open(None, doc, Person.objects.get(user__username="secretary"), "statchg") + doc.set_state(State.objects.get(slug='iesgeval',type='statchg')) + old_ballot = doc.ballot_open("statchg") + self.assertIsNotNone(old_ballot) + + r = self.client.post(url, dict()) + self.assertEqual(r.status_code,302) + new_ballot = doc.ballot_open("statchg") + self.assertIsNotNone(new_ballot) + self.assertNotEqual(new_ballot, old_ballot) + self.assertEqual(doc.get_state_slug("statchg"),"iesgeval") + + def test_clear_deferred_ballot(self): + doc = Document.objects.get(name='status-change-imaginary-mid-review') + url = urlreverse('ietf.doc.views_ballot.clear_ballot',kwargs=dict(name=doc.name, ballot_type_slug="statchg")) + login_testing_unauthorized(self, "secretary", url) + + # Some additional setup + doc.relateddocument_set.create(target=Document.objects.get(name='rfc9999'),relationship_id='tois') + doc.relateddocument_set.create(target=Document.objects.get(name='rfc9998'),relationship_id='tohist') + create_ballot_if_not_open(None, doc, Person.objects.get(user__username="secretary"), "statchg") + doc.set_state(State.objects.get(slug='defer',type='statchg')) + old_ballot = doc.ballot_open("statchg") + self.assertIsNotNone(old_ballot) + r = self.client.post(url, dict()) + self.assertEqual(r.status_code,302) + new_ballot = doc.ballot_open("statchg") + self.assertIsNotNone(new_ballot) + self.assertNotEqual(new_ballot, old_ballot) + self.assertEqual(doc.get_state_slug("statchg"),"iesgeval") + def setUp(self): super().setUp() IndividualRfcFactory(rfc_number=14,std_level_id='unkn') # draft was never issued diff --git a/ietf/doc/views_ballot.py b/ietf/doc/views_ballot.py index 02b55249d6..83ccb07be6 100644 --- a/ietf/doc/views_ballot.py +++ b/ietf/doc/views_ballot.py @@ -399,11 +399,22 @@ def send_ballot_comment(request, name, ballot_id): def clear_ballot(request, name, ballot_type_slug): """Clear all positions and discusses on every open ballot for a document.""" doc = get_object_or_404(Document, name=name) + # If there's no appropriate ballot type state, clearing would be an invalid action. + # This will need to be updated if we ever allow defering IRTF ballots + if ballot_type_slug == "approve": + state_machine = "draft-iesg" + elif ballot_type_slug in ["statchg","conflrev"]: + state_machine = ballot_type_slug + else: + state_machine = None + state_slug = state_machine and doc.get_state_slug(state_machine) + if state_machine is None or state_slug is None: + raise Http404 if request.method == 'POST': by = request.user.person if close_ballot(doc, by, ballot_type_slug): create_ballot_if_not_open(request, doc, by, ballot_type_slug) - if doc.get_state('draft-iesg').slug == 'defer': + if state_slug == "defer": do_undefer_ballot(request,doc) return redirect("ietf.doc.views_doc.document_main", name=doc.name)