Skip to content

Commit ee4bc0c

Browse files
author
Sasha Romijn
committed
Fix ietf-tools#2119 - Allow specifying review type for suggested reviews in LC and telechat
If a review is suggested on the "manage unassigned reviews" page, and the document is in both last call and telechat, the assign form now asks for the type of review that should be assigned. This commit also fixes two bugs in this process: - Comparisons in some cases between strings and integers (group/views.py:1485/1487) - Rejections when assigning suggested reviews, as they could be considered a newly opened request due to not having a pk (group/views.py:1508) Commit ready for merge. - Legacy-Id: 16933
1 parent 730e64d commit ee4bc0c

5 files changed

Lines changed: 125 additions & 18 deletions

File tree

ietf/group/forms.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
# IETF imports
1818
from ietf.group.models import Group, GroupHistory, GroupStateName
19+
from ietf.name.models import ReviewTypeName
1920
from ietf.person.fields import SearchableEmailsField, PersonEmailChoiceField
2021
from ietf.person.models import Person
2122
from ietf.review.models import ReviewerSettings, UnavailablePeriod, ReviewSecretarySettings
@@ -234,6 +235,7 @@ class ManageReviewRequestForm(forms.Form):
234235
close = forms.ModelChoiceField(queryset=close_review_request_states(), required=False)
235236
close_comment = forms.CharField(max_length=255, required=False)
236237
reviewer = PersonEmailChoiceField(empty_label="(None)", required=False, label_with="person")
238+
review_type = forms.ModelChoiceField(queryset=ReviewTypeName.objects.filter(slug__in=['telechat', 'lc']), required=True)
237239
add_skip = forms.BooleanField(required=False)
238240

239241
def __init__(self, review_req, *args, **kwargs):
@@ -262,6 +264,9 @@ def __init__(self, review_req, *args, **kwargs):
262264
setup_reviewer_field(self.fields["reviewer"], review_req)
263265
self.fields["reviewer"].widget.attrs["class"] = "form-control input-sm"
264266

267+
if not getattr(review_req, 'in_lc_and_telechat', False):
268+
del self.fields["review_type"]
269+
265270
if self.is_bound:
266271
if self.data.get("action") == "close":
267272
self.fields["close"].required = True

ietf/group/tests_review.py

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from django.urls import reverse as urlreverse
1414

1515
from ietf.utils.test_utils import login_testing_unauthorized, TestCase, reload_db_objects
16-
from ietf.doc.models import TelechatDocEvent
16+
from ietf.doc.models import TelechatDocEvent, LastCallDocEvent, State
1717
from ietf.group.models import Role
1818
from ietf.iesg.models import TelechatDate
1919
from ietf.person.models import Person
@@ -26,7 +26,8 @@
2626
reviewer_rotation_list,
2727
email_unavaibility_period_ending_reminder, email_reminder_all_open_reviews,
2828
email_review_reminder_overdue_assignment, email_reminder_unconfirmed_assignments)
29-
from ietf.name.models import ReviewResultName, ReviewRequestStateName, ReviewAssignmentStateName
29+
from ietf.name.models import ReviewResultName, ReviewRequestStateName, ReviewAssignmentStateName, \
30+
ReviewTypeName
3031
import ietf.group.views
3132
from ietf.utils.mail import outbox, empty_outbox
3233
from ietf.dbtemplate.factories import DBTemplateFactory
@@ -91,6 +92,7 @@ def test_suggested_review_requests(self):
9192
self.assertEqual(len(suggestions), 1)
9293
self.assertEqual(suggestions[0].doc, doc)
9394
self.assertEqual(suggestions[0].team, team)
95+
self.assertFalse(getattr(suggestions[0], 'in_lc_and_telechat', None))
9496

9597
# blocked by non-versioned refusal
9698
review_req.requested_rev = ""
@@ -120,6 +122,35 @@ def test_suggested_review_requests(self):
120122

121123
self.assertEqual(len(suggested_review_requests_for_team(team)), 1)
122124

125+
def test_suggested_review_requests_on_lc_and_telechat(self):
126+
review_req = ReviewRequestFactory(state_id='assigned')
127+
doc = review_req.doc
128+
team = review_req.team
129+
130+
# put on telechat
131+
TelechatDocEvent.objects.create(
132+
type="scheduled_for_telechat",
133+
by=Person.objects.get(name="(System)"),
134+
doc=doc,
135+
rev=doc.rev,
136+
telechat_date=TelechatDate.objects.all().first().date,
137+
)
138+
139+
# Put on last call as well
140+
doc.states.add(State.objects.get(type="draft-iesg", slug="lc", used=True))
141+
LastCallDocEvent.objects.create(
142+
doc=doc,
143+
expires=datetime.datetime.now() + datetime.timedelta(days=365),
144+
by=Person.objects.get(name="(System)"),
145+
rev=doc.rev
146+
)
147+
148+
suggestions = suggested_review_requests_for_team(team)
149+
self.assertEqual(len(suggestions), 1)
150+
self.assertEqual(suggestions[0].doc, doc)
151+
self.assertEqual(suggestions[0].team, team)
152+
self.assertTrue(suggestions[0].in_lc_and_telechat)
153+
123154
def test_reviewer_overview(self):
124155
team = ReviewTeamFactory()
125156
reviewer = RoleFactory(name_id='reviewer',group=team,person__user__username='reviewer').person
@@ -228,7 +259,9 @@ def test_manage_review_requests(self):
228259
"r{}-action".format(review_req3.pk): "assign",
229260
"r{}-reviewer".format(review_req3.pk): another_reviewer.email_set.first().pk,
230261
"r{}-add_skip".format(review_req3.pk): 1,
231-
262+
# Should be ignored, setting review_type only applies to suggested reviews
263+
"r{}-review_type".format(review_req3.pk): ReviewTypeName.objects.get(slug='telechat').pk,
264+
232265
"action": "save",
233266
})
234267
self.assertEqual(r.status_code, 302)
@@ -237,7 +270,67 @@ def test_manage_review_requests(self):
237270
settings = ReviewerSettings.objects.filter(team=review_req3.team, person=another_reviewer).first()
238271
self.assertEqual(settings.skip_next,1)
239272
self.assertEqual(review_req3.state_id, "assigned")
273+
self.assertEqual(review_req3.type_id, "lc")
274+
275+
def test_manage_review_requests_assign_suggested_reviews(self):
276+
doc = DocumentFactory()
277+
team = ReviewTeamFactory()
240278

279+
# put on telechat
280+
TelechatDocEvent.objects.create(
281+
type="scheduled_for_telechat",
282+
by=Person.objects.get(name="(System)"),
283+
doc=doc,
284+
rev=doc.rev,
285+
telechat_date=TelechatDate.objects.all().first().date,
286+
)
287+
288+
# Put on last call as well
289+
doc.states.add(State.objects.get(type="draft-iesg", slug="lc", used=True))
290+
LastCallDocEvent.objects.create(
291+
doc=doc,
292+
expires=datetime.datetime.now() + datetime.timedelta(days=365),
293+
by=Person.objects.get(name="(System)"),
294+
rev=doc.rev
295+
)
296+
297+
reviewer = RoleFactory(name_id='reviewer', group=team, person__user__username='reviewer')
298+
unassigned_url = urlreverse(ietf.group.views.manage_review_requests, kwargs={ 'acronym': team.acronym, 'group_type': team.type_id, "assignment_status": "unassigned" })
299+
300+
login_testing_unauthorized(self, "secretary", unassigned_url)
301+
302+
# get
303+
r = self.client.get(unassigned_url)
304+
self.assertEqual(r.status_code, 200)
305+
self.assertContains(r, doc.name)
306+
307+
# Submit as lc review
308+
r = self.client.post(unassigned_url, {
309+
"rlc-{}-action".format(doc.name): "assign",
310+
"rlc-{}-review_type".format(doc.name): ReviewTypeName.objects.get(slug='lc').pk,
311+
"rlc-{}-reviewer".format(doc.name): reviewer.person.email_set.first().pk,
312+
313+
"action": "save",
314+
})
315+
self.assertEqual(r.status_code, 302)
316+
review_request = doc.reviewrequest_set.get()
317+
self.assertEqual(review_request.type_id, 'lc')
318+
319+
# Clean up and try again as telechat
320+
review_request.reviewassignment_set.all().delete()
321+
review_request.delete()
322+
323+
r = self.client.post(unassigned_url, {
324+
"rlc-{}-action".format(doc.name): "assign",
325+
"rlc-{}-review_type".format(doc.name): ReviewTypeName.objects.get(slug='telechat').pk,
326+
"rlc-{}-reviewer".format(doc.name): reviewer.person.email_set.first().pk,
327+
328+
"action": "save",
329+
})
330+
self.assertEqual(r.status_code, 302)
331+
review_request = doc.reviewrequest_set.get()
332+
self.assertEqual(review_request.type_id, 'telechat')
333+
241334
def test_email_open_review_assignments(self):
242335
review_req1 = ReviewRequestFactory()
243336
review_assignment_completed = ReviewAssignmentFactory(review_request=review_req1,reviewer=EmailFactory(person__user__username='marschairman'), state_id='completed', reviewed_rev=0)

ietf/group/views.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,9 +1482,9 @@ def manage_review_requests(request, acronym, group_type=None, assignment_status=
14821482
for a in r.reviewassignment_set.all():
14831483
if l and rev:
14841484
if r.doc_id == l[0].doc_id and a.reviewed_rev:
1485-
if int(a.reviewed_rev) > rev:
1485+
if int(a.reviewed_rev) > int(rev):
14861486
l = [r]
1487-
elif int(a.reviewed_rev) == rev:
1487+
elif int(a.reviewed_rev) == int(rev):
14881488
l.append(r)
14891489
else:
14901490
l = [r]
@@ -1505,7 +1505,7 @@ def manage_review_requests(request, acronym, group_type=None, assignment_status=
15051505
saving = form_action.startswith("save")
15061506

15071507
# check for conflicts
1508-
review_requests_dict = { six.text_type(r.pk): r for r in review_requests }
1508+
review_requests_dict = { six.text_type(r.pk): r for r in review_requests if r.pk}
15091509
posted_reqs = set(request.POST.getlist("reviewrequest", []))
15101510
current_reqs = set(review_requests_dict.keys())
15111511

@@ -1530,6 +1530,8 @@ def manage_review_requests(request, acronym, group_type=None, assignment_status=
15301530
close_review_request(request, review_req, review_req.form.cleaned_data["close"],
15311531
review_req.form.cleaned_data["close_comment"])
15321532
elif action=="assign":
1533+
if review_req.form.cleaned_data.get("review_type"):
1534+
review_req.type = review_req.form.cleaned_data.get("review_type")
15331535
reqs_to_assign.append(review_req)
15341536

15351537
assignments_by_person = dict()

ietf/review/utils.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,6 @@ def suggested_review_requests_for_team(team):
605605
requested_by=system_person,
606606
state=requested_state,
607607
)
608-
609608
seen_deadlines[doc.pk] = deadline
610609

611610

@@ -639,16 +638,20 @@ def suggested_review_requests_for_team(team):
639638

640639
if not deadline or deadline > seen_deadlines.get(doc_pk, datetime.date.max):
641640
continue
642-
643-
requests[doc_pk] = ReviewRequest(
644-
time=event_time,
645-
type=telechat_type,
646-
doc_id=doc_pk,
647-
team=team,
648-
deadline=deadline,
649-
requested_by=system_person,
650-
state=requested_state,
651-
)
641+
642+
if doc_pk in requests:
643+
# Document was already added in last call, i.e. it is both in last call and telechat
644+
requests[doc_pk].in_lc_and_telechat = True
645+
else:
646+
requests[doc_pk] = ReviewRequest(
647+
time=event_time,
648+
type=telechat_type,
649+
doc_id=doc_pk,
650+
team=team,
651+
deadline=deadline,
652+
requested_by=system_person,
653+
state=requested_state,
654+
)
652655

653656
seen_deadlines[doc_pk] = deadline
654657

ietf/templates/group/manage_review_requests.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ <h1>Manage {{ assignment_status }} open review requests for {{ group.acronym }}<
3737

3838
<h3 class="panel-title">
3939
<span class="pull-right">
40-
{{ r.type.name }}
40+
{% if r.in_lc_and_telechat %}Last Call and telechat{% else %}{{ r.type.name }}{% endif %}
4141
- deadline {{ r.deadline|date:"Y-m-d" }}
4242
{% if r.due %}<span class="label label-warning">{{ r.due }} day{{ r.due|pluralize }}</span>{% endif %}
4343
</span>
@@ -134,6 +134,10 @@ <h3 class="panel-title">
134134
{{ r.form.action }}
135135

136136
<span class="reviewer-controls form-inline">
137+
{% if r.form.review_type %}
138+
<label for="{{ r.form.review_type.id_for_label }}">Review Type:</label>
139+
{{ r.form.review_type }}
140+
{% endif %}
137141
<label for="{{ r.form.reviewer.id_for_label }}">Assign:</label>
138142
{{ r.form.reviewer }}
139143
{{ r.form.add_skip }} <label for="{{ r.form.add_skip.id_for_label }}">Skip next time</label>

0 commit comments

Comments
 (0)