Merged in [13731] from rjsparks@nostrum.com:
Reworked how review assigments are processed in order to ensure a team's queue rotates when it should. Fixes #2305. - Legacy-Id: 13743 Note: SVN reference [13731] has been migrated to Git commit 7f5cef056ade1641f1d815b0a5f35962077d6d01
This commit is contained in:
parent
9415d65341
commit
108c00a0a3
|
@ -1,6 +1,8 @@
|
|||
import debug # pyflakes:ignore
|
||||
import factory
|
||||
|
||||
from ietf.group.models import Group, Role, GroupEvent
|
||||
from ietf.review.factories import ReviewTeamSettingsFactory
|
||||
|
||||
class GroupFactory(factory.DjangoModelFactory):
|
||||
class Meta:
|
||||
|
@ -8,6 +10,20 @@ class GroupFactory(factory.DjangoModelFactory):
|
|||
|
||||
name = factory.Faker('sentence',nb_words=6)
|
||||
acronym = factory.Sequence(lambda n: 'acronym%d' %n)
|
||||
state_id = 'active'
|
||||
|
||||
class ReviewTeamFactory(factory.DjangoModelFactory):
|
||||
class Meta:
|
||||
model = Group
|
||||
|
||||
type_id = 'dir'
|
||||
name = factory.Faker('sentence',nb_words=6)
|
||||
acronym = factory.Sequence(lambda n: 'acronym%d' %n)
|
||||
state_id = 'active'
|
||||
|
||||
@factory.post_generation
|
||||
def settings(obj, create, extracted, **kwargs):
|
||||
ReviewTeamSettingsFactory.create(group=obj,**kwargs)
|
||||
|
||||
class RoleFactory(factory.DjangoModelFactory):
|
||||
class Meta:
|
||||
|
|
|
@ -1269,8 +1269,12 @@ class StatusUpdateTests(TestCase):
|
|||
self.assertEqual(chair.group.latest_event(type='status_update').desc,'This came from a file.')
|
||||
|
||||
def test_view_all_status_updates(self):
|
||||
GroupEventFactory(type='status_update',desc='blah blah blah',group__type_id='wg')
|
||||
GroupEventFactory(type='status_update',desc='blah blah blah',group__type_id='rg')
|
||||
area = GroupFactory(type_id='area')
|
||||
wg = GroupFactory(type_id='wg',parent=area)
|
||||
irtf = GroupFactory(type_id='irtf')
|
||||
rg = GroupFactory(type_id='rg',parent=irtf)
|
||||
GroupEventFactory(type='status_update',desc='blah blah blah',group=wg)
|
||||
GroupEventFactory(type='status_update',desc='blah blah blah',group=rg)
|
||||
url = urlreverse('ietf.group.views.all_status')
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import datetime
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
from pyquery import PyQuery
|
||||
|
||||
|
@ -15,12 +16,16 @@ from ietf.review.utils import (
|
|||
suggested_review_requests_for_team,
|
||||
review_requests_needing_reviewer_reminder, email_reviewer_reminder,
|
||||
review_requests_needing_secretary_reminder, email_secretary_reminder,
|
||||
reviewer_rotation_list,
|
||||
)
|
||||
from ietf.name.models import ReviewTypeName, ReviewResultName, ReviewRequestStateName
|
||||
import ietf.group.views
|
||||
from ietf.utils.mail import outbox, empty_outbox
|
||||
from ietf.dbtemplate.factories import DBTemplateFactory
|
||||
from ietf.person.factories import PersonFactory
|
||||
from ietf.doc.factories import DocumentFactory
|
||||
from ietf.group.factories import RoleFactory, ReviewTeamFactory
|
||||
from ietf.review.factories import ReviewRequestFactory
|
||||
|
||||
class ReviewTests(TestCase):
|
||||
def test_review_requests(self):
|
||||
|
@ -553,3 +558,37 @@ class ReviewTests(TestCase):
|
|||
self.assertEqual(len(outbox), 1)
|
||||
self.assertTrue(review_req.doc_id in outbox[0].get_payload(decode=True).decode("utf-8"))
|
||||
|
||||
|
||||
|
||||
class BulkAssignmentTests(TestCase):
|
||||
|
||||
def test_rotation_queue_update(self):
|
||||
group = ReviewTeamFactory.create()
|
||||
empty_outbox()
|
||||
reviewers = [RoleFactory.create(group=group,name_id='reviewer') for i in range(6)] # pyflakes:ignore
|
||||
secretary = RoleFactory.create(group=group,name_id='secr')
|
||||
docs = [DocumentFactory.create(type_id='draft',group=None) for i in range(4)]
|
||||
requests = [ReviewRequestFactory(team=group,doc=docs[i]) for i in range(4)]
|
||||
rot_list = reviewer_rotation_list(group)
|
||||
|
||||
expected_ending_head_of_rotation = rot_list[3]
|
||||
|
||||
unassigned_url = urlreverse(ietf.group.views.manage_review_requests, kwargs={ 'acronym': group.acronym, 'group_type': group.type_id, "assignment_status": "unassigned" })
|
||||
|
||||
postdict = {}
|
||||
postdict['reviewrequest'] = [r.id for r in requests]
|
||||
# assignments that affect the first 3 reviewers in queue
|
||||
for i in range(3):
|
||||
postdict['r{}-existing_reviewer'.format(requests[i].pk)] = ''
|
||||
postdict['r{}-action'.format(requests[i].pk)] = 'assign'
|
||||
postdict['r{}-reviewer'.format(requests[i].pk)] = rot_list[i].email_address()
|
||||
# and one out of order assignment
|
||||
postdict['r{}-existing_reviewer'.format(requests[3].pk)] = ''
|
||||
postdict['r{}-action'.format(requests[3].pk)] = 'assign'
|
||||
postdict['r{}-reviewer'.format(requests[3].pk)] = rot_list[5].email_address()
|
||||
postdict['action'] = 'save'
|
||||
self.client.login(username=secretary.person.user.username,password=secretary.person.user.username+'+password')
|
||||
r = self.client.post(unassigned_url, postdict)
|
||||
self.assertEqual(r.status_code,302)
|
||||
self.assertEqual(expected_ending_head_of_rotation,reviewer_rotation_list(group)[0])
|
||||
self.assertEqual(len(outbox),4)
|
||||
|
|
|
@ -1456,13 +1456,32 @@ def manage_review_requests(request, acronym, group_type=None, assignment_status=
|
|||
form_results.append(req.form.is_valid())
|
||||
|
||||
if saving and all(form_results) and not (newly_closed > 0 or newly_opened > 0 or newly_assigned > 0):
|
||||
for review_req in review_requests:
|
||||
action = review_req.form.cleaned_data.get("action")
|
||||
if action == "assign":
|
||||
assign_review_request_to_reviewer(request, review_req, review_req.form.cleaned_data["reviewer"],review_req.form.cleaned_data["add_skip"])
|
||||
elif action == "close":
|
||||
close_review_request(request, review_req, review_req.form.cleaned_data["close"])
|
||||
|
||||
reqs_to_assign = []
|
||||
for review_req in review_requests:
|
||||
form_action = review_req.form.cleaned_data.get("action")
|
||||
if form_action=="close":
|
||||
close_review_request(request, review_req, review_req.form.cleaned_data["close"])
|
||||
elif form_action=="assign":
|
||||
reqs_to_assign.append(review_req)
|
||||
|
||||
assignments_by_person = dict()
|
||||
for r in reqs_to_assign:
|
||||
assignments_by_person[r.form.cleaned_data["reviewer"].person] = r
|
||||
|
||||
# Make sure the any assignments to the person at the head
|
||||
# of the rotation queue are processed first so that the queue
|
||||
# rotates before any more assignments are processed
|
||||
head_of_rotation = reviewer_rotation_list(group)[0]
|
||||
while head_of_rotation in assignments_by_person:
|
||||
review_req = assignments_by_person[head_of_rotation]
|
||||
assign_review_request_to_reviewer(request, review_req, review_req.form.cleaned_data["reviewer"],review_req.form.cleaned_data["add_skip"])
|
||||
reqs_to_assign.remove(review_req)
|
||||
head_of_rotation = reviewer_rotation_list(group)[0]
|
||||
|
||||
for review_req in reqs_to_assign:
|
||||
assign_review_request_to_reviewer(request, review_req, review_req.form.cleaned_data["reviewer"],review_req.form.cleaned_data["add_skip"])
|
||||
|
||||
kwargs = { "acronym": group.acronym }
|
||||
if group_type:
|
||||
kwargs["group_type"] = group_type
|
||||
|
|
22
ietf/review/factories.py
Normal file
22
ietf/review/factories.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
import factory
|
||||
import datetime
|
||||
|
||||
from ietf.review.models import ReviewTeamSettings, ReviewRequest
|
||||
|
||||
class ReviewTeamSettingsFactory(factory.DjangoModelFactory):
|
||||
class Meta:
|
||||
model = ReviewTeamSettings
|
||||
|
||||
group = factory.SubFactory('ietf.group.factories.GroupFactory',type_id='dir')
|
||||
|
||||
class ReviewRequestFactory(factory.DjangoModelFactory):
|
||||
class Meta:
|
||||
model = ReviewRequest
|
||||
|
||||
state_id = 'requested'
|
||||
type_id = 'lc'
|
||||
doc = factory.SubFactory('ietf.doc.factories.DocumentFactory',type_id='draft')
|
||||
team = factory.SubFactory('ietf.group.factories.ReviewTeamFactory',type_id='dir')
|
||||
deadline = datetime.datetime.today()+datetime.timedelta(days=14)
|
||||
requested_by = factory.SubFactory('ietf.person.factories.PersonFactory')
|
||||
|
Loading…
Reference in a new issue