Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions course_discovery/apps/course_metadata/emails.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,10 +453,11 @@ def send_course_deadline_email(course, course_run, recipients, deadline_email_va
html_template = 'course_metadata/email/course_deadline.html'
template = get_template(html_template)
subject_lookup = {
"three_months_reminder": f"Reminder: {course.title} ends in 3 months",
"one_month_reminder": f"Reminder: {course.title} ends in 1 month",
"seven_days_reminder": f"Reminder: {course.title} ends in 7 days",
"course_ended": f"Reminder: {course.title} has ended",
"two_months_reminder": f"Course Availability Reminder: {course.title} Ends in 60 Days",
"one_month_reminder": f"Course Availability Reminder: {course.title} Ends in 30 Days",
"fifteen_days_reminder": f"Course Availability Reminder: {course.title} Ends in 15 Days",
"seven_days_reminder": f"Course Availability Reminder: {course.title} Ends in 7 Days",
"course_ended": f"Reminder: {course.title} has Ended",
}

subject = subject_lookup.get(deadline_email_variant, f"Reminder: {course.title} deadline is approaching")
Expand All @@ -467,8 +468,9 @@ def send_course_deadline_email(course, course_run, recipients, deadline_email_va
"course_key": course.key,
"course_end_date": (course_run.end.strftime("%m/%d/%Y") if course_run.end else None),
"days_to_expire": (
"90 days" if deadline_email_variant == "three_months_reminder"
"60 days" if deadline_email_variant == "two_months_reminder"
else "30 days" if deadline_email_variant == "one_month_reminder"
else "15 days" if deadline_email_variant == "fifteen_days_reminder"
else "7 days" if deadline_email_variant == "seven_days_reminder"
else "course_ended"
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from course_discovery.apps.publisher.choices import InternalUserRole
from course_discovery.apps.publisher.models import OrganizationUserRole

EMAIL_DELTA_DAYS = [90, 30, 7, -1]
EMAIL_DELTA_DAYS = [60, 30, 15, 7, -1]
LAST_RUN_END_DELTA = -1

logger = logging.getLogger(__name__)
Expand All @@ -29,8 +29,9 @@ class Command(BaseCommand):
help = 'Send course deadline emails to Project Coordinators and Course Editors.'

DEADLINE_VARIANTS = {
90: "three_months_reminder",
60: "two_months_reminder",
30: "one_month_reminder",
15: "fifteen_days_reminder",
7: "seven_days_reminder",
-1: "course_ended",
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,9 @@ def test_with_no_course_run_with_end_date_within_range(self):
)

@ddt.data(
(90, "three_months_reminder"),
(60, "two_months_reminder"),
(30, "one_month_reminder"),
(15, "fifteen_days_reminder"),
(7, "seven_days_reminder"),
(-1, "course_ended"),
)
Expand All @@ -122,7 +123,7 @@ def test_with_course_run_with_end_date_within_range(
):
"""
Test that the command sends emails when there are advertised course runs with end dates within
the specified range (90, 30, 7, -1 days).
the specified range (60, 30, 15, 7, -1 days).
"""
self.non_draft_course_run.end = timezone.now() + timedelta(days=days_until_end)
self.non_draft_course_run.save()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,123 @@
{% load django_markup %}

{% block body %}

<p>
{% trans "Hi Course Team," %}
</p>

{% if days_to_expire == '60 days' or days_to_expire == '30 days' or days_to_expire == '15 days' %}

<p>
{% blocktrans with course_name=course_name course_key=course_key course_end_date=course_end_date days=days_to_expire %}
This is an automated reminder that the course "{{ course_name }}" ({{ course_key }}) is scheduled to end in {{ days }} on {{ course_end_date }}.
{% endblocktrans %}
</p>

<p>
{% trans "If no action is taken, the course will be automatically archived after this date. If you decide not to extend the course or create a new run at this time, please inform your dedicated Project Coordinator and share your plans. This helps ensure our internal teams remain aligned and can support you effectively." %}
</p>

<p>
{% trans "To ensure a smooth experience for our edX Learners, please take one of the following actions:" %}
</p>

<ul>
<li>
<strong>{% trans "Create a New Course Run:" %}</strong>
{% trans "Planning to update the content or offer the course to a new cohort? We recommend setting up a new course run in Publisher." %}
{% trans "You can get started" %}
<a href="{{ publisher_url }}courses/{{ course_uuid }}"> {% trans "here" %} </a>.
</li>

<li>
<strong>{% trans "Extend the Course End Date:" %}</strong>
{% trans "If the content is still relevant, you can extend the course end date in Studio." %}
{% trans "Simply visit the Schedule and Details tab" %}
<a href="{{ course_schedule_settings_url }}"> {% trans "here" %} </a>.
</li>
</ul>

{% elif days_to_expire == '7 days' %}

<p>
{% blocktrans with course_name=course_name course_key=course_key course_end_date=course_end_date %}
Our records indicate that the course "{{ course_name }}" (Course Key: {{ course_key }}) is scheduled to end in 7 days on {{ course_end_date }}. Despite previous reminders, we’ve noticed that no action has been taken yet.
{% endblocktrans %}
</p>

<p>
<strong>{% trans "Important:" %}</strong>
{% trans "If no action is taken, the course will be automatically archived after the current end date. If you choose not to extend or create a new course run at this time, you must inform your dedicated Project Coordinator with your reasons. This will ensure our internal teams are properly informed about your plans." %}
</p>

<p>
{% if days_to_expire == '90 days' or days_to_expire == '30 days' or days_to_expire == '7 days' %}
{% blocktrans with course_name=course_name course_key=course_key course_end_date=course_end_date days=days_to_expire %}
This is an automated reminder that the course "{{ course_name }}" (Course Key: {{ course_key }}) is scheduled to end in {{ days }} on {{ course_end_date }}.
{% endblocktrans %}
<p>
{% trans "To ensure uninterrupted learner access and enrollment, please take one of the following actions:" %}
</p>
{% elif days_to_expire == 'course_ended' %}
{% blocktrans with course_name=course_name course_key=course_key course_end_date=course_end_date %}
This is an automated reminder that the course "{{ course_name }}" (Course Key: {{ course_key }}) has officially ended as of {{ course_end_date }}.
{% endblocktrans %}
<p>
{% trans "If this was intentional, no action is needed. However, if this course was meant to remain available, you have two options to restore access:" %}
</p>
{% endif %}
{% trans "To prevent disruption to learner access, please choose one of the following options:" %}
</p>

<ul>
<li>{% trans "Extend the current course run’s end date if the same course is meant to remain available." %}</li>
<li>
{% trans "Create a new course run if you are planning to offer this course again with updated content, pacing, or a new cohort of learners." %}
<a href="{{ publisher_url }}courses/{{ course_uuid }}"> {% trans "Visit the Course in Publisher" %} </a>
</li>
<li>
<strong>{% trans "Create a New Course Run:" %}</strong>
{% trans "Planning to update the content or offer the course to a new cohort? We recommend setting up a new course run in Publisher." %}
{% trans "You can get started" %}
<a href="{{ publisher_url }}courses/{{ course_uuid }}"> {% trans "here" %} </a>.
</li>

<li>
<strong>{% trans "Extend the Course End Date:" %}</strong>
{% trans "If the content is still relevant, you can extend the course end date in Studio." %}
{% trans "Simply visit the Schedule and Details tab" %}
<a href="{{ course_schedule_settings_url }}"> {% trans "here" %} </a>.
</li>
</ul>

{% elif days_to_expire == 'course_ended' %}

<p>
{% blocktrans with course_name=course_name course_key=course_key course_end_date=course_end_date %}
Our records show that the course "{{ course_name }}" (Course Key: {{ course_key }}) officially ended on {{ course_end_date }} and has now entered the archived state. Despite our previous reminders, it appears no action has been taken yet.
{% endblocktrans %}
</p>

<p>
<strong>{% trans "Important:" %}</strong>
{% trans "If you decide not to extend the course or create a new course run at this time, you must inform your dedicated Project Coordinator with the reasons behind this. This will help ensure our internal teams are fully updated on your plans for the course." %}
</p>

<p>
{% trans "If you wish to keep this course active, please choose one of the following options:" %}
</p>

<ul>
<li>
<strong>{% trans "Create a New Course Run:" %}</strong>
{% trans "Planning to update the content or offer the course to a new cohort? We recommend setting up a new course run in Publisher." %}
{% trans "You can get started" %}
<a href="{{ publisher_url }}courses/{{ course_uuid }}"> {% trans "here" %} </a>.
</li>

<li>
<strong>{% trans "Extend the Course End Date:" %}</strong>
{% trans "If the content is still relevant, you can extend the course end date in Studio." %}
{% trans "Simply visit the Schedule and Details tab" %}
<a href="{{ course_schedule_settings_url }}"> {% trans "here" %} </a>.
</li>
</ul>

{% endif %}

<p>
<strong>{% trans "NOTE:" %}</strong>
{% trans "This email address isn’t monitored for replies. If you have any questions or need assistance, please reach out to your dedicated Project Coordinator." %}
</p>

<p>
{% trans "Thank you for your attention to this—looking forward to your updates!" %}
</p>

<p>
{% trans "You can review and modify the course end settings here:" %}
<a href="{{ course_schedule_settings_url }}">{{ course_schedule_settings_url }}</a>
<br/>
{% if days_to_expire == 'course_ended' %}
{% blocktrans with partner_marketing_site_url=partner_marketing_site_url %}
If no action is taken, the course will no longer be available for enrollment or access by learners on
<a href="{{ partner_marketing_site_url }}">{{ partner_marketing_site_url }}</a> after the end date.
{% endblocktrans %}
<br/>
{% endif %}
{% trans "Thanks" %}
{% trans "Best," %}<br/>
{% trans "edX Operational Team" %}
</p>

<!-- End Message Body -->
{% endblock body %}
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,60 @@

{% trans "Hi Course Team," %}

{% if days_to_expire == '90 days' or days_to_expire == '30 days' or days_to_expire == '7 days' %}
{% if days_to_expire == '60 days' or days_to_expire == '30 days' or days_to_expire == '15 days' %}
{% blocktrans with course_name=course_name course_key=course_key course_end_date=course_end_date days=days_to_expire %}
This is an automated reminder that the course "{{ course_name }}" (Course Key: {{ course_key }}) is scheduled to end in {{ days }} on {{ course_end_date }}.
This is an automated reminder that the course "{{ course_name }}" ({{ course_key }}) is scheduled to end in {{ days }} on {{ course_end_date }}.
{% endblocktrans %}
{% elif days_to_expire == 'course_ended' %}

{% trans "If no action is taken, the course will be automatically archived after this date. If you decide not to extend the course or create a new run at this time, please inform your dedicated Project Coordinator and share your plans. This helps ensure our internal teams remain aligned and can support you effectively." %}

{% trans "To ensure a smooth experience for our edX Learners, please take one of the following actions:" %}

- {% trans "Create a New Course Run:" %}
{% trans "Planning to update the content or offer the course to a new cohort? We recommend setting up a new course run in Publisher." %}
{% trans "You can get started here:" %} {{ publisher_url }}courses/{{ course_uuid }}

- {% trans "Extend the Course End Date:" %}
{% trans "If the content is still relevant, you can extend the course end date in Studio." %}
{% trans "Simply visit the Schedule and Details tab here:" %} {{ course_schedule_settings_url }}

{% elif days_to_expire == '7 days' %}

{% blocktrans with course_name=course_name course_key=course_key course_end_date=course_end_date %}
This is an automated reminder that the course "{{ course_name }}" (Course Key: {{ course_key }}) has officially ended as of {{ course_end_date }}.
Our records indicate that the course "{{ course_name }}" (Course Key: {{ course_key }}) is scheduled to end in 7 days on {{ course_end_date }}. Despite previous reminders, we’ve noticed that no action has been taken yet.
{% endblocktrans %}
{% endif %}

{% if days_to_expire == '90 days' or days_to_expire == '30 days' or days_to_expire == '7 days' %}
{% trans "To ensure uninterrupted learner access and enrollment, please take one of the following actions:" %}
{% elif days_to_expire == 'course_ended' %}
{% trans "If this was intentional, no action is needed. However, if this course was meant to remain available, you have two options to restore access:" %}
{% endif %}
{% trans "Important: If no action is taken, the course will be automatically archived after the current end date. If you choose not to extend or create a new course run at this time, you must inform your dedicated Project Coordinator with your reasons. This will ensure our internal teams are properly informed about your plans." %}

{% trans "To prevent disruption to learner access, please choose one of the following options:" %}

- {% trans "Extend the current course run’s end date if the same course is meant to remain available." %}
- {% trans "Create a new course run if you are planning to offer this course again with updated content, pacing, or a new cohort of learners." %}
{% trans "Visit the Course in Publisher:" %} {{ publisher_url }}courses/{{ course_uuid }}
- {% trans "Create a New Course Run:" %}
{{ publisher_url }}courses/{{ course_uuid }}

{% trans "You can review and modify the course end settings here:" %}
{{ course_schedule_settings_url }}
- {% trans "Extend the Course End Date:" %}
{{ course_schedule_settings_url }}

{% if days_to_expire == 'course_ended' %}
{% blocktrans with partner_marketing_site_url=partner_marketing_site_url %}
If no action is taken, the course will no longer be available for enrollment or access by learners on {{ partner_marketing_site_url }} after the end date.
{% elif days_to_expire == 'course_ended' %}

{% blocktrans with course_name=course_name course_key=course_key course_end_date=course_end_date %}
Our records show that the course "{{ course_name }}" (Course Key: {{ course_key }}) officially ended on {{ course_end_date }} and has now entered the archived state. Despite our previous reminders, it appears no action has been taken yet.
{% endblocktrans %}

{% trans "Important: If you decide not to extend the course or create a new course run at this time, you must inform your dedicated Project Coordinator with the reasons behind this. This will help ensure our internal teams are fully updated on your plans for the course." %}

{% trans "If you wish to keep this course active, please choose one of the following options:" %}

- {% trans "Create a New Course Run:" %}
{{ publisher_url }}courses/{{ course_uuid }}

- {% trans "Extend the Course End Date:" %}
{{ course_schedule_settings_url }}

{% endif %}

{% trans "Thanks" %}
{% trans "NOTE: This email address isn’t monitored for replies. If you have any questions or need assistance, please reach out to your dedicated Project Coordinator." %}

{% trans "Thank you for your attention to this—looking forward to your updates!" %}

{% trans "Best," %}
{% trans "edX Operational Team" %}
28 changes: 25 additions & 3 deletions course_discovery/apps/course_metadata/tests/test_emails.py
Original file line number Diff line number Diff line change
Expand Up @@ -744,15 +744,37 @@ def test_send_course_deadline_email(self):

assert len(mail.outbox) == 1
email = mail.outbox[0]
assert str(email.subject) == f'Reminder: {self.course.title} ends in 7 days'

assert str(email.subject) == f'Course Availability Reminder: {self.course.title} Ends in 7 Days'

assert email.to == [self.editor.email]
assert email.from_email == settings.PUBLISHER_FROM_EMAIL

assert 'Hi Course Team' in email.body

assert (
f'This is an automated reminder that the course "{self.course.title}" (Course Key: {self.course.key})'
f' is scheduled to end in 7 days on {self.course_run.end.strftime("%m/%d/%Y")}.'
f'Our records indicate that the course "{self.course.title}" (Course Key: {self.course.key}) '
f'is scheduled to end in 7 days on {self.course_run.end.strftime("%m/%d/%Y")}.'
in email.body
)

assert 'Despite previous reminders' in email.body

assert 'Important:' in email.body

assert 'If no action is taken, the course will be automatically archived after the current end date.' in email.body # pylint: disable=line-too-long

assert 'To prevent disruption to learner access' in email.body

assert 'Create a New Course Run:' in email.body
assert 'Extend the Course End Date:' in email.body

assert 'NOTE:' in email.body
assert 'This email address isn’t monitored for replies.' in email.body

assert 'Thank you for your attention to this—looking forward to your updates!' in email.body
assert 'edX Operational Team' in email.body

log_capture.check(
(
emails.logger.name,
Expand Down
Loading