Skip to content

Commit

Permalink
feat: default stale start_dates to today in braze assignment task
Browse files Browse the repository at this point in the history
  • Loading branch information
brobro10000 committed Sep 19, 2024
1 parent 3fc0229 commit ebb2666
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 7 deletions.
2 changes: 2 additions & 0 deletions enterprise_access/apps/content_assignments/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ class AssignmentAutomaticExpiredReason:

NUM_DAYS_BEFORE_AUTO_EXPIRATION = 90

START_DATE_DEFAULT_TO_TODAY_THRESHOLD_DAYS = 14

RETIRED_EMAIL_ADDRESS_FORMAT = 'retired_user{}@retired.invalid'

BRAZE_ACTION_REQUIRED_BY_TIMESTAMP_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
13 changes: 11 additions & 2 deletions enterprise_access/apps/content_assignments/tasks.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""
Tasks for content_assignments app.
"""

import logging

from braze.exceptions import BrazeBadRequestError
Expand All @@ -26,6 +25,7 @@
)

from .constants import BRAZE_ACTION_REQUIRED_BY_TIMESTAMP_FORMAT, LearnerContentAssignmentStateChoices
from .utils import get_self_paced_normalized_start_date

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -211,8 +211,17 @@ def get_enrollment_deadline(self):
return get_human_readable_date(self._enrollment_deadline_raw())

def get_start_date(self):
"""
Checks if the start_date is before today's date offset by the
START_DATE_DEFAULT_TO_TODAY_THRESHOLD_DAYS value and returns today's date
If not, pass through the formatted start date.
"""
start_date = self.normalized_metadata.get('start_date')
end_date = self.normalized_metadata.get('end_date')
course_metadata = self.course_metadata

return get_human_readable_date(
self.normalized_metadata.get('start_date')
get_self_paced_normalized_start_date(start_date, end_date, course_metadata)
)

def get_action_required_by_timestamp(self):
Expand Down
13 changes: 8 additions & 5 deletions enterprise_access/apps/content_assignments/tests/test_tasks.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Tests for Enterprise Access content_assignments tasks.
"""
import datetime
from unittest import mock
from uuid import uuid4

Expand All @@ -20,7 +21,7 @@
AssignmentActions,
LearnerContentAssignmentStateChoices
)
from enterprise_access.apps.content_assignments.content_metadata_api import format_datetime_obj
from enterprise_access.apps.content_assignments.content_metadata_api import format_datetime_obj, get_human_readable_date
from enterprise_access.apps.content_assignments.tasks import (
BrazeCampaignSender,
create_pending_enterprise_learner_for_assignment_task,
Expand Down Expand Up @@ -240,6 +241,9 @@ def setUpTestData(cls):
],
'card_image_url': 'https://itsanimage.com',
}
cls.mock_formatted_todays_date = get_human_readable_date(datetime.datetime.now().strftime(
BRAZE_ACTION_REQUIRED_BY_TIMESTAMP_FORMAT
))

def setUp(self):
super().setUp()
Expand Down Expand Up @@ -382,6 +386,7 @@ def test_send_reminder_email_for_pending_assignment(
[self.assignment.learner_email],
ENTERPRISE_BRAZE_ALIAS_LABEL,
)

mock_braze_client.send_campaign_message.assert_called_once_with(
expected_campaign_identifier,
recipients=[expected_recipient],
Expand All @@ -390,7 +395,7 @@ def test_send_reminder_email_for_pending_assignment(
'organization': self.enterprise_customer_name,
'course_title': self.assignment.content_title,
'enrollment_deadline': 'Jan 01, 2021',
'start_date': 'Jan 01, 2020',
'start_date': self.mock_formatted_todays_date,
'course_partner': 'Smart Folks, Good People, and Fast Learners',
'course_card_image': 'https://itsanimage.com',
'learner_portal_link': 'http://enterprise-learner-portal.example.com/test-slug',
Expand Down Expand Up @@ -420,7 +425,6 @@ def test_send_email_for_new_assignment(
'count': 1,
'results': [self.mock_content_metadata]
}

# Set the subsidy expiration time to tomorrow
mock_subsidy = {
'uuid': self.policy.subsidy_uuid,
Expand All @@ -439,7 +443,6 @@ def test_send_email_for_new_assignment(
mock_lms_client.return_value.get_enterprise_customer_data.assert_called_with(
self.assignment_configuration.enterprise_customer_uuid
)

mock_braze_client.return_value.send_campaign_message.assert_any_call(
'test-assignment-notification-campaign',
recipients=[mock_recipient],
Expand All @@ -448,7 +451,7 @@ def test_send_email_for_new_assignment(
'organization': self.enterprise_customer_name,
'course_title': self.assignment.content_title,
'enrollment_deadline': 'Jan 01, 2021',
'start_date': 'Jan 01, 2020',
'start_date': self.mock_formatted_todays_date,
'course_partner': 'Smart Folks and Good People',
'course_card_image': self.mock_content_metadata['card_image_url'],
'learner_portal_link': '{}/{}'.format(
Expand Down
55 changes: 55 additions & 0 deletions enterprise_access/apps/content_assignments/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""
Utils for content_assignments
"""
from datetime import datetime, timedelta

from dateutil import parser
from pytz import UTC

from enterprise_access.apps.content_assignments.constants import (
BRAZE_ACTION_REQUIRED_BY_TIMESTAMP_FORMAT,
START_DATE_DEFAULT_TO_TODAY_THRESHOLD_DAYS
)


def is_within_minimum_start_date_threshold(today, start_date):
"""
Checks if today's date were set to a certain number of days in the past,
offset_date_from_today, is the start_date before offset_date_from_today.
"""
start_date_datetime = parser.parse(start_date)
offset_date_from_today = today - timedelta(days=START_DATE_DEFAULT_TO_TODAY_THRESHOLD_DAYS)
return start_date_datetime < offset_date_from_today.replace(tzinfo=UTC)


def has_time_to_complete(today, end_date, weeks_to_complete):
"""
Checks if today's date were set to a certain number of weeks_to_complete in the future,
offset_now_by_weeks_to_complete, is offset_now_by_weeks_to_complete date before the end_date
"""
end_date_datetime = parser.parse(end_date)
offset_now_by_weeks_to_complete = today + timedelta(weeks=weeks_to_complete)
return offset_now_by_weeks_to_complete.replace(tzinfo=UTC) <= end_date_datetime


def get_self_paced_normalized_start_date(start_date, end_date, course_metadata):
"""
Normalizes courses start_date far in the past based on a heuristic for the purpose of displaying a
reasonable start_date in content assignment related emails.
Heuristic:
For self-paced courses with a weeks_to_complete field too close to the end date to complete the course
or a start_date that is before today offset by the START_DATE_DEFAULT_TO_TODAY_THRESHOLD_DAYS should
default to today's date.
Otherwise, return the current start_date
"""
today = datetime.now()
pacing_type = course_metadata.get('pacing_type') or None
weeks_to_complete = course_metadata.get('weeks_to_complete') or None
if not (start_date and end_date and pacing_type and weeks_to_complete):
return today.strftime(BRAZE_ACTION_REQUIRED_BY_TIMESTAMP_FORMAT)
if pacing_type == "self_paced":
if has_time_to_complete(today, end_date, weeks_to_complete) or \
is_within_minimum_start_date_threshold(today, start_date):
return today.strftime(BRAZE_ACTION_REQUIRED_BY_TIMESTAMP_FORMAT)
return start_date

0 comments on commit ebb2666

Please sign in to comment.