Skip to content

Commit b14e981

Browse files
committed
Merged in [12520] from rjsparks@nostrum.com:
Slight refactor of the review models to capture review team settings. Allows configuring review teams to get automatic suggestions for reviews or not. Provides a better admin for creating/managing review teams. Fixes ietf-tools#2048 and ietf-tools#2072. - Legacy-Id: 12544 Note: SVN reference [12520] has been migrated to Git commit b24bdb5
2 parents c19ffa6 + b24bdb5 commit b14e981

10 files changed

Lines changed: 147 additions & 37 deletions

ietf/doc/tests_review.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
import debug # pyflakes:ignore
1414

15-
from ietf.review.models import (ReviewRequest, ResultUsedInReviewTeam, ReviewerSettings,
15+
from ietf.review.models import (ReviewRequest, ReviewerSettings,
1616
ReviewWish, UnavailablePeriod, NextReviewerInTeam)
1717
from ietf.review.utils import reviewer_rotation_list, possibly_advance_next_reviewer_for_team
1818
import ietf.review.mailarch
@@ -490,8 +490,7 @@ def setup_complete_review_test(self):
490490
review_req.state = ReviewRequestStateName.objects.get(slug="accepted")
491491
review_req.save()
492492
for r in ReviewResultName.objects.filter(slug__in=("issues", "ready")):
493-
ResultUsedInReviewTeam.objects.get_or_create(team=review_req.team, result=r)
494-
review_req.team.save()
493+
review_req.team.reviewteamsettings.review_results.add(r)
495494

496495
url = urlreverse('ietf.doc.views_review.complete_review', kwargs={ "name": doc.name, "request_id": review_req.pk })
497496

@@ -528,7 +527,7 @@ def test_complete_review_upload_content(self):
528527
test_file.name = "unnamed"
529528

530529
r = self.client.post(url, data={
531-
"result": ReviewResultName.objects.get(resultusedinreviewteam__team=review_req.team, slug="ready").pk,
530+
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
532531
"state": ReviewRequestStateName.objects.get(slug="completed").pk,
533532
"reviewed_rev": review_req.doc.rev,
534533
"review_submission": "upload",
@@ -571,7 +570,7 @@ def test_complete_review_enter_content(self):
571570
empty_outbox()
572571

573572
r = self.client.post(url, data={
574-
"result": ReviewResultName.objects.get(resultusedinreviewteam__team=review_req.team, slug="ready").pk,
573+
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
575574
"state": ReviewRequestStateName.objects.get(slug="completed").pk,
576575
"reviewed_rev": review_req.doc.rev,
577576
"review_submission": "enter",
@@ -601,7 +600,7 @@ def test_complete_review_link_to_mailing_list(self):
601600
empty_outbox()
602601

603602
r = self.client.post(url, data={
604-
"result": ReviewResultName.objects.get(resultusedinreviewteam__team=review_req.team, slug="ready").pk,
603+
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
605604
"state": ReviewRequestStateName.objects.get(slug="completed").pk,
606605
"reviewed_rev": review_req.doc.rev,
607606
"review_submission": "link",
@@ -629,7 +628,7 @@ def test_partially_complete_review(self):
629628
empty_outbox()
630629

631630
r = self.client.post(url, data={
632-
"result": ReviewResultName.objects.get(resultusedinreviewteam__team=review_req.team, slug="ready").pk,
631+
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
633632
"state": ReviewRequestStateName.objects.get(slug="part-completed").pk,
634633
"reviewed_rev": review_req.doc.rev,
635634
"review_submission": "enter",
@@ -663,7 +662,7 @@ def test_partially_complete_review(self):
663662
url = urlreverse('ietf.doc.views_review.complete_review', kwargs={ "name": review_req.doc.name, "request_id": review_req.pk })
664663

665664
r = self.client.post(url, data={
666-
"result": ReviewResultName.objects.get(resultusedinreviewteam__team=review_req.team, slug="ready").pk,
665+
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
667666
"state": ReviewRequestStateName.objects.get(slug="completed").pk,
668667
"reviewed_rev": review_req.doc.rev,
669668
"review_submission": "enter",
@@ -688,7 +687,7 @@ def test_revise_review_enter_content(self):
688687
empty_outbox()
689688

690689
r = self.client.post(url, data={
691-
"result": ReviewResultName.objects.get(resultusedinreviewteam__team=review_req.team, slug="ready").pk,
690+
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
692691
"state": ReviewRequestStateName.objects.get(slug="completed").pk,
693692
"reviewed_rev": review_req.doc.rev,
694693
"review_submission": "enter",
@@ -713,7 +712,7 @@ def test_revise_review_enter_content(self):
713712
# revise again
714713
empty_outbox()
715714
r = self.client.post(url, data={
716-
"result": ReviewResultName.objects.get(resultusedinreviewteam__team=review_req.team, slug="ready").pk,
715+
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
717716
"state": ReviewRequestStateName.objects.get(slug="part-completed").pk,
718717
"reviewed_rev": review_req.doc.rev,
719718
"review_submission": "enter",

ietf/doc/views_review.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from ietf.doc.models import (Document, NewRevisionDocEvent, State, DocAlias,
1515
LastCallDocEvent, ReviewRequestDocEvent)
1616
from ietf.name.models import ReviewRequestStateName, ReviewResultName, DocTypeName
17-
from ietf.review.models import ReviewRequest, TypeUsedInReviewTeam
17+
from ietf.review.models import ReviewRequest
1818
from ietf.group.models import Group
1919
from ietf.person.fields import PersonEmailChoiceField, SearchablePersonField
2020
from ietf.ietfauth.utils import is_authorized_in_doc_stream, user_is_person, has_role
@@ -57,7 +57,7 @@ def __init__(self, user, doc, *args, **kwargs):
5757
f.queryset = active_review_teams()
5858
f.initial = [group.pk for group in f.queryset if can_manage_review_requests_for_team(user, group, allow_personnel_outside_team=False)]
5959

60-
self.fields['type'].queryset = self.fields['type'].queryset.filter(used=True, typeusedinreviewteam__team__in=self.fields["team"].queryset).distinct()
60+
self.fields['type'].queryset = self.fields['type'].queryset.filter(used=True, reviewteamsettings__group__in=self.fields["team"].queryset).distinct()
6161
self.fields['type'].widget = forms.RadioSelect(choices=[t for t in self.fields['type'].choices if t[0]])
6262

6363
self.fields["requested_rev"].label = "Document revision"
@@ -83,7 +83,7 @@ def clean(self):
8383

8484
if chosen_type and chosen_teams:
8585
for t in chosen_teams:
86-
if not TypeUsedInReviewTeam.objects.filter(type=chosen_type, team=t).exists():
86+
if chosen_type not in t.reviewteamsettings.review_types.all():
8787
self.add_error("type", "{} does not use the review type {}.".format(t.name, chosen_type.name))
8888

8989
return self.cleaned_data
@@ -361,7 +361,7 @@ def __init__(self, review_req, *args, **kwargs):
361361
" ".join("<a class=\"rev label label-default\">{}</a>".format(r)
362362
for r in known_revisions))
363363

364-
self.fields["result"].queryset = self.fields["result"].queryset.filter(resultusedinreviewteam__team=review_req.team)
364+
self.fields["result"].queryset = self.fields["result"].queryset.filter(reviewteamsettings__group=review_req.team)
365365

366366
def format_submission_choice(label):
367367
if revising_review:

ietf/review/admin.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from ietf.review.models import (ReviewerSettings, UnavailablePeriod, ReviewWish,
44
ResultUsedInReviewTeam, TypeUsedInReviewTeam, NextReviewerInTeam,
5-
ReviewRequest)
5+
ReviewRequest, ReviewTeamSettings )
66

77
class ReviewerSettingsAdmin(admin.ModelAdmin):
88
def acronym(self, obj):
@@ -72,3 +72,11 @@ class ReviewRequestAdmin(admin.ModelAdmin):
7272
search_fields = ["doc__name", "reviewer__person__name"]
7373

7474
admin.site.register(ReviewRequest, ReviewRequestAdmin)
75+
76+
class ReviewTeamSettingsAdmin(admin.ModelAdmin):
77+
list_display = ["group", ]
78+
search_fields = ["group__acronym", ]
79+
raw_id_fields = ["group", ]
80+
filter_horizontal = ["review_types", "review_results", ]
81+
82+
admin.site.register(ReviewTeamSettings, ReviewTeamSettingsAdmin)

ietf/review/import_from_review_tool.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
import datetime, re, itertools
1717
from collections import namedtuple
1818
from django.db import connections
19-
from ietf.review.models import (ReviewRequest, ReviewerSettings, ReviewResultName, ResultUsedInReviewTeam,
20-
ReviewRequestStateName, ReviewTypeName, TypeUsedInReviewTeam,
19+
from ietf.review.models import (ReviewRequest, ReviewerSettings, ReviewResultName,
20+
ReviewRequestStateName, ReviewTypeName,
2121
UnavailablePeriod, NextReviewerInTeam)
2222
from ietf.group.models import Group, Role, RoleName
2323
from ietf.person.models import Person, Email, Alias
@@ -190,10 +190,10 @@ def parse_timestamp(t):
190190
summaries = [v.strip().lower() for v in row.value.split(";") if v.strip()]
191191

192192
for s in summaries:
193-
ResultUsedInReviewTeam.objects.get_or_create(team=team, result=results[s])
193+
team.reviewteamsettings.review_results.add(results[s])
194194

195195
for t in ReviewTypeName.objects.filter(slug__in=["early", "lc", "telechat"]):
196-
TypeUsedInReviewTeam.objects.get_or_create(team=team, type=t)
196+
team.reviewteamsettings.review_types.add(t)
197197

198198
# review requests
199199

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# -*- coding: utf-8 -*-
2+
from __future__ import unicode_literals
3+
4+
from django.db import migrations, models
5+
import ietf.review.models
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
('name', '0016_auto_20161013_1010'),
12+
('group', '0009_auto_20150930_0758'),
13+
('review', '0006_auto_20161209_0436'),
14+
]
15+
16+
operations = [
17+
migrations.CreateModel(
18+
name='ReviewTeamSettings',
19+
fields=[
20+
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
21+
('autosuggest', models.BooleanField(default=True, verbose_name=b'Automatically suggest possible review requests')),
22+
('group', models.OneToOneField(to='group.Group')),
23+
('review_results', models.ManyToManyField(default=ietf.review.models.get_default_review_results, to='name.ReviewResultName')),
24+
('review_types', models.ManyToManyField(default=ietf.review.models.get_default_review_types, to='name.ReviewTypeName')),
25+
],
26+
options={
27+
'verbose_name': 'Review team settings',
28+
'verbose_name_plural': 'Review team settings',
29+
},
30+
),
31+
]
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# -*- coding: utf-8 -*-
2+
from __future__ import unicode_literals
3+
4+
from django.db import migrations
5+
6+
def forward(apps, schema_editor):
7+
ReviewTeamSettings = apps.get_model('review','ReviewTeamSettings')
8+
ResultUsedInReviewTeam = apps.get_model('review','ResultUsedInReviewTeam')
9+
TypeUsedInReviewTeam = apps.get_model('review','TypeUsedInReviewTeam')
10+
11+
for group_id in ResultUsedInReviewTeam.objects.values_list('team',flat=True).distinct():
12+
rts = ReviewTeamSettings.objects.create(group_id=group_id)
13+
rts.review_types = TypeUsedInReviewTeam.objects.filter(team_id=group_id).values_list('type',flat=True).distinct()
14+
rts.review_results = ResultUsedInReviewTeam.objects.filter(team_id=group_id).values_list('result',flat=True).distinct()
15+
16+
17+
def reverse(apps, schema_editor):
18+
ReviewTeamSettings = apps.get_model('review','ReviewTeamSettings')
19+
ReviewTeamSettings.objects.all().delete()
20+
21+
class Migration(migrations.Migration):
22+
23+
dependencies = [
24+
('review', '0007_reviewteamsettings'),
25+
]
26+
27+
operations = [
28+
migrations.RunPython(forward, reverse)
29+
]

ietf/review/models.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
class ReviewerSettings(models.Model):
1212
"""Keeps track of admin data associated with a reviewer in a team."""
13-
team = models.ForeignKey(Group, limit_choices_to=~models.Q(resultusedinreviewteam=None))
13+
team = models.ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None))
1414
person = models.ForeignKey(Person)
1515
INTERVALS = [
1616
(7, "Once per week"),
@@ -34,7 +34,7 @@ class Meta:
3434

3535
class ReviewSecretarySettings(models.Model):
3636
"""Keeps track of admin data associated with a secretary in a team."""
37-
team = models.ForeignKey(Group, limit_choices_to=~models.Q(resultusedinreviewteam=None))
37+
team = models.ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None))
3838
person = models.ForeignKey(Person)
3939
remind_days_before_deadline = models.IntegerField(null=True, blank=True, help_text="To get an email reminder in case a reviewer forgets to do an assigned review, enter the number of days before review deadline you want to receive it. Clear the field if you don't want a reminder.")
4040

@@ -45,7 +45,7 @@ class Meta:
4545
verbose_name_plural = "review secretary settings"
4646

4747
class UnavailablePeriod(models.Model):
48-
team = models.ForeignKey(Group, limit_choices_to=~models.Q(resultusedinreviewteam=None))
48+
team = models.ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None))
4949
person = models.ForeignKey(Person)
5050
start_date = models.DateField(default=datetime.date.today, null=True, help_text="Choose the start date so that you can still do a review if it's assigned just before the start date - this usually means you should mark yourself unavailable for assignment some time before you are actually away.")
5151
end_date = models.DateField(blank=True, null=True, help_text="Leaving the end date blank means that the period continues indefinitely. You can end it later.")
@@ -76,7 +76,7 @@ def __unicode__(self):
7676
class ReviewWish(models.Model):
7777
"""Reviewer wishes to review a document when it becomes available for review."""
7878
time = models.DateTimeField(default=datetime.datetime.now)
79-
team = models.ForeignKey(Group, limit_choices_to=~models.Q(resultusedinreviewteam=None))
79+
team = models.ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None))
8080
person = models.ForeignKey(Person)
8181
doc = models.ForeignKey(Document)
8282

@@ -104,7 +104,7 @@ class Meta:
104104
class TypeUsedInReviewTeam(models.Model):
105105
"""Captures that a type name is valid for a given team for new
106106
reviews. """
107-
team = models.ForeignKey(Group, limit_choices_to=~models.Q(resultusedinreviewteam=None))
107+
team = models.ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None))
108108
type = models.ForeignKey(ReviewTypeName)
109109

110110
def __unicode__(self):
@@ -115,7 +115,7 @@ class Meta:
115115
verbose_name_plural = "review type used in team settings"
116116

117117
class NextReviewerInTeam(models.Model):
118-
team = models.ForeignKey(Group, limit_choices_to=~models.Q(resultusedinreviewteam=None))
118+
team = models.ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None))
119119
next_reviewer = models.ForeignKey(Person)
120120

121121
def __unicode__(self):
@@ -138,7 +138,7 @@ class ReviewRequest(models.Model):
138138
time = models.DateTimeField(default=datetime.datetime.now)
139139
type = models.ForeignKey(ReviewTypeName)
140140
doc = models.ForeignKey(Document, related_name='reviewrequest_set')
141-
team = models.ForeignKey(Group, limit_choices_to=~models.Q(resultusedinreviewteam=None))
141+
team = models.ForeignKey(Group, limit_choices_to=~models.Q(reviewteamsettings=None))
142142
deadline = models.DateField()
143143
requested_by = models.ForeignKey(Person)
144144
requested_rev = models.CharField(verbose_name="requested revision", max_length=16, blank=True, help_text="Fill in if a specific revision is to be reviewed, e.g. 02")
@@ -156,3 +156,23 @@ class ReviewRequest(models.Model):
156156

157157
def __unicode__(self):
158158
return u"%s review on %s by %s %s" % (self.type, self.doc, self.team, self.state)
159+
160+
def get_default_review_types():
161+
return ReviewTypeName.objects.filter(slug__in=['early','lc','telechat'])
162+
163+
def get_default_review_results():
164+
return ReviewResultName.objects.filter(slug__in=['not-ready', 'right-track', 'almost-ready', 'ready-issues', 'ready-nits', 'ready'])
165+
166+
class ReviewTeamSettings(models.Model):
167+
"""Holds configuration specific to groups that are review teams"""
168+
group = models.OneToOneField(Group)
169+
autosuggest = models.BooleanField(default=True, verbose_name="Automatically suggest possible review requests")
170+
review_types = models.ManyToManyField(ReviewTypeName, default=get_default_review_types)
171+
review_results = models.ManyToManyField(ReviewResultName, default=get_default_review_results)
172+
173+
def __unicode__(self):
174+
return u"%s" % (self.group.acronym,)
175+
176+
class Meta:
177+
verbose_name = "Review team settings"
178+
verbose_name_plural = "Review team settings"

ietf/review/resources.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from ietf.review.models import (ReviewerSettings, ReviewRequest,
1111
ResultUsedInReviewTeam, TypeUsedInReviewTeam,
1212
UnavailablePeriod, ReviewWish, NextReviewerInTeam,
13-
ReviewSecretarySettings)
13+
ReviewSecretarySettings, ReviewTeamSettings )
1414

1515

1616
from ietf.person.resources import PersonResource
@@ -185,3 +185,24 @@ class Meta:
185185
}
186186
api.review.register(ReviewSecretarySettingsResource())
187187

188+
189+
from ietf.group.resources import GroupResource
190+
from ietf.name.resources import ReviewResultNameResource, ReviewTypeNameResource
191+
class ReviewTeamSettingsResource(ModelResource):
192+
group = ToOneField(GroupResource, 'group')
193+
review_types = ToManyField(ReviewTypeNameResource, 'review_types', null=True)
194+
review_results = ToManyField(ReviewResultNameResource, 'review_results', null=True)
195+
class Meta:
196+
queryset = ReviewTeamSettings.objects.all()
197+
serializer = api.Serializer()
198+
cache = SimpleCache()
199+
#resource_name = 'reviewteamsettings'
200+
filtering = {
201+
"id": ALL,
202+
"autosuggest": ALL,
203+
"group": ALL_WITH_RELATIONS,
204+
"review_types": ALL_WITH_RELATIONS,
205+
"review_results": ALL_WITH_RELATIONS,
206+
}
207+
api.review.register(ReviewTeamSettingsResource())
208+

0 commit comments

Comments
 (0)