diff --git a/lms/djangoapps/course_goals/management/commands/goal_reminder_email.py b/lms/djangoapps/course_goals/management/commands/goal_reminder_email.py index 0acdf1b995..e977d4305f 100644 --- a/lms/djangoapps/course_goals/management/commands/goal_reminder_email.py +++ b/lms/djangoapps/course_goals/management/commands/goal_reminder_email.py @@ -3,18 +3,29 @@ Command to trigger sending reminder emails for learners to achieve their Course """ from datetime import date, timedelta import logging +import six +from django.conf import settings from django.contrib.sites.models import Site from django.core.management.base import BaseCommand +from django.urls import reverse +from edx_ace import ace +from edx_ace.message import Message +from edx_ace.recipient import Recipient from common.djangoapps.student.models import CourseEnrollment from lms.djangoapps.certificates.api import get_certificate_for_user_id from lms.djangoapps.certificates.data import CertificateStatuses from lms.djangoapps.course_goals.models import CourseGoal, CourseGoalReminderStatus, UserActivity from lms.djangoapps.course_goals.toggles import COURSE_GOALS_NUMBER_OF_DAYS_GOALS +from openedx.core.djangoapps.ace_common.template_context import get_base_template_context from openedx.core.djangoapps.content.course_overviews.models import CourseOverview +from openedx.core.djangoapps.lang_pref import LANGUAGE_KEY +from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers +from openedx.core.djangoapps.user_api.preferences.api import get_user_preference from openedx.core.lib.celery.task_utils import emulate_http_request from openedx.features.course_duration_limits.access import get_user_course_expiration_date +from openedx.features.course_experience import course_home_url_name log = logging.getLogger(__name__) @@ -22,8 +33,53 @@ MONDAY_WEEKDAY = 0 SUNDAY_WEEKDAY = 6 -def ace_send(): - """Just here as a mock hook for tests - drop this once we fix AA-909""" +def send_ace_message(goal): + """ + Send an email reminding users to stay on track for their learning goal in this course + + Arguments: + goal (CourseGoal): Goal object + """ + user = goal.user + try: + course = CourseOverview.get_from_id(goal.course_key) + except CourseOverview.DoesNotExist: + log.error("Goal Reminder course not found.") + + course_name = course.display_name + + site = Site.objects.get_current() + message_context = get_base_template_context(site) + + course_home_url = reverse(course_home_url_name(course.id), args=[str(course.id)]) + course_home_absolute_url_parts = ("https", site.name, course_home_url, '', '', '') + course_home_absolute_url = six.moves.urllib.parse.urlunparse(course_home_absolute_url_parts) + + goals_unsubscribe_url = reverse( + 'course-home:unsubscribe-from-course-goal', + kwargs={'token': goal.unsubscribe_token} + ) + + message_context.update({ + 'email': user.email, + 'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME), + 'course_name': course_name, + 'days_per_week': goal.days_per_week, + 'course_url': course_home_absolute_url, + 'goals_unsubscribe_url': goals_unsubscribe_url, + 'unsubscribe_url': None, # We don't want to include the default unsubscribe link + }) + + msg = Message( + name="goalreminder", + app_label="course_goals", + recipient=Recipient(user.id, user.email), + language=get_user_preference(user, LANGUAGE_KEY), + context=message_context + ) + + with emulate_http_request(site, user): + ace.send(msg) class Command(BaseCommand): @@ -104,9 +160,7 @@ class Command(BaseCommand): # Essentially, if today is Sunday, days_left_in_week should be 1 since they have Sunday to hit their goal. days_left_in_week = SUNDAY_WEEKDAY - today.weekday() + 1 if required_days_left == days_left_in_week: - # TODO: hook up email AA-909 - # ace.send(msg) - ace_send() # temporary for tests, drop with AA-909 and just mock ace.send directly + send_ace_message(goal) CourseGoalReminderStatus.objects.update_or_create(goal=goal, defaults={'email_reminder_sent': True}) return True diff --git a/lms/djangoapps/course_goals/management/commands/tests/test_goal_reminder_email.py b/lms/djangoapps/course_goals/management/commands/tests/test_goal_reminder_email.py index 1d7d9ee976..148703e909 100644 --- a/lms/djangoapps/course_goals/management/commands/tests/test_goal_reminder_email.py +++ b/lms/djangoapps/course_goals/management/commands/tests/test_goal_reminder_email.py @@ -56,7 +56,7 @@ class TestGoalReminderEmailCommand(TestCase): def call_command(self, day=TUESDAY, expect_sent=None, expect_send_count=None): """Calls the management command with a frozen time and optionally checks whether we sent an email""" - with mock.patch('lms.djangoapps.course_goals.management.commands.goal_reminder_email.ace_send') as mock_send: + with mock.patch('lms.djangoapps.course_goals.management.commands.goal_reminder_email.send_ace_message') as mock_send: # pylint: disable=line-too-long with freeze_time(f'2021-03-0{day + 1}'): # March 2021 starts on a Monday call_command('goal_reminder_email') diff --git a/lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/body.html b/lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/body.html index 50f681098b..7dc7604f6f 100644 --- a/lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/body.html +++ b/lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/body.html @@ -1,33 +1,85 @@ {% extends 'ace_common/edx_ace/common/base_body.html' %} - {% load i18n %} +{% load django_markup %} {% load static %} {% block content %} - +{# email client support for style sheets is pretty spotty, so we have to inline all of these styles #} +{# we're using important below to override inline styles and my understanding is for email clients where media queries do not work, they'll simply see the desktop css on their phone #} +
-

- {% trans "There's still time to reach your goal" as tmsg %}{{ tmsg | force_escape }} -

-

- {% filter force_escape %} - {% blocktrans %}You set a goal of learning 3x a week in Rhetoric: The Art of Persuasive Writing and Public Speaking. You're not quite there, but there's still time to reach that goal!{% endblocktrans %} - {% endfilter %} -
-

+ {% include "goal_reminder_banner.html" %} + +
+

+ {% filter force_escape %}{% blocktrans %} + There's still time to reach your goal + {% endblocktrans %}{% endfilter %} +

-

- {% filter force_escape %} - {% blocktrans %}Remember, you can always change your learning goal. The best goal is one that you can stick to. {% endblocktrans %} - {% endfilter %} -
-

+

+ {% filter force_escape %} + {% blocktrans asvar goal_text %} + You set a goal of learning {start_bold}{{days_per_week}} times a week in {{course_name}}{end_bold}. You're not quite there, but there's still time to reach that goal! + {% endblocktrans %} + {% endfilter %} + {% interpolate_html goal_text start_bold=''|safe end_bold=''|safe %} +
+

- {% filter force_escape %} - {% blocktrans asvar course_cta_text %}Adjust my goal{% endblocktrans %} - {% endfilter %} - {% include "ace_common/edx_ace/common/return_to_course_cta.html" with course_cta_text=course_cta_text course_cta_url=reset_link %} + +
+ {% filter force_escape %}{% blocktrans %} + Jump back in + {% endblocktrans %}{% endfilter %} +
+
+ +

+ {% filter force_escape %}{% blocktrans %} + Remember, you can always change your learning goal. The best goal is one that you can stick to. + {% endblocktrans %}{% endfilter %} +
+

+ + +
+ {% filter force_escape %}{% blocktrans %} + Adjust my goal + {% endblocktrans %}{% endfilter %} +
+
+ + + {% filter force_escape %}{% blocktrans %} + Unsubscribe from goal reminder emails to this course + {% endblocktrans %}{% endfilter %} + +
-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/body.txt b/lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/body.txt new file mode 100644 index 0000000000..604819e2ef --- /dev/null +++ b/lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/body.txt @@ -0,0 +1,11 @@ +{% load i18n %} +{% trans "You’re almost there!" %} +{% trans "There's still time to reach your goal" as tmsg %} +{% blocktrans %}You set a goal of learning {{days_per_week}} times a week in {{course_name}}. You're not quite there, but there's still time to reach that goal!{% endblocktrans %} +{% trans "Jump back in"} +{{course_url}} +{% blocktrans %}Remember, you can always change your learning goal. The best goal is one that you can stick to. {% endblocktrans %} +{% trans "Adjust my goal"} +{{course_url}} +{% trans "Unsubscribe from goal reminder emails to this course"} +{{course_url}} \ No newline at end of file diff --git a/lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/from_name.txt b/lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/from_name.txt new file mode 100644 index 0000000000..dcbc23c004 --- /dev/null +++ b/lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/from_name.txt @@ -0,0 +1 @@ +{{ platform_name }} diff --git a/lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/head.html b/lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/head.html new file mode 100644 index 0000000000..366ada7ad9 --- /dev/null +++ b/lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/head.html @@ -0,0 +1 @@ +{% extends 'ace_common/edx_ace/common/base_head.html' %} diff --git a/lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/subject.txt b/lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/subject.txt new file mode 100644 index 0000000000..09baf8fa00 --- /dev/null +++ b/lms/djangoapps/course_goals/templates/course_goals/edx_ace/goalreminder/email/subject.txt @@ -0,0 +1,4 @@ +{% load i18n %} +{% autoescape off %} +{% blocktrans trimmed %}You've almost reached your goal in {{ course_name }}{% endblocktrans %} +{% endautoescape %} diff --git a/lms/templates/goal_reminder_banner.html b/lms/templates/goal_reminder_banner.html new file mode 100644 index 0000000000..a6937957ef --- /dev/null +++ b/lms/templates/goal_reminder_banner.html @@ -0,0 +1,75 @@ +{% load i18n %} +{# email client support for style sheets is pretty spotty, so we have to inline all of these styles #} +{# we're using important below to override inline styles and my understanding is for email clients where media queries do not work, they'll simply see the desktop css on their phone #} + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ {% filter force_escape %}{% blocktrans %} + You’re almost there! + {% endblocktrans %}{% endfilter %} +

+
+
\ No newline at end of file