Commit eff9c9c9 by Calen Pennington

Move common attributes into Resolver.__init__

parent 27fd73ac
...@@ -2,6 +2,7 @@ import datetime ...@@ -2,6 +2,7 @@ import datetime
from itertools import groupby from itertools import groupby
import logging import logging
import attr
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
...@@ -42,6 +43,8 @@ RECURRING_NUDGE_NUM_BINS = DEFAULT_NUM_BINS ...@@ -42,6 +43,8 @@ RECURRING_NUDGE_NUM_BINS = DEFAULT_NUM_BINS
UPGRADE_REMINDER_NUM_BINS = DEFAULT_NUM_BINS UPGRADE_REMINDER_NUM_BINS = DEFAULT_NUM_BINS
COURSE_UPDATE_NUM_BINS = DEFAULT_NUM_BINS COURSE_UPDATE_NUM_BINS = DEFAULT_NUM_BINS
@attr.s
class BinnedSchedulesBaseResolver(PrefixedDebugLoggerMixin, RecipientResolver): class BinnedSchedulesBaseResolver(PrefixedDebugLoggerMixin, RecipientResolver):
""" """
Starts num_bins number of async tasks, each of which sends emails to an equal group of learners. Starts num_bins number of async tasks, each of which sends emails to an equal group of learners.
...@@ -55,6 +58,15 @@ class BinnedSchedulesBaseResolver(PrefixedDebugLoggerMixin, RecipientResolver): ...@@ -55,6 +58,15 @@ class BinnedSchedulesBaseResolver(PrefixedDebugLoggerMixin, RecipientResolver):
num_bins -- the int number of bins to split the users into num_bins -- the int number of bins to split the users into
enqueue_config_var -- the string field name of the config variable on ScheduleConfig to check before enqueuing enqueue_config_var -- the string field name of the config variable on ScheduleConfig to check before enqueuing
""" """
async_send_task = attr.ib()
site = attr.ib()
target_datetime = attr.ib()
day_offset = attr.ib()
bin_num = attr.ib()
org_list = attr.ib()
exclude_orgs = attr.ib(default=False)
override_recipient_email = attr.ib(default=None)
def send(self, msg_type): def send(self, msg_type):
pass pass
...@@ -156,45 +168,35 @@ class ScheduleStartResolver(BinnedSchedulesBaseResolver): ...@@ -156,45 +168,35 @@ class ScheduleStartResolver(BinnedSchedulesBaseResolver):
""" """
log_prefix = 'Scheduled Nudge' log_prefix = 'Scheduled Nudge'
def schedule_bin( def schedule_bin(self):
self, async_send_task, site, target_datetime, day_offset, bin_num, org_list, exclude_orgs=False, override_recipient_email=None, msg_type = RecurringNudge(abs(self.day_offset))
): _annotate_for_monitoring(msg_type, self.site, self.bin_num, self.target_datetime, self.day_offset)
# TODO: in the next refactor of this task, pass in current_datetime instead of reproducing it here
current_datetime = target_datetime - datetime.timedelta(days=day_offset) for (user, language, context) in self.schedules_for_bin():
msg_type = RecurringNudge(abs(day_offset))
_annotate_for_monitoring(msg_type, site, bin_num, target_datetime, day_offset)
for (user, language, context) in self.schedules_for_bin(
site,
current_datetime,
target_datetime,
bin_num,
org_list,
exclude_orgs
):
msg = msg_type.personalize( msg = msg_type.personalize(
Recipient( Recipient(
user.username, user.username,
override_recipient_email or user.email, self.override_recipient_email or user.email,
), ),
language, language,
context, context,
) )
with function_trace('enqueue_send_task'): with function_trace('enqueue_send_task'):
async_send_task.apply_async( self.async_send_task.apply_async(
(site.id, str(msg)), retry=False) (self.site.id, str(msg)), retry=False)
def schedules_for_bin(self):
# TODO: in the next refactor of this task, pass in current_datetime instead of reproducing it here
current_datetime = self.target_datetime - datetime.timedelta(days=self.day_offset)
def schedules_for_bin(self, site, current_datetime, target_datetime, bin_num, org_list, exclude_orgs=False):
schedules = get_schedules_with_target_date_by_bin_and_orgs( schedules = get_schedules_with_target_date_by_bin_and_orgs(
schedule_date_field='start', schedule_date_field='start',
current_datetime=current_datetime, current_datetime=current_datetime,
target_datetime=target_datetime, target_datetime=self.target_datetime,
bin_num=bin_num, bin_num=self.bin_num,
num_bins=RECURRING_NUDGE_NUM_BINS, num_bins=RECURRING_NUDGE_NUM_BINS,
org_list=org_list, org_list=self.org_list,
exclude_orgs=exclude_orgs, exclude_orgs=self.exclude_orgs,
) )
LOG.debug('Recurring Nudge: Query = %r', schedules.query.sql_with_params()) LOG.debug('Recurring Nudge: Query = %r', schedules.query.sql_with_params())
...@@ -204,12 +206,12 @@ class ScheduleStartResolver(BinnedSchedulesBaseResolver): ...@@ -204,12 +206,12 @@ class ScheduleStartResolver(BinnedSchedulesBaseResolver):
course_id_strs = [str(schedule.enrollment.course_id) for schedule in user_schedules] course_id_strs = [str(schedule.enrollment.course_id) for schedule in user_schedules]
first_schedule = user_schedules[0] first_schedule = user_schedules[0]
template_context = get_base_template_context(site) template_context = get_base_template_context(self.site)
template_context.update({ template_context.update({
'student_name': user.profile.name, 'student_name': user.profile.name,
'course_name': first_schedule.enrollment.course.display_name, 'course_name': first_schedule.enrollment.course.display_name,
'course_url': absolute_url(site, reverse('course_root', args=[str(first_schedule.enrollment.course_id)])), 'course_url': absolute_url(self.site, reverse('course_root', args=[str(first_schedule.enrollment.course_id)])),
# This is used by the bulk email optout policy # This is used by the bulk email optout policy
'course_ids': course_id_strs, 'course_ids': course_id_strs,
...@@ -238,45 +240,34 @@ class UpgradeReminderResolver(BinnedSchedulesBaseResolver): ...@@ -238,45 +240,34 @@ class UpgradeReminderResolver(BinnedSchedulesBaseResolver):
""" """
log_prefix = 'Upgrade Reminder' log_prefix = 'Upgrade Reminder'
def schedule_bin( def schedule_bin(self):
self, async_send_task, site, target_datetime, day_offset, bin_num, org_list, exclude_orgs=False, override_recipient_email=None,
):
# TODO: in the next refactor of this task, pass in current_datetime instead of reproducing it here
current_datetime = target_datetime - datetime.timedelta(days=day_offset)
msg_type = UpgradeReminder() msg_type = UpgradeReminder()
_annotate_for_monitoring(msg_type, self.site, self.bin_num, self.target_datetime, self.day_offset)
_annotate_for_monitoring(msg_type, site, bin_num, target_datetime, day_offset) for (user, language, context) in self.schedules_for_bin():
for (user, language, context) in self.schedules_for_bin(
site,
current_datetime,
target_datetime,
bin_num,
org_list,
exclude_orgs
):
msg = msg_type.personalize( msg = msg_type.personalize(
Recipient( Recipient(
user.username, user.username,
override_recipient_email or user.email, self.override_recipient_email or user.email,
), ),
language, language,
context, context,
) )
with function_trace('enqueue_send_task'): with function_trace('enqueue_send_task'):
async_send_task.apply_async( self.async_send_task.apply_async(
(site.id, str(msg)), retry=False) (self.site.id, str(msg)), retry=False)
def schedules_for_bin(self, site, current_datetime, target_datetime, bin_num, org_list, exclude_orgs=False): def schedules_for_bin(self):
# TODO: in the next refactor of this task, pass in current_datetime instead of reproducing it here
current_datetime = self.target_datetime - datetime.timedelta(days=self.day_offset)
schedules = get_schedules_with_target_date_by_bin_and_orgs( schedules = get_schedules_with_target_date_by_bin_and_orgs(
schedule_date_field='upgrade_deadline', schedule_date_field='upgrade_deadline',
current_datetime=current_datetime, current_datetime=current_datetime,
target_datetime=target_datetime, target_datetime=self.target_datetime,
bin_num=bin_num, bin_num=self.bin_num,
num_bins=RECURRING_NUDGE_NUM_BINS, num_bins=RECURRING_NUDGE_NUM_BINS,
org_list=org_list, org_list=self.org_list,
exclude_orgs=exclude_orgs, exclude_orgs=self.exclude_orgs,
) )
for (user, user_schedules) in groupby(schedules, lambda s: s.enrollment.user): for (user, user_schedules) in groupby(schedules, lambda s: s.enrollment.user):
...@@ -284,17 +275,17 @@ class UpgradeReminderResolver(BinnedSchedulesBaseResolver): ...@@ -284,17 +275,17 @@ class UpgradeReminderResolver(BinnedSchedulesBaseResolver):
course_id_strs = [str(schedule.enrollment.course_id) for schedule in user_schedules] course_id_strs = [str(schedule.enrollment.course_id) for schedule in user_schedules]
first_schedule = user_schedules[0] first_schedule = user_schedules[0]
template_context = get_base_template_context(site) template_context = get_base_template_context(self.site)
template_context.update({ template_context.update({
'student_name': user.profile.name, 'student_name': user.profile.name,
'course_links': [ 'course_links': [
{ {
'url': absolute_url(site, reverse('course_root', args=[str(s.enrollment.course_id)])), 'url': absolute_url(self.site, reverse('course_root', args=[str(s.enrollment.course_id)])),
'name': s.enrollment.course.display_name 'name': s.enrollment.course.display_name
} for s in user_schedules } for s in user_schedules
], ],
'first_course_name': first_schedule.enrollment.course.display_name, 'first_course_name': first_schedule.enrollment.course.display_name,
'cert_image': absolute_url(site, static('course_experience/images/verified-cert.png')), 'cert_image': absolute_url(self.site, static('course_experience/images/verified-cert.png')),
# This is used by the bulk email optout policy # This is used by the bulk email optout policy
'course_ids': course_id_strs, 'course_ids': course_id_strs,
...@@ -346,47 +337,35 @@ class CourseUpdateResolver(BinnedSchedulesBaseResolver): ...@@ -346,47 +337,35 @@ class CourseUpdateResolver(BinnedSchedulesBaseResolver):
""" """
log_prefix = 'Course Update' log_prefix = 'Course Update'
def schedule_bin( def schedule_bin(self):
self, async_send_task, site, target_datetime, day_offset, bin_num, org_list, exclude_orgs=False, override_recipient_email=None,
):
# TODO: in the next refactor of this task, pass in current_datetime instead of reproducing it here
current_datetime = target_datetime - datetime.timedelta(days=day_offset)
msg_type = CourseUpdate() msg_type = CourseUpdate()
_annotate_for_monitoring(msg_type, self.site, self.bin_num, self.target_datetime, self.day_offset)
_annotate_for_monitoring(msg_type, site, bin_num, target_datetime, day_offset) for (user, language, context) in self._course_update_schedules_for_bin():
for (user, language, context) in self._course_update_schedules_for_bin(
site,
current_datetime,
target_datetime,
day_offset,
bin_num,
org_list,
exclude_orgs
):
msg = msg_type.personalize( msg = msg_type.personalize(
Recipient( Recipient(
user.username, user.username,
override_recipient_email or user.email, self.override_recipient_email or user.email,
), ),
language, language,
context, context,
) )
with function_trace('enqueue_send_task'): with function_trace('enqueue_send_task'):
async_send_task.apply_async( self.async_send_task.apply_async(
(site.id, str(msg)), retry=False) (self.site.id, str(msg)), retry=False)
def schedules_for_bin(self, site, current_datetime, target_datetime, day_offset, bin_num, org_list, def schedules_for_bin(self):
exclude_orgs=False): # TODO: in the next refactor of this task, pass in current_datetime instead of reproducing it here
week_num = abs(day_offset) / 7 current_datetime = self.target_datetime - datetime.timedelta(days=self.day_offset)
week_num = abs(self.day_offset) / 7
schedules = get_schedules_with_target_date_by_bin_and_orgs( schedules = get_schedules_with_target_date_by_bin_and_orgs(
schedule_date_field='start', schedule_date_field='start',
current_datetime=current_datetime, current_datetime=current_datetime,
target_datetime=target_datetime, target_datetime=self.target_datetime,
bin_num=bin_num, bin_num=self.bin_num,
num_bins=COURSE_UPDATE_NUM_BINS, num_bins=COURSE_UPDATE_NUM_BINS,
org_list=org_list, org_list=self.org_list,
exclude_orgs=exclude_orgs, exclude_orgs=self.exclude_orgs,
order_by='enrollment__course', order_by='enrollment__course',
) )
LOG.debug('Course Update: Query = %r', schedules.query.sql_with_params()) LOG.debug('Course Update: Query = %r', schedules.query.sql_with_params())
...@@ -402,12 +381,12 @@ class CourseUpdateResolver(BinnedSchedulesBaseResolver): ...@@ -402,12 +381,12 @@ class CourseUpdateResolver(BinnedSchedulesBaseResolver):
user = enrollment.user user = enrollment.user
course_id_str = str(enrollment.course_id) course_id_str = str(enrollment.course_id)
template_context = get_base_template_context(site) template_context = get_base_template_context(self.site)
template_context.update({ template_context.update({
'student_name': user.profile.name, 'student_name': user.profile.name,
'user_personal_address': user.profile.name if user.profile.name else user.username, 'user_personal_address': user.profile.name if user.profile.name else user.username,
'course_name': schedule.enrollment.course.display_name, 'course_name': schedule.enrollment.course.display_name,
'course_url': absolute_url(site, reverse('course_root', args=[str(schedule.enrollment.course_id)])), 'course_url': absolute_url(self.site, reverse('course_root', args=[str(schedule.enrollment.course_id)])),
'week_num': week_num, 'week_num': week_num,
'week_summary': week_summary, 'week_summary': week_summary,
......
...@@ -134,7 +134,7 @@ class ScheduleMessageBaseTask(Task): ...@@ -134,7 +134,7 @@ class ScheduleMessageBaseTask(Task):
def run( def run(
self, site_id, target_day_str, day_offset, bin_num, org_list, exclude_orgs=False, override_recipient_email=None, self, site_id, target_day_str, day_offset, bin_num, org_list, exclude_orgs=False, override_recipient_email=None,
): ):
return self.resolver().schedule_bin( return self.resolver(
self.async_send_task, self.async_send_task,
Site.objects.get(id=site_id), Site.objects.get(id=site_id),
deserialize(target_day_str), deserialize(target_day_str),
...@@ -143,7 +143,7 @@ class ScheduleMessageBaseTask(Task): ...@@ -143,7 +143,7 @@ class ScheduleMessageBaseTask(Task):
org_list, org_list,
exclude_orgs=exclude_orgs, exclude_orgs=exclude_orgs,
override_recipient_email=override_recipient_email, override_recipient_email=override_recipient_email,
) ).schedule_bin()
@task(ignore_result=True, routing_key=ROUTING_KEY) @task(ignore_result=True, routing_key=ROUTING_KEY)
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
# * @edx/ospr - to check licensing # * @edx/ospr - to check licensing
# * @edx/devops - to check system requirements # * @edx/devops - to check system requirements
attrs==17.2.0
beautifulsoup4==4.1.3 beautifulsoup4==4.1.3
beautifulsoup==3.2.1 beautifulsoup==3.2.1
bleach==1.4 bleach==1.4
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment