Skip to content

Commit b24bdb5

Browse files
committed
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. Commit ready for merge.
- Legacy-Id: 12520
1 parent 57fa52e commit b24bdb5

File tree

10 files changed

+141
-37
lines changed

10 files changed

+141
-37
lines changed

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
@@ -479,8 +479,7 @@ def setup_complete_review_test(self):
479479
review_req.state = ReviewRequestStateName.objects.get(slug="accepted")
480480
review_req.save()
481481
for r in ReviewResultName.objects.filter(slug__in=("issues", "ready")):
482-
ResultUsedInReviewTeam.objects.get_or_create(team=review_req.team, result=r)
483-
review_req.team.save()
482+
review_req.team.reviewteamsettings.review_results.add(r)
484483

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

@@ -517,7 +516,7 @@ def test_complete_review_upload_content(self):
517516
test_file.name = "unnamed"
518517

519518
r = self.client.post(url, data={
520-
"result": ReviewResultName.objects.get(resultusedinreviewteam__team=review_req.team, slug="ready").pk,
519+
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
521520
"state": ReviewRequestStateName.objects.get(slug="completed").pk,
522521
"reviewed_rev": review_req.doc.rev,
523522
"review_submission": "upload",
@@ -560,7 +559,7 @@ def test_complete_review_enter_content(self):
560559
empty_outbox()
561560

562561
r = self.client.post(url, data={
563-
"result": ReviewResultName.objects.get(resultusedinreviewteam__team=review_req.team, slug="ready").pk,
562+
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
564563
"state": ReviewRequestStateName.objects.get(slug="completed").pk,
565564
"reviewed_rev": review_req.doc.rev,
566565
"review_submission": "enter",
@@ -590,7 +589,7 @@ def test_complete_review_link_to_mailing_list(self):
590589
empty_outbox()
591590

592591
r = self.client.post(url, data={
593-
"result": ReviewResultName.objects.get(resultusedinreviewteam__team=review_req.team, slug="ready").pk,
592+
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
594593
"state": ReviewRequestStateName.objects.get(slug="completed").pk,
595594
"reviewed_rev": review_req.doc.rev,
596595
"review_submission": "link",
@@ -618,7 +617,7 @@ def test_partially_complete_review(self):
618617
empty_outbox()
619618

620619
r = self.client.post(url, data={
621-
"result": ReviewResultName.objects.get(resultusedinreviewteam__team=review_req.team, slug="ready").pk,
620+
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
622621
"state": ReviewRequestStateName.objects.get(slug="part-completed").pk,
623622
"reviewed_rev": review_req.doc.rev,
624623
"review_submission": "enter",
@@ -652,7 +651,7 @@ def test_partially_complete_review(self):
652651
url = urlreverse('ietf.doc.views_review.complete_review', kwargs={ "name": review_req.doc.name, "request_id": review_req.pk })
653652

654653
r = self.client.post(url, data={
655-
"result": ReviewResultName.objects.get(resultusedinreviewteam__team=review_req.team, slug="ready").pk,
654+
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
656655
"state": ReviewRequestStateName.objects.get(slug="completed").pk,
657656
"reviewed_rev": review_req.doc.rev,
658657
"review_submission": "enter",
@@ -677,7 +676,7 @@ def test_revise_review_enter_content(self):
677676
empty_outbox()
678677

679678
r = self.client.post(url, data={
680-
"result": ReviewResultName.objects.get(resultusedinreviewteam__team=review_req.team, slug="ready").pk,
679+
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
681680
"state": ReviewRequestStateName.objects.get(slug="completed").pk,
682681
"reviewed_rev": review_req.doc.rev,
683682
"review_submission": "enter",
@@ -702,7 +701,7 @@ def test_revise_review_enter_content(self):
702701
# revise again
703702
empty_outbox()
704703
r = self.client.post(url, data={
705-
"result": ReviewResultName.objects.get(resultusedinreviewteam__team=review_req.team, slug="ready").pk,
704+
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
706705
"state": ReviewRequestStateName.objects.get(slug="part-completed").pk,
707706
"reviewed_rev": review_req.doc.rev,
708707
"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: 16 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,18 @@ class Meta:
185185
}
186186
api.review.register(ReviewSecretarySettingsResource())
187187

188+
class ReviewTeamSettingsResource(ModelResource):
189+
group = ToOneField(GroupResource, 'group')
190+
review_types = ToManyField(ReviewTypeNameResource, 'review_types')
191+
review_results = ToManyField(ReviewResultNameResource, 'review_results')
192+
class Meta:
193+
queryset = ReviewTeamSettings.objects.all()
194+
serializer = api.Serializer()
195+
cache = SimpleCache()
196+
filtering = {
197+
"id": ALL,
198+
"autosuggest": ALL,
199+
"review_types": ALL_WITH_RELATIONS,
200+
"review_results": ALL_WITH_RELATIONS,
201+
}
202+
api.review.register(ReviewTeamSettingsResource())

0 commit comments

Comments
 (0)