diff --git a/ietf/doc/urls_review.py b/ietf/doc/urls_review.py
index 1cc37f744..013344427 100644
--- a/ietf/doc/urls_review.py
+++ b/ietf/doc/urls_review.py
@@ -9,6 +9,7 @@ urlpatterns = [
url(r'^(?P[0-9]+)/$', views_review.review_request),
url(r'^(?P[0-9]+)/login/$', views_review.review_request_forced_login),
url(r'^(?P[0-9]+)/close/$', views_review.close_request),
+ url(r'^(?P[0-9]+)/addrequestcomment/$', views_review.add_request_comment),
url(r'^(?P[0-9]+)/assignreviewer/$', views_review.assign_reviewer),
url(r'^(?P[0-9]+)/rejectreviewerassignment/$', views_review.reject_reviewer_assignment),
url(r'^(?P[0-9]+)/complete/$', views_review.complete_review),
diff --git a/ietf/doc/views_review.py b/ietf/doc/views_review.py
index e267d9a46..e0e6cb05b 100644
--- a/ietf/doc/views_review.py
+++ b/ietf/doc/views_review.py
@@ -219,6 +219,8 @@ def review_request(request, name, request_id):
can_edit_deadline = can_edit_comment
+ can_add_comment = can_manage_request
+
assignments = review_req.reviewassignment_set.all()
for assignment in assignments:
assignment.is_reviewer = user_is_person(request.user, assignment.reviewer.person)
@@ -260,6 +262,7 @@ def review_request(request, name, request_id):
'can_assign_reviewer': can_assign_reviewer,
'can_edit_comment': can_edit_comment,
'can_edit_deadline': can_edit_deadline,
+ 'can_add_comment': can_add_comment,
'assignments': assignments,
'wg_chairs': wg_chairs,
'iesg_state_summary': iesg_state_summary,
@@ -310,6 +313,31 @@ def close_request(request, name, request_id):
'form': form,
})
+class AddCommentForm(forms.Form):
+ comment = forms.CharField(required=True, widget=forms.Textarea, strip=False)
+
+@login_required
+def add_request_comment(request, name, request_id):
+ doc = get_object_or_404(Document, name=name)
+ review_req = get_object_or_404(ReviewRequest, pk=request_id)
+
+ can_request = is_authorized_in_doc_stream(request.user, doc)
+ can_manage_request = can_manage_review_requests_for_team(request.user, review_req.team)
+ if not (can_request or can_manage_request):
+ permission_denied(request, "You do not have permission to perform this action")
+
+ if request.method == "POST":
+ form = AddCommentForm(request.POST)
+ if form.is_valid():
+ c = form.cleaned_data['comment']
+
+ review_req.add_history(c)
+ return redirect(review_request, name=review_req.doc.name, request_id=review_req.pk)
+ else:
+ form = AddCommentForm()
+
+ return render(request, 'doc/add_comment.html',
+ dict(doc=doc, form=form, review_req=review_req))
class AssignReviewerForm(forms.Form):
reviewer = PersonEmailChoiceField(label="Assign Additional Reviewer", empty_label="(None)")
diff --git a/ietf/review/models.py b/ietf/review/models.py
index f78e9b83c..d1b50c711 100644
--- a/ietf/review/models.py
+++ b/ietf/review/models.py
@@ -143,6 +143,10 @@ class ReviewRequest(models.Model):
def request_closed_time(self):
return self.doc.request_closed_time(self) or self.time
+ def add_history(self, description):
+ self._change_reason = description
+ self.save()
+
class ReviewAssignment(models.Model):
""" One of possibly many reviews assigned in response to a ReviewRequest """
history = HistoricalRecords(history_change_reason_field=models.TextField(null=True))
diff --git a/ietf/review/tests.py b/ietf/review/tests.py
index f76d03f56..f9d55d9d1 100644
--- a/ietf/review/tests.py
+++ b/ietf/review/tests.py
@@ -1,10 +1,14 @@
# Copyright The IETF Trust 2019-2020, All Rights Reserved
# -*- coding: utf-8 -*-
import datetime
+import debug # pyflakes:ignore
+from pyquery import PyQuery
from ietf.group.factories import RoleFactory
+from ietf.doc.factories import WgDraftFactory
from ietf.utils.mail import empty_outbox, get_payload_text, outbox
from ietf.utils.test_utils import TestCase, reload_db_objects
+from ietf.utils.test_utils import login_testing_unauthorized, unicontent
from ietf.utils.timezone import date_today, datetime_from_date
from .factories import ReviewAssignmentFactory, ReviewRequestFactory, ReviewerSettingsFactory
from .mailarch import hash_list_message_id
@@ -14,6 +18,7 @@ from .utils import (email_secretary_reminder, review_assignments_needing_secreta
send_reminder_unconfirmed_assignments, send_review_reminder_overdue_assignment,
send_reminder_all_open_reviews, send_unavailability_period_ending_reminder,
ORIGIN_DATE_PERIODIC_REMINDERS)
+from django.urls import reverse as urlreverse
class HashTest(TestCase):
@@ -508,3 +513,40 @@ class ReviewAssignmentReminderTests(TestCase):
self.assertTrue(self.reviewer.email_address() in log[0])
self.assertTrue('1 open review' in log[0])
+class AddReviewCommentTestCase(TestCase):
+ def test_review_add_comment(self):
+ draft = WgDraftFactory(name='draft-ietf-mars-test',group__acronym='mars')
+ review_req = ReviewRequestFactory(doc=draft, state_id='assigned')
+ ReviewAssignmentFactory(review_request=review_req, state_id='assigned')
+
+ url_post = urlreverse('ietf.doc.views_review.add_request_comment', kwargs=dict(name=draft.name, request_id=review_req.pk))
+ url_page = urlreverse('ietf.doc.views_review.review_request', kwargs=dict(name=draft.name, request_id=review_req.pk))
+
+ login_testing_unauthorized(self, "secretary", url_post)
+
+ # Check that we do not have entry on the page
+ r = self.client.get(url_page)
+ self.assertEqual(r.status_code, 200)
+ # Needs to have history
+ self.assertContains(r, 'History')
+ # But can't have the comment we are goint to add.
+ self.assertNotContains(r, 'This is a test.')
+
+ # Get the form
+ r = self.client.get(url_post)
+ self.assertEqual(r.status_code, 200)
+ q = PyQuery(unicontent(r))
+ self.assertEqual(len(q('form textarea[name=comment]')), 1)
+
+ # Post the comment
+ r = self.client.post(url_post, dict(comment="This is a test."))
+ self.assertEqual(r.status_code, 302)
+
+ # Get the main page again
+ r = self.client.get(url_page)
+ self.assertEqual(r.status_code, 200)
+ # Needs to have history
+ self.assertContains(r, 'History')
+ # But can't have the comment we are goint to add.
+ self.assertContains(r, 'This is a test.')
+
diff --git a/ietf/templates/doc/add_comment.html b/ietf/templates/doc/add_comment.html
index 01e12418d..211cb380d 100644
--- a/ietf/templates/doc/add_comment.html
+++ b/ietf/templates/doc/add_comment.html
@@ -2,13 +2,14 @@
{# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin %}
{% load django_bootstrap5 %}
-{% block title %}Add comment for {{ doc }}{% endblock %}
+{% block title %}Add comment for
+{% if review_req %} {{ review_req }} {% else %} {{ doc }} {% endif %} {% endblock %}
{% block content %}
{% origin %}
Add comment
- {{ doc }}
+ {% if review_req %} {{ review_req }} {% else %} {{ doc }} {% endif %}
{% bootstrap_button button_type="submit" content="Submit" %}
+ {% if review_req %}
+ Back
+ {% else %}
Back
+ {% endif %}
{% endblock %}
\ No newline at end of file
diff --git a/ietf/templates/doc/review/review_request.html b/ietf/templates/doc/review/review_request.html
index ccf3c1836..85335aab6 100644
--- a/ietf/templates/doc/review/review_request.html
+++ b/ietf/templates/doc/review/review_request.html
@@ -21,6 +21,15 @@
{% endif %}
History
+ {% if can_add_comment %}
+
+ {% endif %}
@@ -30,6 +39,7 @@
Description |
+
{% for h in history %}
{% if h.history_change_reason %}
@@ -39,6 +49,7 @@
{% endif %}
{% endfor %}
+
{% endblock %}