From 68bdff6fd570c382055211e67eb2e42f4d2f7314 Mon Sep 17 00:00:00 2001 From: Robert Sparks Date: Thu, 15 Dec 2016 19:30:36 +0000 Subject: [PATCH 1/5] Missed adding a migration to svn for r12521. Commit ready to merge. Should only be applied after r12521. - Legacy-Id: 12540 --- .../migrations/0009_auto_20161214_1537.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 ietf/review/migrations/0009_auto_20161214_1537.py diff --git a/ietf/review/migrations/0009_auto_20161214_1537.py b/ietf/review/migrations/0009_auto_20161214_1537.py new file mode 100644 index 000000000..cf3218b2a --- /dev/null +++ b/ietf/review/migrations/0009_auto_20161214_1537.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('review', '0008_populate_reviewteamsettings'), + ] + + operations = [ + migrations.RemoveField( + model_name='resultusedinreviewteam', + name='result', + ), + migrations.RemoveField( + model_name='resultusedinreviewteam', + name='team', + ), + migrations.RemoveField( + model_name='typeusedinreviewteam', + name='team', + ), + migrations.RemoveField( + model_name='typeusedinreviewteam', + name='type', + ), + migrations.DeleteModel( + name='ResultUsedInReviewTeam', + ), + migrations.DeleteModel( + name='TypeUsedInReviewTeam', + ), + ] From df86798cf35ac67fd488c3c685c30cd83f3f99d2 Mon Sep 17 00:00:00 2001 From: Robert Sparks Date: Thu, 15 Dec 2016 19:48:37 +0000 Subject: [PATCH 2/5] Provide default filters for reviewer settings. Fixes #2093. Commit ready for merge. - Legacy-Id: 12541 --- ietf/group/views_review.py | 9 ++++++--- ietf/ietfauth/views.py | 4 ++-- ietf/review/utils.py | 11 ++++++++++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/ietf/group/views_review.py b/ietf/group/views_review.py index a569370c7..9f757713a 100644 --- a/ietf/group/views_review.py +++ b/ietf/group/views_review.py @@ -25,7 +25,8 @@ from ietf.review.utils import (can_manage_review_requests_for_team, email_reviewer_availability_change, reviewer_rotation_list, latest_review_requests_for_reviewers, - augment_review_requests_with_events) + augment_review_requests_with_events, + get_default_filter_re,) from ietf.doc.models import LastCallDocEvent from ietf.group.models import Role from ietf.group.utils import get_group_or_404, construct_group_menu_context @@ -488,8 +489,10 @@ def change_reviewer_settings(request, acronym, reviewer_email, group_type=None): or can_manage_review_requests_for_team(request.user, group)): return HttpResponseForbidden("You do not have permission to perform this action") - settings = (ReviewerSettings.objects.filter(person=reviewer, team=group).first() - or ReviewerSettings(person=reviewer, team=group)) + settings = ReviewerSettings.objects.filter(person=reviewer, team=group).first() + if not settings: + settings = ReviewerSettings(person=reviewer, team=group) + settings.filter_re = get_default_filter_re(reviewer) back_url = request.GET.get("next") if not back_url: diff --git a/ietf/ietfauth/views.py b/ietf/ietfauth/views.py index 3449814dd..8b3c18ff1 100644 --- a/ietf/ietfauth/views.py +++ b/ietf/ietfauth/views.py @@ -56,7 +56,7 @@ from ietf.ietfauth.utils import role_required from ietf.mailinglists.models import Subscribed, Whitelisted from ietf.person.models import Person, Email, Alias from ietf.review.models import ReviewRequest, ReviewerSettings, ReviewWish -from ietf.review.utils import unavailable_periods_to_list +from ietf.review.utils import unavailable_periods_to_list, get_default_filter_re from ietf.utils.mail import send_mail from ietf.doc.fields import SearchableDocumentField @@ -433,7 +433,7 @@ def review_overview(request): roles = { o.group_id: o for o in Role.objects.filter(name="reviewer", person__user=request.user, group__in=teams) } for t in teams: - t.reviewer_settings = settings.get(t.pk) or ReviewerSettings(team=t) + t.reviewer_settings = settings.get(t.pk) or ReviewerSettings(team=t,filter_re = get_default_filter_re(request.user.person)) t.unavailable_periods = unavailable_periods.get(t.pk, []) t.role = roles.get(t.pk) diff --git a/ietf/review/utils.py b/ietf/review/utils.py index 7ea50b837..0eb234d66 100644 --- a/ietf/review/utils.py +++ b/ietf/review/utils.py @@ -691,6 +691,15 @@ def setup_reviewer_field(field, review_req): field.choices = choices +def get_default_filter_re(person): + if type(person) != Person: + person = Person.objects.get(id=person) + groups_to_avoid = [r.group for r in person.role_set.filter(name='chair',group__type__in=['wg','rg'])] + if not groups_to_avoid: + return '^draft-%s-.*$' % ( person.last_name().lower(), ) + else: + return '^draft-(%s|%s)-.*$' % ( person.last_name().lower(), '|'.join(['ietf-%s' % g.acronym for g in groups_to_avoid])) + def make_assignment_choices(email_queryset, review_req): doc = review_req.doc team = review_req.team @@ -708,7 +717,7 @@ def make_assignment_choices(email_queryset, review_req): for p in possible_person_ids: if p not in reviewer_settings: - reviewer_settings[p] = ReviewerSettings(team=team) + reviewer_settings[p] = ReviewerSettings(team=team, filter_re = get_default_filter_re(p)) # frequency days_needed_for_reviewers = days_needed_to_fulfill_min_interval_for_reviewers(team) From 870fa59d0ce5cde9305770df102c77e53f97c9d3 Mon Sep 17 00:00:00 2001 From: Robert Sparks Date: Thu, 15 Dec 2016 20:36:15 +0000 Subject: [PATCH 3/5] Provide defaults on the Request review form. Fixes #2108. Commit ready for merge. - Legacy-Id: 12543 --- ietf/doc/views_review.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ietf/doc/views_review.py b/ietf/doc/views_review.py index 8be966bf7..0e4bd298d 100644 --- a/ietf/doc/views_review.py +++ b/ietf/doc/views_review.py @@ -132,12 +132,19 @@ def request_review(request, name): else: if lc_ends: review_type = "lc" + deadline = lc_ends.date().isoformat() elif scheduled_for_telechat: review_type = "telechat" + deadline = doc.telechat_date()-datetime.timedelta(days=2) else: review_type = "early" + deadline = None - form = RequestReviewForm(request.user, doc, initial={ "type": review_type }) + form = RequestReviewForm(request.user, doc, + initial={ "type": review_type, + "requested_by": request.user.person, + "deadline": deadline, + }) return render(request, 'doc/review/request_review.html', { 'doc': doc, From 6fcd8b8a16ba037b942ddc66b40a644fba45592f Mon Sep 17 00:00:00 2001 From: Robert Sparks Date: Thu, 15 Dec 2016 21:52:12 +0000 Subject: [PATCH 4/5] Allow a review request to include a comment to show to the review team secretary at assignment time and the reviewer at review time. Fixes #2096. Commit ready for merge. - Legacy-Id: 12545 --- ietf/doc/tests_review.py | 2 ++ ietf/doc/views_review.py | 4 +++- ietf/review/admin.py | 8 ++++++++ .../migrations/0010_reviewrequest_comment.py | 19 +++++++++++++++++++ ietf/review/models.py | 1 + ietf/templates/doc/review/request_review.html | 1 + ietf/templates/doc/review/review_request.html | 8 ++++++++ .../group/manage_review_requests.html | 5 ++++- 8 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 ietf/review/migrations/0010_reviewrequest_comment.py diff --git a/ietf/doc/tests_review.py b/ietf/doc/tests_review.py index a8b9ebf6d..1fa44b845 100644 --- a/ietf/doc/tests_review.py +++ b/ietf/doc/tests_review.py @@ -64,6 +64,7 @@ class ReviewTests(TestCase): "deadline": deadline.isoformat(), "requested_rev": "01", "requested_by": Person.objects.get(user__username="reviewsecretary").pk, + "comment": "gZT2iiYqYLKiQHvsgWCcVLdH" }) self.assertEqual(r.status_code, 302) @@ -74,6 +75,7 @@ class ReviewTests(TestCase): self.assertEqual(req.deadline, deadline) self.assertEqual(req.requested_rev, "01") self.assertEqual(doc.latest_event().type, "requested_review") + self.assertEqual(req.comment, "gZT2iiYqYLKiQHvsgWCcVLdH") def test_doc_page(self): diff --git a/ietf/doc/views_review.py b/ietf/doc/views_review.py index 0e4bd298d..6d926748e 100644 --- a/ietf/doc/views_review.py +++ b/ietf/doc/views_review.py @@ -46,7 +46,7 @@ class RequestReviewForm(forms.ModelForm): class Meta: model = ReviewRequest - fields = ('requested_by', 'type', 'deadline', 'requested_rev') + fields = ('requested_by', 'type', 'deadline', 'requested_rev', 'comment') def __init__(self, user, doc, *args, **kwargs): super(RequestReviewForm, self).__init__(*args, **kwargs) @@ -62,6 +62,8 @@ class RequestReviewForm(forms.ModelForm): self.fields["requested_rev"].label = "Document revision" + self.fields["comment"].widget = forms.Textarea() + if has_role(user, "Secretariat"): self.fields["requested_by"] = SearchablePersonField() else: diff --git a/ietf/review/admin.py b/ietf/review/admin.py index a706fc744..22da2df81 100644 --- a/ietf/review/admin.py +++ b/ietf/review/admin.py @@ -1,4 +1,5 @@ from django.contrib import admin +from django import forms from ietf.review.models import (ReviewerSettings, UnavailablePeriod, ReviewWish, NextReviewerInTeam, ReviewRequest, ReviewTeamSettings ) @@ -43,7 +44,14 @@ class NextReviewerInTeamAdmin(admin.ModelAdmin): admin.site.register(NextReviewerInTeam, NextReviewerInTeamAdmin) +class ReviewRequestAdminForm( forms.ModelForm ): + comment = forms.CharField(widget=forms.Textarea) + class Meta: + exclude = [] + model = ReviewRequest + class ReviewRequestAdmin(admin.ModelAdmin): + form = ReviewRequestAdminForm list_display = ["doc", "time", "type", "team", "deadline"] list_display_links = ["doc"] list_filter = ["team", "type", "state", "result"] diff --git a/ietf/review/migrations/0010_reviewrequest_comment.py b/ietf/review/migrations/0010_reviewrequest_comment.py new file mode 100644 index 000000000..ce8dc93ae --- /dev/null +++ b/ietf/review/migrations/0010_reviewrequest_comment.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('review', '0009_auto_20161214_1537'), + ] + + operations = [ + migrations.AddField( + model_name='reviewrequest', + name='comment', + field=models.CharField(default=b'', help_text=b'Provide any additional information to show to the review team secretary and reviewer', max_length=2048, verbose_name=b"Requester's comments and instructions", blank=True), + ), + ] diff --git a/ietf/review/models.py b/ietf/review/models.py index 2d1176867..d74653fe3 100644 --- a/ietf/review/models.py +++ b/ietf/review/models.py @@ -115,6 +115,7 @@ class ReviewRequest(models.Model): deadline = models.DateField() requested_by = models.ForeignKey(Person) 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") + comment = models.CharField(verbose_name="Requester's comments and instructions", max_length=2048, blank=True, help_text="Provide any additional information to show to the review team secretary and reviewer", default='') # Fields filled in as reviewer is assigned and as the review is # uploaded. Once these are filled in and we progress beyond being diff --git a/ietf/templates/doc/review/request_review.html b/ietf/templates/doc/review/request_review.html index 39625ca64..79d64df13 100644 --- a/ietf/templates/doc/review/request_review.html +++ b/ietf/templates/doc/review/request_review.html @@ -35,6 +35,7 @@ {% bootstrap_field form.team layout="horizontal" %} {% bootstrap_field form.deadline layout="horizontal" %} {% bootstrap_field form.requested_rev layout="horizontal" %} + {% bootstrap_field form.comment layout="horizontal" %} {% buttons %} diff --git a/ietf/templates/doc/review/review_request.html b/ietf/templates/doc/review/review_request.html index 1adf98bbe..f33fa866b 100644 --- a/ietf/templates/doc/review/review_request.html +++ b/ietf/templates/doc/review/review_request.html @@ -66,6 +66,14 @@ {{ review_req.requested_by }} {% endif %} + + {% if review_req.comment %} + + + Comments +
{{review_req.comment}}
+ + {% endif %} diff --git a/ietf/templates/group/manage_review_requests.html b/ietf/templates/group/manage_review_requests.html index 3a2ec9547..3ff06116e 100644 --- a/ietf/templates/group/manage_review_requests.html +++ b/ietf/templates/group/manage_review_requests.html @@ -60,7 +60,7 @@
+ {% if r.comment %} +
{{ r.comment }}
+ {% endif %}
From 32b431cf24f49dcf8ff67bf0235122d6cfeb8394 Mon Sep 17 00:00:00 2001 From: Robert Sparks Date: Thu, 15 Dec 2016 22:54:40 +0000 Subject: [PATCH 5/5] allow ads and secretaries to edit the review request comment. Fixes #2096. (Again). Commit ready for merge. - Legacy-Id: 12549 --- ietf/doc/tests_review.py | 17 ++++++++++++ ietf/doc/urls_review.py | 1 + ietf/doc/views_review.py | 26 +++++++++++++++++++ .../doc/review/edit_request_comment.html | 22 ++++++++++++++++ ietf/templates/doc/review/review_request.html | 6 ++++- 5 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 ietf/templates/doc/review/edit_request_comment.html diff --git a/ietf/doc/tests_review.py b/ietf/doc/tests_review.py index 1fa44b845..1065dde50 100644 --- a/ietf/doc/tests_review.py +++ b/ietf/doc/tests_review.py @@ -722,3 +722,20 @@ class ReviewTests(TestCase): self.assertEqual(len(outbox), 0) + def test_edit_comment(self): + doc = make_test_data() + review_req = make_review_data(doc) + + url = urlreverse('ietf.doc.views_review.edit_comment', kwargs={ "name": doc.name, "request_id": review_req.pk }) + + login_testing_unauthorized(self, "ad", url) + + r = self.client.get(url) + self.assertEqual(r.status_code, 200) + + r = self.client.post(url, data={ + "comment": "iHsnReEHXEmNPXcixsvAF9Aa", + }) + self.assertEqual(r.status_code, 302) + review_req = reload_db_objects(review_req) + self.assertEqual(review_req.comment,'iHsnReEHXEmNPXcixsvAF9Aa') diff --git a/ietf/doc/urls_review.py b/ietf/doc/urls_review.py index 0085d6add..9256bb904 100644 --- a/ietf/doc/urls_review.py +++ b/ietf/doc/urls_review.py @@ -9,5 +9,6 @@ urlpatterns = patterns('', url(r'^(?P[0-9]+)/rejectreviewerassignment/$', views_review.reject_reviewer_assignment), url(r'^(?P[0-9]+)/complete/$', views_review.complete_review), url(r'^(?P[0-9]+)/searchmailarchive/$', views_review.search_mail_archive), + url(r'^(?P[0-9]+)/editcomment/$', views_review.edit_comment), ) diff --git a/ietf/doc/views_review.py b/ietf/doc/views_review.py index 6d926748e..5080fd071 100644 --- a/ietf/doc/views_review.py +++ b/ietf/doc/views_review.py @@ -183,6 +183,8 @@ def review_request(request, name, request_id): and review_req.reviewer and (is_reviewer or can_manage_request)) + can_edit_comment = can_request_review_of_doc(request.user, doc) + if request.method == "POST" and request.POST.get("action") == "accept" and can_accept_reviewer_assignment: review_req.state = ReviewRequestStateName.objects.get(slug="accepted") review_req.save() @@ -197,6 +199,7 @@ def review_request(request, name, request_id): 'can_assign_reviewer': can_assign_reviewer, 'can_accept_reviewer_assignment': can_accept_reviewer_assignment, 'can_complete_review': can_complete_review, + 'can_edit_comment': can_edit_comment, }) @@ -603,3 +606,26 @@ def search_mail_archive(request, name, request_id): return JsonResponse(res) +class EditReviewRequestCommentForm(forms.ModelForm): + comment = forms.CharField(widget=forms.Textarea) + class Meta: + fields = ['comment',] + model = ReviewRequest + +def edit_comment(request, name, request_id): + review_req = get_object_or_404(ReviewRequest, pk=request_id) + if not can_request_review_of_doc(request.user, review_req.doc): + return HttpResponseForbidden("You do not have permission to perform this action") + + if request.method == "POST": + form = EditReviewRequestCommentForm(request.POST, instance=review_req) + if form.is_valid(): + form.save() + return redirect(review_request, name=review_req.doc.name, request_id=review_req.pk) + else: + form = EditReviewRequestCommentForm(instance=review_req) + + return render(request, 'doc/review/edit_request_comment.html', { + 'review_req': review_req, + 'form' : form, + }) diff --git a/ietf/templates/doc/review/edit_request_comment.html b/ietf/templates/doc/review/edit_request_comment.html new file mode 100644 index 000000000..6a3ca44c4 --- /dev/null +++ b/ietf/templates/doc/review/edit_request_comment.html @@ -0,0 +1,22 @@ +{% extends "base.html" %} +{# Copyright The IETF Trust 2016, All Rights Reserved #} +{% load origin bootstrap3 static %} + +{% block title %}Edit review request comment for {{ review_req.doc.name }}{% endblock %} + +{% block content %} + {% origin %} +

Edit review request comment
{{ review_req.doc.name }}

+ +
+ {% csrf_token %} + + {% bootstrap_form form %} + + {% buttons %} + Cancel + + {% endbuttons %} +
+ +{% endblock %} diff --git a/ietf/templates/doc/review/review_request.html b/ietf/templates/doc/review/review_request.html index f33fa866b..af7227489 100644 --- a/ietf/templates/doc/review/review_request.html +++ b/ietf/templates/doc/review/review_request.html @@ -71,7 +71,11 @@ Comments -
{{review_req.comment}}
+
{{review_req.comment}}
+ {% if can_edit_comment %} + Edit comment + {% endif %} + {% endif %}