Skip to content

Commit 16e2848

Browse files
committed
Add page for emailing open review assignments summary to the review team list
- Legacy-Id: 11846
1 parent 0958bcb commit 16e2848

7 files changed

Lines changed: 119 additions & 3 deletions

File tree

ietf/group/tests_review.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from ietf.person.models import Email, Person
1313
from ietf.review.utils import suggested_review_requests_for_team
1414
import ietf.group.views_review
15+
from ietf.utils.mail import outbox, empty_outbox
1516

1617
class ReviewTests(TestCase):
1718
def test_suggested_review_requests(self):
@@ -79,7 +80,7 @@ def test_manage_review_requests(self):
7980

8081
group = review_req1.team
8182

82-
url = urlreverse(ietf.group.views_review.manage_review_requests, kwargs={ 'acronym': group.acronym })
83+
url = urlreverse(ietf.group.views_review.manage_review_requests, kwargs={ 'acronym': group.acronym, 'group_type': group.type_id })
8384

8485
login_testing_unauthorized(self, "secretary", url)
8586

@@ -161,3 +162,31 @@ def test_manage_review_requests(self):
161162
self.assertEqual(review_req2.state_id, "requested")
162163
self.assertEqual(review_req2.reviewer, new_reviewer)
163164
self.assertEqual(review_req3.state_id, "requested")
165+
166+
def test_email_open_review_assignments(self):
167+
doc = make_test_data()
168+
review_req1 = make_review_data(doc)
169+
170+
group = review_req1.team
171+
172+
url = urlreverse(ietf.group.views_review.email_open_review_assignments, kwargs={ 'acronym': group.acronym, 'group_type': group.type_id })
173+
174+
login_testing_unauthorized(self, "secretary", url)
175+
176+
r = self.client.get(url)
177+
self.assertEqual(r.status_code, 200)
178+
self.assertTrue(review_req1.doc.name in unicontent(r))
179+
180+
empty_outbox()
181+
r = self.client.post(url, {
182+
"to": group.list_email,
183+
"subject": "Test subject",
184+
"body": "Test body",
185+
"action": "email",
186+
})
187+
self.assertEqual(r.status_code, 302)
188+
self.assertEqual(len(outbox), 1)
189+
self.assertTrue(group.list_email in outbox[0]["To"])
190+
self.assertEqual(outbox[0]["subject"], "Test subject")
191+
self.assertTrue("Test body" in unicode(outbox[0]))
192+

ietf/group/urls_info_details.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,6 @@
3232
(r'^photos/$', views.group_photos),
3333
(r'^reviews/$', views.review_requests),
3434
(r'^reviews/manage/$', views_review.manage_review_requests),
35+
(r'^reviews/email-assignments/$', views_review.email_open_review_assignments),
3536
url(r'^email-aliases/$', RedirectView.as_view(pattern_name='ietf.group.views.email',permanent=False),name='old_group_email_aliases'),
3637
)

ietf/group/views_review.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@
22
from django.http import Http404, HttpResponseForbidden
33
from django.contrib.auth.decorators import login_required
44
from django import forms
5+
from django.template.loader import render_to_string
56

67
from ietf.review.models import ReviewRequest
78
from ietf.review.utils import (can_manage_review_requests_for_team, close_review_request_states,
89
extract_revision_ordered_review_requests_for_documents,
910
assign_review_request_to_reviewer,
1011
close_review_request,
1112
setup_reviewer_field,
12-
# make_new_review_request_from_existing,
1313
suggested_review_requests_for_team)
1414
from ietf.group.utils import get_group_or_404
1515
from ietf.person.fields import PersonEmailChoiceField
16+
from ietf.utils.mail import send_mail_text
1617

1718

1819
class ManageReviewRequestForm(forms.Form):
@@ -168,3 +169,53 @@ def manage_review_requests(request, acronym, group_type=None):
168169
'saving': saving,
169170
})
170171

172+
class EmailOpenAssignmentsForm(forms.Form):
173+
to = forms.EmailField(widget=forms.EmailInput(attrs={ "readonly": True }))
174+
subject = forms.CharField()
175+
body = forms.CharField(widget=forms.Textarea)
176+
177+
@login_required
178+
def email_open_review_assignments(request, acronym, group_type=None):
179+
group = get_group_or_404(acronym, group_type)
180+
if not group.features.has_reviews:
181+
raise Http404
182+
183+
if not can_manage_review_requests_for_team(request.user, group):
184+
return HttpResponseForbidden("You do not have permission to perform this action")
185+
186+
review_requests = list(ReviewRequest.objects.filter(
187+
team=group,
188+
state__in=("requested", "accepted"),
189+
).exclude(
190+
reviewer=None,
191+
).prefetch_related("reviewer", "type", "state", "doc").distinct().order_by("deadline", "reviewer"))
192+
193+
if request.method == "POST" and request.POST.get("action") == "email":
194+
form = EmailOpenAssignmentsForm(request.POST)
195+
if form.is_valid():
196+
send_mail_text(request, form.cleaned_data["to"], None, form.cleaned_data["subject"], form.cleaned_data["body"])
197+
198+
kwargs = { "acronym": group.acronym }
199+
if group_type:
200+
kwargs["group_type"] = group_type
201+
202+
return redirect(manage_review_requests, **kwargs)
203+
else:
204+
to = group.list_email
205+
subject = "Open review assignments in {}".format(group.acronym)
206+
body = render_to_string("group/email_open_review_assignments.txt", {
207+
"review_requests": review_requests,
208+
})
209+
210+
form = EmailOpenAssignmentsForm(initial={
211+
"to": to,
212+
"subject": subject,
213+
"body": body,
214+
})
215+
216+
return render(request, 'group/email_open_review_assignments.html', {
217+
'group': group,
218+
'review_requests': review_requests,
219+
'form': form,
220+
})
221+

ietf/static/ietf/css/ietf.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,11 @@ form.review-requests label {
500500
padding-right: 0.3em;
501501
}
502502

503+
form.email-open-review-assignments [name=body] {
504+
height: 50em;
505+
font-family: monospace;
506+
}
507+
503508
/* Profile */
504509

505510
.photo-name {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{% extends "base.html" %}
2+
{# Copyright The IETF Trust 2015, All Rights Reserved #}
3+
{% load origin %}{% origin %}
4+
5+
{% load ietf_filters staticfiles bootstrap3 %}
6+
7+
{% block title %}Email summary of assigned review requests for {{ group.acronym }}{% endblock %}
8+
9+
{% block content %}
10+
{% origin %}
11+
12+
<h1>Email summary of assigned review requests for {{ group.acronym }}</h1>
13+
14+
{% if review_requests %}
15+
<form class="email-open-review-assignments" method="post">{% csrf_token %}
16+
{% bootstrap_form form %}
17+
18+
{% buttons %}
19+
<a href="{% url "ietf.group.views_review.manage_review_requests" group_type=group.type_id acronym=group.acronym %}" class="btn btn-default pull-right">Cancel</a>
20+
<button class="btn btn-primary" type="submit" name="action" value="email">Send to team mailing list</button>
21+
{% endbuttons %}
22+
</form>
23+
{% else %}
24+
<p>There are currently no open requests.</p>
25+
{% endif %}
26+
{% endblock %}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{% autoescape off %}
2+
Reviewer Deadline Draft
3+
{% for r in review_requests %}{{ r.reviewer.person.plain_name|ljust:"22" }} {{ r.deadline|date:"Y-m-d" }} {{ r.doc_id }}-{% if r.requested_rev %}{{ r.requested_rev }}{% else %}{{ r.doc.rev }}{% endif %}
4+
{% endfor %}{% endautoescape %}

ietf/templates/group/manage_review_requests.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ <h1>Manage open review requests for {{ group.acronym }}</h1>
1717

1818
<p>Other options:
1919
<a href="{% url "ietf.group.views.review_requests" group_type=group.type_id acronym=group.acronym %}#closed-review-requests">Closed review requests</a>
20-
- <a href="FIXME">Email open assignments summary</a>
20+
- <a href="{% url "ietf.group.views_review.email_open_review_assignments" group_type=group.type_id acronym=group.acronym %}">Email open assignments summary</a>
2121
</p>
2222

2323
{% if newly_closed > 0 or newly_opened > 0 or newly_assigned > 0 %}

0 commit comments

Comments
 (0)