Skip to content

Commit cc64992

Browse files
author
Sasha Romijn
committed
Refs ietf-tools#2277 - Send daily reminders of overdue reviews to secretaries
Commit ready for merge. - Legacy-Id: 16765
1 parent ec56a03 commit cc64992

6 files changed

Lines changed: 118 additions & 3 deletions

File tree

ietf/bin/send-review-reminders

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ import datetime
2424
from ietf.review.utils import (
2525
review_assignments_needing_reviewer_reminder, email_reviewer_reminder,
2626
review_assignments_needing_secretary_reminder, email_secretary_reminder,
27-
email_unavaibility_period_ending_reminder, email_reminder_all_open_reviews)
27+
email_unavaibility_period_ending_reminder, email_reminder_all_open_reviews,
28+
email_review_reminder_overdue_assignment)
2829

2930
today = datetime.date.today()
3031

@@ -39,4 +40,5 @@ for assignment, secretary_role in review_assignments_needing_secretary_reminder(
3940
print("Emailed reminder to {} for review of {} in {} (req. id {})".format(secretary_role.email.address, review_req.doc_id, review_req.team.acronym, review_req.pk))
4041

4142
print('\n'.join(email_unavaibility_period_ending_reminder(today)))
43+
print('\n'.join(email_review_reminder_overdue_assignment(today)))
4244
print('\n'.join(email_reminder_all_open_reviews(today)))

ietf/group/tests_review.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
review_assignments_needing_reviewer_reminder, email_reviewer_reminder,
2424
review_assignments_needing_secretary_reminder, email_secretary_reminder,
2525
reviewer_rotation_list,
26-
email_unavaibility_period_ending_reminder, email_reminder_all_open_reviews)
26+
email_unavaibility_period_ending_reminder, email_reminder_all_open_reviews,
27+
email_review_reminder_overdue_assignment)
2728
from ietf.name.models import ReviewResultName, ReviewRequestStateName, ReviewAssignmentStateName
2829
import ietf.group.views
2930
from ietf.utils.mail import outbox, empty_outbox
@@ -548,6 +549,26 @@ def test_email_unavaibility_period_ending_reminder(self):
548549
self.assertTrue(reviewer.person.name in log[0])
549550
self.assertTrue(review_team.acronym in log[0])
550551

552+
def test_email_review_reminder_overdue_assignment(self):
553+
today = datetime.date.today()
554+
review_req = ReviewRequestFactory(state_id='assigned', deadline=today - datetime.timedelta(5))
555+
reviewer = RoleFactory(name_id='reviewer', group=review_req.team,person__user__username='reviewer').person
556+
ReviewAssignmentFactory(review_request=review_req, state_id='assigned', assigned_on=review_req.time, reviewer=reviewer.email_set.first())
557+
secretary = RoleFactory(name_id='secr', group=review_req.team, person__user__username='reviewsecretary')
558+
559+
empty_outbox()
560+
log = email_review_reminder_overdue_assignment(today)
561+
562+
self.assertEqual(len(outbox), 1)
563+
self.assertTrue(secretary.person.email_address() in outbox[0]["To"])
564+
self.assertEqual(outbox[0]["Subject"], "1 Overdue review for team {}".format(review_req.team.acronym))
565+
message = outbox[0].get_payload(decode=True).decode("utf-8")
566+
self.assertTrue(review_req.team.acronym + ' has 1 accepted or assigned review overdue by at least 5 days.' in message)
567+
self.assertTrue('Review of {} by {}'.format(review_req.doc.name, reviewer.name) in message)
568+
self.assertEqual(len(log), 1)
569+
self.assertTrue(secretary.person.email_address() in log[0])
570+
self.assertTrue('1 overdue review' in log[0])
571+
551572
def test_email_reminder_all_open_reviews(self):
552573
review_req = ReviewRequestFactory(state_id='assigned')
553574
reviewer = RoleFactory(name_id='reviewer', group=review_req.team,person__user__username='reviewer').person
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Copyright The IETF Trust 2019, All Rights Reserved
2+
# -*- coding: utf-8 -*-
3+
4+
from __future__ import absolute_import, print_function, unicode_literals
5+
6+
from django.db import migrations
7+
8+
9+
def forward(apps, schema_editor):
10+
MailTrigger = apps.get_model('mailtrigger', 'MailTrigger')
11+
Recipient = apps.get_model('mailtrigger', 'Recipient')
12+
13+
review_reminder_overdue_assignment = MailTrigger.objects.create(
14+
slug="review_reminder_overdue_assignment",
15+
desc="Recipients for overdue review assignment reminders",
16+
)
17+
review_reminder_overdue_assignment.to.add(
18+
Recipient.objects.get(slug='group_secretaries')
19+
)
20+
21+
22+
def reverse(apps, schema_editor):
23+
MailTrigger = apps.get_model('mailtrigger', 'MailTrigger')
24+
MailTrigger.objects.filter(slug='review_reminder_overdue_assignment').delete()
25+
26+
27+
class Migration(migrations.Migration):
28+
29+
dependencies = [
30+
('mailtrigger', '0009_custom_review_complete_mailtriggers'),
31+
]
32+
33+
operations = [
34+
migrations.RunPython(forward, reverse)
35+
]

ietf/name/fixtures/names.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4164,6 +4164,17 @@
41644164
"cc": []
41654165
}
41664166
},
4167+
{
4168+
"model": "mailtrigger.mailtrigger",
4169+
"pk": "review_reminder_overdue_assignment",
4170+
"fields": {
4171+
"desc": "Recipients for overdue review assignment reminders",
4172+
"to": [
4173+
"group_secretaries"
4174+
],
4175+
"cc": []
4176+
}
4177+
},
41674178
{
41684179
"fields": {
41694180
"desc": "The person providing a comment to nomcom",

ietf/review/utils.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
from ietf.mailtrigger.utils import gather_address_lists
2727
from ietf.person.models import Person
2828
from ietf.ietfauth.utils import has_role, is_authorized_in_doc_stream
29-
from ietf.review.models import (ReviewRequest, ReviewAssignment, ReviewRequestStateName, ReviewTypeName,
29+
from ietf.review.models import (ReviewRequest, ReviewAssignment, ReviewRequestStateName,
30+
ReviewTypeName,
3031
ReviewerSettings, UnavailablePeriod, ReviewWish, NextReviewerInTeam,
3132
ReviewSecretarySettings)
3233
from ietf.utils.mail import send_mail
@@ -959,6 +960,37 @@ def email_unavaibility_period_ending_reminder(remind_date):
959960
return log
960961

961962

963+
def email_review_reminder_overdue_assignment(remind_date):
964+
min_overdue_days = 5
965+
min_deadline = remind_date + datetime.timedelta(days=min_overdue_days)
966+
teams = Group.objects.exclude(reviewteamsettings=None)
967+
log = []
968+
for team in teams:
969+
assignments = ReviewAssignment.objects.filter(
970+
state__in=("assigned", "accepted"),
971+
review_request__deadline__lte=min_deadline,
972+
review_request__team=team,
973+
)
974+
if not assignments:
975+
continue
976+
977+
(to, cc) = gather_address_lists('review_reminder_overdue_assignment', group=team)
978+
domain = Site.objects.get_current().domain
979+
subject = "{} Overdue review{} for team {}".format(
980+
len(assignments), pluralize(len(assignments)), team.acronym)
981+
982+
send_mail(None, to, None, subject, "review/review_reminder_overdue_assignment.txt", {
983+
"domain": domain,
984+
"assignments": assignments,
985+
"team": team,
986+
"min_overdue_days": min_overdue_days,
987+
}, cc=cc)
988+
log.append("Emailed reminder to {} about {} overdue reviews in {}".format(
989+
to, assignments.count(), team.acronym,
990+
))
991+
return log
992+
993+
962994
def email_reminder_all_open_reviews(remind_date):
963995
log = []
964996
# The origin date is arbitrarily chosen, to have a single reference date for "every X days"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{% load ietf_filters %}{% autoescape off %}{% filter wordwrap:78 %}
2+
Team {{ team.acronym }} has {{ assignments|length }} accepted or assigned review{{ assignments|length|pluralize }} overdue by at least {{ min_overdue_days }} days.
3+
4+
All reviews overdue by at least {{ min_overdue_days }} days are listed below, including links to mark each of them as no response.
5+
6+
{% for assignment in assignments %}
7+
Review of {{ assignment.review_request.doc }} by {{ assignment.reviewer.person }}
8+
https://{{ domain }}{% url 'ietf.doc.views_review.mark_reviewer_assignment_no_response' name=assignment.review_request.doc.name assignment_id=assignment.pk %}
9+
10+
{% endfor %}
11+
12+
This reminder will be sent daily.
13+
14+
{% endfilter %}{% endautoescape %}

0 commit comments

Comments
 (0)