From d9ef21479b377fd5931a9bcd1fbefbf83177db9d Mon Sep 17 00:00:00 2001 From: Paul Selkirk Date: Tue, 3 Oct 2023 15:11:51 -0400 Subject: [PATCH 1/3] feat: Update IRTF state when entering/exiting IETF conflict review (#3469) --- ietf/doc/tests_conflict_review.py | 55 +++++++++++++++++++++++++++++-- ietf/doc/views_conflict_review.py | 31 ++++++++++++++++- 2 files changed, 82 insertions(+), 4 deletions(-) diff --git a/ietf/doc/tests_conflict_review.py b/ietf/doc/tests_conflict_review.py index 6fa1a4d9b6..8a6d8b9c79 100644 --- a/ietf/doc/tests_conflict_review.py +++ b/ietf/doc/tests_conflict_review.py @@ -1,4 +1,4 @@ -# Copyright The IETF Trust 2012-2020, All Rights Reserved +# Copyright The IETF Trust 2012-2023, All Rights Reserved # -*- coding: utf-8 -*- @@ -13,8 +13,8 @@ import debug # pyflakes:ignore -from ietf.doc.factories import IndividualDraftFactory, ConflictReviewFactory -from ietf.doc.models import Document, DocEvent, NewRevisionDocEvent, BallotPositionDocEvent, TelechatDocEvent, State +from ietf.doc.factories import IndividualDraftFactory, ConflictReviewFactory, RgDraftFactory +from ietf.doc.models import Document, DocEvent, NewRevisionDocEvent, BallotPositionDocEvent, TelechatDocEvent, State, DocTagName from ietf.doc.utils import create_ballot_if_not_open from ietf.doc.views_conflict_review import default_approval_text from ietf.group.models import Person @@ -450,3 +450,52 @@ def test_subsequent_submission(self): def setUp(self): super().setUp() ConflictReviewFactory(name='conflict-review-imaginary-irtf-submission',review_of=IndividualDraftFactory(name='draft-imaginary-irtf-submission',stream_id='irtf'),notify='notifyme@example.net') + +class ConflictReviewIrtfStateTests(TestCase): + + def start_review(self, role, kwargs=None): + doc = RgDraftFactory() + url = urlreverse('ietf.doc.views_conflict_review.start_review', kwargs=dict(name=doc.name)) + login_testing_unauthorized(self, role, url) + + r = self.client.post(url, kwargs) + self.assertEqual(r.status_code, 302) + self.assertEqual(doc.get_state('draft-stream-irtf').slug, 'iesg-rev') + + def test_start_review_as_secretary(self): + ad_strpk = str(Person.objects.get(name='Areaư Irector').pk) + state_strpk = str(State.objects.get(used=True, slug='needshep', type__slug='conflrev').pk) + self.start_review('secretary', kwargs=dict(ad=ad_strpk, create_in_state=state_strpk)) + + def test_start_review_as_stream_owner(self): + self.start_review('irtf-chair') + + def close_review(self, close_type, role): + doc = RgDraftFactory() + review = ConflictReviewFactory(review_of=doc) + url = urlreverse('ietf.doc.views_conflict_review.change_state', kwargs=dict(name=review.name)) + login_testing_unauthorized(self, role, url) + + strpk = str(State.objects.get(used=True, slug=close_type, type__slug='conflrev').pk) + r = self.client.post(url, dict(review_state=strpk)) + self.assertEqual(r.status_code, 302) + self.assertEqual(doc.get_state('draft-stream-irtf').slug, 'chair-w') + self.assertIn(DocTagName.objects.get(pk='iesg-com'), doc.tags.all()) + + def test_close_review_reqnopub_as_secretary(self): + self.close_review('appr-reqnopub-sent', 'secretary') + + def test_close_review_noprob_as_secretary(self): + self.close_review('appr-noprob-sent', 'secretary') + + def test_close_review_withdraw_as_secretary(self): + self.close_review('withdraw', 'secretary') + + def test_close_review_dead_as_secretary(self): + self.close_review('dead', 'secretary') + + def test_close_review_withdraw_as_ad(self): + self.close_review('withdraw', 'ad') + + def test_close_review_dead_as_ad(self): + self.close_review('dead', 'ad') diff --git a/ietf/doc/views_conflict_review.py b/ietf/doc/views_conflict_review.py index 5efd62dbe9..f571c732ef 100644 --- a/ietf/doc/views_conflict_review.py +++ b/ietf/doc/views_conflict_review.py @@ -1,4 +1,4 @@ -# Copyright The IETF Trust 2012-2020, All Rights Reserved +# Copyright The IETF Trust 2012-2023, All Rights Reserved # -*- coding: utf-8 -*- @@ -25,6 +25,7 @@ from ietf.group.models import Role, Group from ietf.iesg.models import TelechatDate from ietf.ietfauth.utils import has_role, role_required, is_authorized_in_doc_stream +from ietf.name.models import DocTagName from ietf.person.models import Person from ietf.utils import log from ietf.utils.mail import send_mail_preformatted @@ -90,6 +91,20 @@ def change_state(request, name, option=None): review, ok_to_publish) + if new_state.slug in ["appr-reqnopub-sent", "appr-noprob-sent", "withdraw", "dead"]: + doc = review.related_that_doc("conflrev")[0].document + if doc.stream_id == "irtf": + prev_state = doc.get_state("draft-stream-irtf") + new_state = State.objects.get(type_id="draft-stream-irtf", slug="chair-w") + prev_tags = set(doc.tags.all()) + new_tags = set(DocTagName.objects.filter(pk="iesg-com")) + + if new_state != prev_state: + doc.set_state(new_state) + doc.tags.clear() + doc.tags.set(new_tags) + events = [add_state_change_event(doc, login, prev_state, new_state, prev_tags, new_tags)] + doc.save_with_history(events) return redirect('ietf.doc.views_doc.document_main', name=review.name) else: @@ -488,6 +503,9 @@ def start_review_as_secretariat(request, name): send_conflict_review_started_email(request, conflict_review) + if doc_to_review.stream_id == 'irtf': + start_review_irtf_state(doc_to_review, login) + return HttpResponseRedirect(conflict_review.get_absolute_url()) else: notify_addresses = build_notify_addresses(doc_to_review) @@ -522,6 +540,9 @@ def start_review_as_stream_owner(request, name): send_conflict_review_started_email(request, conflict_review) + if doc_to_review.stream_id == 'irtf': + start_review_irtf_state(doc_to_review, login) + return HttpResponseRedirect(conflict_review.get_absolute_url()) else: notify_addresses = build_notify_addresses(doc_to_review) @@ -536,3 +557,11 @@ def start_review_as_stream_owner(request, name): 'doc_to_review': doc_to_review, }, ) + +def start_review_irtf_state(doc, by): + prev_state = doc.get_state('draft-stream-irtf') + new_state = State.objects.get(type_id='draft-stream-irtf', slug='iesg-rev') + doc.set_state(new_state) + events = [] + events.append(add_state_change_event(doc, by, prev_state, new_state)) + doc.save_with_history(events) From fd889ecfb2a7507e709a63745177f53eecba2cba Mon Sep 17 00:00:00 2001 From: Paul Selkirk Date: Tue, 3 Oct 2023 17:01:56 -0400 Subject: [PATCH 2/3] fix: Update IRTF state in approve_conflict_review() as well --- ietf/doc/tests_conflict_review.py | 13 +++++++++++++ ietf/doc/views_conflict_review.py | 29 ++++++++++++++++++----------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/ietf/doc/tests_conflict_review.py b/ietf/doc/tests_conflict_review.py index 8a6d8b9c79..58398be686 100644 --- a/ietf/doc/tests_conflict_review.py +++ b/ietf/doc/tests_conflict_review.py @@ -499,3 +499,16 @@ def test_close_review_withdraw_as_ad(self): def test_close_review_dead_as_ad(self): self.close_review('dead', 'ad') + + def test_approve_review(self): + doc = RgDraftFactory() + review = ConflictReviewFactory(review_of=doc) + review.set_state(State.objects.get(used=True, slug='appr-noprob-pend', type='conflrev')) + + url = urlreverse('ietf.doc.views_conflict_review.approve_conflict_review', kwargs=dict(name=review.name)) + login_testing_unauthorized(self, 'secretary', url) + + r = self.client.post(url, dict(announcement_text=default_approval_text(review))) + self.assertEqual(r.status_code, 302) + self.assertEqual(doc.get_state('draft-stream-irtf').slug, 'chair-w') + self.assertIn(DocTagName.objects.get(pk='iesg-com'), doc.tags.all()) diff --git a/ietf/doc/views_conflict_review.py b/ietf/doc/views_conflict_review.py index f571c732ef..d31bccfb70 100644 --- a/ietf/doc/views_conflict_review.py +++ b/ietf/doc/views_conflict_review.py @@ -94,17 +94,7 @@ def change_state(request, name, option=None): if new_state.slug in ["appr-reqnopub-sent", "appr-noprob-sent", "withdraw", "dead"]: doc = review.related_that_doc("conflrev")[0].document if doc.stream_id == "irtf": - prev_state = doc.get_state("draft-stream-irtf") - new_state = State.objects.get(type_id="draft-stream-irtf", slug="chair-w") - prev_tags = set(doc.tags.all()) - new_tags = set(DocTagName.objects.filter(pk="iesg-com")) - - if new_state != prev_state: - doc.set_state(new_state) - doc.tags.clear() - doc.tags.set(new_tags) - events = [add_state_change_event(doc, login, prev_state, new_state, prev_tags, new_tags)] - doc.save_with_history(events) + close_review_irtf_state(doc, login) return redirect('ietf.doc.views_doc.document_main', name=review.name) else: @@ -370,6 +360,10 @@ def approve_conflict_review(request, name): c.desc = "The following approval message was sent\n"+form.cleaned_data['announcement_text'] c.save() + doc = review.related_that_doc("conflrev")[0].document + if doc.stream_id == "irtf": + close_review_irtf_state(doc, login) + return HttpResponseRedirect(review.get_absolute_url()) else: @@ -565,3 +559,16 @@ def start_review_irtf_state(doc, by): events = [] events.append(add_state_change_event(doc, by, prev_state, new_state)) doc.save_with_history(events) + +def close_review_irtf_state(doc, by): + prev_state = doc.get_state("draft-stream-irtf") + new_state = State.objects.get(type_id="draft-stream-irtf", slug="chair-w") + prev_tags = set(doc.tags.all()) + new_tags = set(DocTagName.objects.filter(pk="iesg-com")) + + if new_state != prev_state: + doc.set_state(new_state) + doc.tags.clear() + doc.tags.set(new_tags) + events = [add_state_change_event(doc, by, prev_state, new_state, prev_tags, new_tags)] + doc.save_with_history(events) From a463e7c88339fa8aef37a1093027a9ff8d22d3ad Mon Sep 17 00:00:00 2001 From: Paul Selkirk Date: Mon, 9 Oct 2023 15:05:34 -0400 Subject: [PATCH 3/3] chore: Add "new_state != prev_state" guard --- ietf/doc/views_conflict_review.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ietf/doc/views_conflict_review.py b/ietf/doc/views_conflict_review.py index d31bccfb70..e208bda221 100644 --- a/ietf/doc/views_conflict_review.py +++ b/ietf/doc/views_conflict_review.py @@ -555,10 +555,12 @@ def start_review_as_stream_owner(request, name): def start_review_irtf_state(doc, by): prev_state = doc.get_state('draft-stream-irtf') new_state = State.objects.get(type_id='draft-stream-irtf', slug='iesg-rev') - doc.set_state(new_state) - events = [] - events.append(add_state_change_event(doc, by, prev_state, new_state)) - doc.save_with_history(events) + + if new_state != prev_state: + doc.set_state(new_state) + events = [] + events.append(add_state_change_event(doc, by, prev_state, new_state)) + doc.save_with_history(events) def close_review_irtf_state(doc, by): prev_state = doc.get_state("draft-stream-irtf")