Let review teams opt in to poking a responsible AD when unhappy reviews are submitted. Fixes #2544. Commit ready for merge.
- Legacy-Id: 15675
This commit is contained in:
parent
542a85d949
commit
c7bf147b1d
|
@ -573,7 +573,7 @@ class ReviewTests(TestCase):
|
|||
test_file.name = "unnamed"
|
||||
|
||||
r = self.client.post(url, data={
|
||||
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
|
||||
"result": ReviewResultName.objects.get(reviewteamsettings_review_results_set__group=review_req.team, slug="ready").pk,
|
||||
"state": ReviewRequestStateName.objects.get(slug="completed").pk,
|
||||
"reviewed_rev": review_req.doc.rev,
|
||||
"review_submission": "upload",
|
||||
|
@ -627,7 +627,7 @@ class ReviewTests(TestCase):
|
|||
empty_outbox()
|
||||
|
||||
r = self.client.post(url, data={
|
||||
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
|
||||
"result": ReviewResultName.objects.get(reviewteamsettings_review_results_set__group=review_req.team, slug="ready").pk,
|
||||
"state": ReviewRequestStateName.objects.get(slug="completed").pk,
|
||||
"reviewed_rev": review_req.doc.rev,
|
||||
"review_submission": "enter",
|
||||
|
@ -649,6 +649,30 @@ class ReviewTests(TestCase):
|
|||
|
||||
self.assertTrue(settings.MAILING_LIST_ARCHIVE_URL in review_req.review.external_url)
|
||||
|
||||
def test_complete_notify_ad(self):
|
||||
review_req, url = self.setup_complete_review_test()
|
||||
review_req.team.reviewteamsettings.notify_ad_when.add(ReviewResultName.objects.get(slug='issues'))
|
||||
# TODO - it's a little surprising that the factories so far didn't give this doc an ad
|
||||
review_req.doc.ad = PersonFactory()
|
||||
review_req.doc.save_with_history([DocEvent.objects.create(doc=review_req.doc, rev=review_req.doc.rev, by=review_req.reviewer.person, type='changed_document',desc='added an AD')])
|
||||
login_testing_unauthorized(self, review_req.reviewer.person.user.username, url)
|
||||
|
||||
empty_outbox()
|
||||
|
||||
r = self.client.post(url, data={
|
||||
"result": ReviewResultName.objects.get(reviewteamsettings_review_results_set__group=review_req.team, slug="issues").pk,
|
||||
"state": ReviewRequestStateName.objects.get(slug="completed").pk,
|
||||
"reviewed_rev": review_req.doc.rev,
|
||||
"review_submission": "enter",
|
||||
"review_content": "This is a review\nwith two lines",
|
||||
"review_url": "",
|
||||
"review_file": "",
|
||||
})
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
||||
self.assertEqual(len(outbox), 2)
|
||||
self.assertIn('Has Issues', outbox[-1]['Subject'])
|
||||
|
||||
@patch('requests.get')
|
||||
def test_complete_review_link_to_mailing_list(self, mock):
|
||||
# Mock up the url response for the request.get() call to retrieve the mailing list url
|
||||
|
@ -665,7 +689,7 @@ class ReviewTests(TestCase):
|
|||
empty_outbox()
|
||||
|
||||
r = self.client.post(url, data={
|
||||
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
|
||||
"result": ReviewResultName.objects.get(reviewteamsettings_review_results_set__group=review_req.team, slug="ready").pk,
|
||||
"state": ReviewRequestStateName.objects.get(slug="completed").pk,
|
||||
"reviewed_rev": review_req.doc.rev,
|
||||
"review_submission": "link",
|
||||
|
@ -693,7 +717,7 @@ class ReviewTests(TestCase):
|
|||
empty_outbox()
|
||||
|
||||
r = self.client.post(url, data={
|
||||
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
|
||||
"result": ReviewResultName.objects.get(reviewteamsettings_review_results_set__group=review_req.team, slug="ready").pk,
|
||||
"state": ReviewRequestStateName.objects.get(slug="part-completed").pk,
|
||||
"reviewed_rev": review_req.doc.rev,
|
||||
"review_submission": "enter",
|
||||
|
@ -734,7 +758,7 @@ class ReviewTests(TestCase):
|
|||
url = urlreverse('ietf.doc.views_review.complete_review', kwargs={ "name": review_req.doc.name, "request_id": review_req.pk })
|
||||
|
||||
r = self.client.post(url, data={
|
||||
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
|
||||
"result": ReviewResultName.objects.get(reviewteamsettings_review_results_set__group=review_req.team, slug="ready").pk,
|
||||
"state": ReviewRequestStateName.objects.get(slug="completed").pk,
|
||||
"reviewed_rev": review_req.doc.rev,
|
||||
"review_submission": "enter",
|
||||
|
@ -766,7 +790,7 @@ class ReviewTests(TestCase):
|
|||
empty_outbox()
|
||||
|
||||
r = self.client.post(url, data={
|
||||
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
|
||||
"result": ReviewResultName.objects.get(reviewteamsettings_review_results_set__group=review_req.team, slug="ready").pk,
|
||||
"state": ReviewRequestStateName.objects.get(slug="completed").pk,
|
||||
"reviewed_rev": review_req.doc.rev,
|
||||
"review_submission": "enter",
|
||||
|
@ -791,7 +815,7 @@ class ReviewTests(TestCase):
|
|||
# revise again
|
||||
empty_outbox()
|
||||
r = self.client.post(url, data={
|
||||
"result": ReviewResultName.objects.get(reviewteamsettings__group=review_req.team, slug="ready").pk,
|
||||
"result": ReviewResultName.objects.get(reviewteamsettings_review_results_set__group=review_req.team, slug="ready").pk,
|
||||
"state": ReviewRequestStateName.objects.get(slug="part-completed").pk,
|
||||
"reviewed_rev": review_req.doc.rev,
|
||||
"review_submission": "enter",
|
||||
|
|
|
@ -12,6 +12,7 @@ import debug # pyflakes:ignore
|
|||
from django.http import HttpResponseForbidden, JsonResponse
|
||||
from django.shortcuts import render, get_object_or_404, redirect
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.utils.html import mark_safe
|
||||
from django.core.exceptions import ValidationError
|
||||
|
@ -25,6 +26,7 @@ from ietf.review.models import ReviewRequest
|
|||
from ietf.group.models import Group
|
||||
from ietf.ietfauth.utils import is_authorized_in_doc_stream, user_is_person, has_role
|
||||
from ietf.message.models import Message
|
||||
from ietf.message.utils import infer_message
|
||||
from ietf.person.fields import PersonEmailChoiceField, SearchablePersonField
|
||||
from ietf.review.utils import (active_review_teams, assign_review_request_to_reviewer,
|
||||
can_request_review_of_doc, can_manage_review_requests_for_team,
|
||||
|
@ -423,7 +425,7 @@ class CompleteReviewForm(forms.Form):
|
|||
" ".join("<a class=\"rev label label-default {0}\" title=\"{2:%Y-%m-%d}\">{1}</a>".format('', *r)
|
||||
for i, r in enumerate(known_revisions)))
|
||||
|
||||
self.fields["result"].queryset = self.fields["result"].queryset.filter(reviewteamsettings__group=review_req.team)
|
||||
self.fields["result"].queryset = self.fields["result"].queryset.filter(reviewteamsettings_review_results_set__group=review_req.team)
|
||||
|
||||
def format_submission_choice(label):
|
||||
if revising_review:
|
||||
|
@ -643,6 +645,19 @@ def complete_review(request, name, request_id):
|
|||
review.external_url = mailarch.construct_message_url(list_name, email.utils.unquote(msg["Message-ID"]))
|
||||
review.save_with_history([close_event])
|
||||
|
||||
if review_req.result in review_req.team.reviewteamsettings.notify_ad_when.all():
|
||||
(to, cc) = gather_address_lists('review_notify_ad',review_req = review_req)
|
||||
msg_txt = render_to_string("review/notify_ad.txt", {
|
||||
"to": to,
|
||||
"cc": cc,
|
||||
"review_req": review_req,
|
||||
"settings": settings,
|
||||
})
|
||||
msg = infer_message(msg_txt)
|
||||
msg.by = request.user.person
|
||||
msg.save()
|
||||
send_mail_message(request, msg)
|
||||
|
||||
return redirect("ietf.doc.views_doc.document_main", name=review_req.review.name)
|
||||
else:
|
||||
initial={
|
||||
|
|
40
ietf/mailtrigger/migrations/0003_add_review_notify_ad.py
Normal file
40
ietf/mailtrigger/migrations/0003_add_review_notify_ad.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2018-11-02 11:34
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
MailTrigger = apps.get_model('mailtrigger','MailTrigger')
|
||||
Recipient = apps.get_model('mailtrigger', 'Recipient')
|
||||
|
||||
Recipient.objects.create(
|
||||
slug = 'review_doc_ad',
|
||||
desc = "The reviewed document's responsible area director",
|
||||
template = '{% if review_req.doc.ad %}{{review_req.doc.ad.email_address}}{% endif %}'
|
||||
)
|
||||
|
||||
review_notify_ad = MailTrigger.objects.create(
|
||||
slug = 'review_notify_ad',
|
||||
desc = 'Recipients when a team notifies area directors when a review with one of a certain set of results (typically results indicating problem) is submitted',
|
||||
)
|
||||
review_notify_ad.to.set(Recipient.objects.filter(slug='review_doc_ad'))
|
||||
|
||||
|
||||
def reverse(apps, schema_editor):
|
||||
MailTrigger = apps.get_model('mailtrigger','MailTrigger')
|
||||
Recipient = apps.get_model('mailtrigger', 'Recipient')
|
||||
|
||||
MailTrigger.objects.filter(slug='review_notify_ad').delete()
|
||||
Recipient.objects.filter(slug='review_doc_ad').delete()
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mailtrigger', '0002_conflrev_changes'),
|
||||
('review', '0003_add_notify_ad_when'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward, reverse)
|
||||
]
|
File diff suppressed because it is too large
Load diff
|
@ -63,6 +63,6 @@ class ReviewTeamSettingsAdmin(admin.ModelAdmin):
|
|||
list_display = ["group", ]
|
||||
search_fields = ["group__acronym", ]
|
||||
raw_id_fields = ["group", ]
|
||||
filter_horizontal = ["review_types", "review_results", ]
|
||||
filter_horizontal = ["review_types", "review_results", "notify_ad_when"]
|
||||
|
||||
admin.site.register(ReviewTeamSettings, ReviewTeamSettingsAdmin)
|
||||
|
|
27
ietf/review/migrations/0003_add_notify_ad_when.py
Normal file
27
ietf/review/migrations/0003_add_notify_ad_when.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2018-11-02 10:10
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import ietf.review.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('name', '0004_add_prefix_to_doctypenames'),
|
||||
('review', '0002_unavailableperiod_reason'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='reviewteamsettings',
|
||||
name='notify_ad_when',
|
||||
field=models.ManyToManyField(related_name='reviewteamsettings_notify_ad_set', to='name.ReviewResultName'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='reviewteamsettings',
|
||||
name='review_results',
|
||||
field=models.ManyToManyField(default=ietf.review.models.get_default_review_results, related_name='reviewteamsettings_review_results_set', to='name.ReviewResultName'),
|
||||
),
|
||||
]
|
23
ietf/review/migrations/0004_set_secdir_notify_ad_when.py
Normal file
23
ietf/review/migrations/0004_set_secdir_notify_ad_when.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.16 on 2018-11-02 10:20
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
ReviewTeamSettings = apps.get_model('review','ReviewTeamSettings')
|
||||
ReviewTeamSettings.objects.get(group__acronym='secdir').notify_ad_when.set(['serious-issues', 'issues', 'not-ready'])
|
||||
|
||||
def reverse(apps, schema_editor):
|
||||
ReviewTeamSettings = apps.get_model('review','ReviewTeamSettings')
|
||||
ReviewTeamSettings.objects.get(group__acronym='secdir').notify_ad_when.set([])
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('review', '0003_add_notify_ad_when'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward, reverse)
|
||||
]
|
|
@ -160,7 +160,8 @@ class ReviewTeamSettings(models.Model):
|
|||
group = OneToOneField(Group)
|
||||
autosuggest = models.BooleanField(default=True, verbose_name="Automatically suggest possible review requests")
|
||||
review_types = models.ManyToManyField(ReviewTypeName, default=get_default_review_types)
|
||||
review_results = models.ManyToManyField(ReviewResultName, default=get_default_review_results)
|
||||
review_results = models.ManyToManyField(ReviewResultName, default=get_default_review_results, related_name='reviewteamsettings_review_results_set')
|
||||
notify_ad_when = models.ManyToManyField(ReviewResultName, related_name='reviewteamsettings_notify_ad_set')
|
||||
|
||||
def __unicode__(self):
|
||||
return u"%s" % (self.group.acronym,)
|
||||
|
|
|
@ -157,6 +157,7 @@ class ReviewTeamSettingsResource(ModelResource):
|
|||
group = ToOneField(GroupResource, 'group')
|
||||
review_types = ToManyField(ReviewTypeNameResource, 'review_types', null=True)
|
||||
review_results = ToManyField(ReviewResultNameResource, 'review_results', null=True)
|
||||
notify_ad_when = ToManyField(ReviewResultNameResource, 'notify_ad_when', null = True)
|
||||
class Meta:
|
||||
queryset = ReviewTeamSettings.objects.all()
|
||||
serializer = api.Serializer()
|
||||
|
@ -168,6 +169,7 @@ class ReviewTeamSettingsResource(ModelResource):
|
|||
"group": ALL_WITH_RELATIONS,
|
||||
"review_types": ALL_WITH_RELATIONS,
|
||||
"review_results": ALL_WITH_RELATIONS,
|
||||
"notify_ad_when": ALL_WITH_RELATIONS,
|
||||
}
|
||||
api.review.register(ReviewTeamSettingsResource())
|
||||
|
||||
|
|
12
ietf/templates/review/notify_ad.txt
Normal file
12
ietf/templates/review/notify_ad.txt
Normal file
|
@ -0,0 +1,12 @@
|
|||
{% load ietf_filters %}{% autoescape off %}From: {{settings.DEFAULT_FROM_EMAIL}}
|
||||
To: {{to}}{% if cc %}
|
||||
Cc: {{cc}}{% endif %}
|
||||
Subject: "{{review_req.result}}" review submitted for {{review_req.doc}}{% if review_req.reviewed_rev %}-{{review_req.reviewed_rev}}{% endif %}
|
||||
|
||||
{{review_req.reviewer.person.name}} has submitted a "{{review_req.result}}" review result for {{review_req.doc}}{% if review_req.reviewed_rev %}-{{review_req.reviewed_rev}}{% endif %}.
|
||||
|
||||
The review is available at {{settings.IDTRACKER_BASE_URL}}{% url 'ietf.doc.views_doc.document_main' name=review_req.review.name %}
|
||||
|
||||
The document is available at {{settings.IDTRACKER_BASE_URL}}{% url 'ietf.doc.views_doc.document_main' name=review_req.doc.name %}
|
||||
|
||||
{% endautoescape %}
|
Loading…
Reference in a new issue