Skip to content

Commit

Permalink
refactor: send_nomcom_reminders via celery task (#7424)
Browse files Browse the repository at this point in the history
* refactor: send_reminders.py -> celery task

* chore: add PeriodicTask

* chore: remove management command and tests
  • Loading branch information
jennifer-richards committed May 15, 2024
1 parent c9f3598 commit c59d612
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 51 deletions.
37 changes: 0 additions & 37 deletions ietf/nomcom/management/commands/send_reminders.py

This file was deleted.

10 changes: 10 additions & 0 deletions ietf/nomcom/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright The IETF Trust 2024, All Rights Reserved

from celery import shared_task

from .utils import send_reminders


@shared_task
def send_nomcom_reminders_task():
send_reminders()
40 changes: 26 additions & 14 deletions ietf/nomcom/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@
NomineePositionStateName, Feedback, FeedbackTypeName, \
Nomination, FeedbackLastSeen, TopicFeedbackLastSeen, ReminderDates, \
NomCom
from ietf.nomcom.management.commands.send_reminders import Command, is_time_to_send
from ietf.nomcom.factories import NomComFactory, FeedbackFactory, TopicFactory, \
nomcom_kwargs_for_year, provide_private_key_to_test_client, \
key
from ietf.nomcom.tasks import send_nomcom_reminders_task
from ietf.nomcom.utils import get_nomcom_by_year, make_nomineeposition, \
get_hash_nominee_position, is_eligible, list_eligible, \
get_eligibility_date, suggest_affiliation, ingest_feedback_email, \
decorate_volunteers_with_qualifications
decorate_volunteers_with_qualifications, send_reminders, _is_time_to_send_reminder
from ietf.person.factories import PersonFactory, EmailFactory
from ietf.person.models import Email, Person
from ietf.stats.models import MeetingRegistration
Expand Down Expand Up @@ -1207,36 +1207,41 @@ def tearDown(self):
teardown_test_public_keys_dir(self)
super().tearDown()

def test_is_time_to_send(self):
def test_is_time_to_send_reminder(self):
self.nomcom.reminder_interval = 4
today = date_today()
self.assertTrue(is_time_to_send(self.nomcom,today+datetime.timedelta(days=4),today))
self.assertTrue(
_is_time_to_send_reminder(self.nomcom, today + datetime.timedelta(days=4), today)
)
for delta in range(4):
self.assertFalse(is_time_to_send(self.nomcom,today+datetime.timedelta(days=delta),today))
self.assertFalse(
_is_time_to_send_reminder(
self.nomcom, today + datetime.timedelta(days=delta), today
)
)
self.nomcom.reminder_interval = None
self.assertFalse(is_time_to_send(self.nomcom,today,today))
self.assertFalse(_is_time_to_send_reminder(self.nomcom, today, today))
self.nomcom.reminderdates_set.create(date=today)
self.assertTrue(is_time_to_send(self.nomcom,today,today))
self.assertTrue(_is_time_to_send_reminder(self.nomcom, today, today))

def test_command(self):
c = Command()
messages_before=len(outbox)
def test_send_reminders(self):
messages_before = len(outbox)
self.nomcom.reminder_interval = 3
self.nomcom.save()
c.handle(None,None)
send_reminders()
self.assertEqual(len(outbox), messages_before + 2)
self.assertIn('nominee1@example.org', outbox[-1]['To'])
self.assertIn('please complete', outbox[-1]['Subject'])
self.assertIn('nominee1@example.org', outbox[-2]['To'])
self.assertIn('please accept', outbox[-2]['Subject'])
messages_before=len(outbox)
messages_before = len(outbox)
self.nomcom.reminder_interval = 4
self.nomcom.save()
c.handle(None,None)
send_reminders()
self.assertEqual(len(outbox), messages_before + 1)
self.assertIn('nominee2@example.org', outbox[-1]['To'])
self.assertIn('please accept', outbox[-1]['Subject'])

def test_remind_accept_view(self):
url = reverse('ietf.nomcom.views.send_reminder_mail', kwargs={'year': NOMCOM_YEAR,'type':'accept'})
login_testing_unauthorized(self, CHAIR_USER, url)
Expand Down Expand Up @@ -3048,3 +3053,10 @@ def test_reclassify_feedback_unrelated(self):
self.assertEqual(fb.type_id, 'junk')
self.assertEqual(Feedback.objects.filter(type='read').count(), 0)
self.assertEqual(Feedback.objects.filter(type='junk').count(), 1)


class TaskTests(TestCase):
@mock.patch("ietf.nomcom.tasks.send_reminders")
def test_send_nomcom_reminders_task(self, mock_send):
send_nomcom_reminders_task()
self.assertEqual(mock_send.call_count, 1)
24 changes: 24 additions & 0 deletions ietf/nomcom/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -747,3 +747,27 @@ def ingest_feedback_email(message: bytes, year: int):
email_original_message=message,
) from err
log("Received nomcom email from %s" % feedback.author)


def _is_time_to_send_reminder(nomcom, send_date, nomination_date):
if nomcom.reminder_interval:
days_passed = (send_date - nomination_date).days
return days_passed > 0 and days_passed % nomcom.reminder_interval == 0
else:
return bool(nomcom.reminderdates_set.filter(date=send_date))


def send_reminders():
from .models import NomCom, NomineePosition
for nomcom in NomCom.objects.filter(group__state__slug="active"):
nps = NomineePosition.objects.filter(
nominee__nomcom=nomcom, nominee__duplicated__isnull=True
)
for nominee_position in nps.pending():
if _is_time_to_send_reminder(nomcom, date_today(), nominee_position.time.date()):
send_accept_reminder_to_nominee(nominee_position)
log(f"Sent accept reminder to {nominee_position.nominee.email.address}")
for nominee_position in nps.accepted().without_questionnaire_response():
if _is_time_to_send_reminder(nomcom, date_today(), nominee_position.time.date()):
send_questionnaire_reminder_to_nominee(nominee_position)
log(f"Sent questionnaire reminder to {nominee_position.nominee.email.address}")
10 changes: 10 additions & 0 deletions ietf/utils/management/commands/periodic_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,16 @@ def create_default_tasks(self):
),
)

PeriodicTask.objects.get_or_create(
name="Send NomCom reminders",
task="ietf.nomcom.tasks.send_nomcom_reminders_task",
defaults=dict(
enabled=False,
crontab=self.crontabs["daily"],
description="Send acceptance and questionnaire reminders to nominees",
),
)

def show_tasks(self):
for label, crontab in self.crontabs.items():
tasks = PeriodicTask.objects.filter(crontab=crontab).order_by(
Expand Down

0 comments on commit c59d612

Please sign in to comment.