Skip to content

Commit

Permalink
feat: take exec ed course data from course run instead of additional_…
Browse files Browse the repository at this point in the history
…metadata

style: fix long line

fix: don't use advertised_course_run before it is populated

fix: bug caused by typo

fix: merge error
  • Loading branch information
marlonkeating committed May 6, 2024
1 parent 00b7aca commit aa9dddd
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 57 deletions.
45 changes: 14 additions & 31 deletions enterprise_catalog/apps/api/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,31 +286,25 @@ def _normalize_course_metadata(course_metadata_record):
"""
json_meta = course_metadata_record.json_metadata
normalized_metadata = {}
# For each content type, find the values that correspond to the desired output key.
if course_metadata_record.is_exec_ed_2u_course:
# First case covers Exec Ed courses.
additional_metadata = json_meta.get('additional_metadata', {})
normalized_metadata['start_date'] = additional_metadata.get('start_date')
normalized_metadata['end_date'] = additional_metadata.get('end_date')
normalized_metadata['enroll_by_date'] = additional_metadata.get('registration_deadline')
for entitlement in json_meta.get('entitlements', []):
if entitlement.get('mode') == CourseMode.PAID_EXECUTIVE_EDUCATION:
normalized_metadata['content_price'] = entitlement.get('price') or DEFAULT_NORMALIZED_PRICE
else:
# Else case covers OCM courses.
advertised_course_run_uuid = json_meta.get('advertised_course_run_uuid')
advertised_course_run = _get_course_run_by_uuid(json_meta, advertised_course_run_uuid)
if advertised_course_run is not None:
normalized_metadata['start_date'] = advertised_course_run.get('start')
normalized_metadata['end_date'] = advertised_course_run.get('end')
normalized_metadata['content_price'] = \
advertised_course_run.get('first_enrollable_paid_seat_price') or DEFAULT_NORMALIZED_PRICE

advertised_course_run_uuid = json_meta.get('advertised_course_run_uuid')
advertised_course_run = _get_course_run_by_uuid(json_meta, advertised_course_run_uuid)

if advertised_course_run is not None:
normalized_metadata['start_date'] = advertised_course_run.get('start')
normalized_metadata['end_date'] = advertised_course_run.get('end')
normalized_metadata['content_price'] = advertised_course_run.get('first_enrollable_paid_seat_price') \
or DEFAULT_NORMALIZED_PRICE
if enrollment_end := advertised_course_run.get('enrollment_end'):
normalized_metadata['enroll_by_date'] = enrollment_end
else:
all_seats = advertised_course_run.get('seats', [])
seat = _find_best_mode_seat(all_seats)
if seat:
normalized_metadata['enroll_by_date'] = seat.get('upgrade_deadline')
else:
logger.info(f"No Seat Found for course run '{advertised_course_run.get('key')}'. Seats: {all_seats}")
logger.info(f"No enrollment end or seat found for course run + \
'{advertised_course_run.get('key')}'. Seats: {all_seats}")

# Add normalized values to net-new keys:
json_meta['normalized_metadata'] = normalized_metadata
Expand Down Expand Up @@ -366,17 +360,6 @@ def _update_full_content_metadata_course(content_keys, dry_run=False):
# Merge the full metadata from discovery's /api/v1/courses into the local metadata object.
metadata_record.json_metadata.update(course_metadata_dict)

# Exec ed provides the start/end dates in additional_metadata, so we should copy those over to the keys that
# we use (inside the advertised course run).
if metadata_record.is_exec_ed_2u_course:
json_meta = metadata_record.json_metadata
start_date = json_meta.get('additional_metadata', {}).get('start_date')
end_date = json_meta.get('additional_metadata', {}).get('end_date')
course_run_uuid = json_meta.get('advertised_course_run_uuid')
for run in json_meta.get('course_runs', []):
if run.get('uuid') == course_run_uuid:
run.update({'start': start_date, 'end': end_date})

# Perform more steps to normalize and move keys around for more consistency across content types.
_normalize_course_metadata(metadata_record)

Expand Down
23 changes: 21 additions & 2 deletions enterprise_catalog/apps/api/tests/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,23 @@ def test_update_full_metadata(self, mock_oauth_client, mock_partition_course_key
]
}],
'advertised_course_run_uuid': course_run_3_uuid,
'advertised_course_run': {
'key': f'course-v1:{course_key_3}+1',
'uuid': course_run_3_uuid,
'start': '2023-03-01T00:00:00Z',
'end': '2023-03-01T00:00:00Z',
'first_enrollable_paid_seat_price': 90,
'seats': [
{
'type': CourseMode.VERIFIED,
'upgrade_deadline': '2023-02-01T00:00:00Z',
},
{
"type": str(CourseMode.PROFESSIONAL),
"upgrade_deadline": '2022-02-01T00:00:00Z',
},
]
},
}

non_course_key = 'course-runX'
Expand Down Expand Up @@ -617,8 +634,10 @@ def test_update_full_metadata_exec_ed(self, mock_oauth_client, mock_partition_co
'key': course_run_key,
'uuid': course_run_uuid,
# Use dummy 2022 dates that we will assert are overwritten.
'start': '2022-03-01T00:00:00Z',
'end': '2022-03-01T00:00:00Z',
'start': '2023-03-01T00:00:00Z',
'end': '2023-04-09T23:59:59Z',
'enrollment_end': '2023-02-01T00:00:00Z',
"first_enrollable_paid_seat_price": 2900,
}],
'programs': [],
'additional_metadata': {
Expand Down
25 changes: 12 additions & 13 deletions enterprise_catalog/apps/api/v1/export_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,13 @@ def course_hit_to_row(hit):


def fetch_and_format_registration_date(obj):
enroll_by_date = obj.get('registration_deadline')
"""
Args:
obj: CourseRun object
Returns:
string: date to register by
"""
enroll_by_date = obj.get('end')
stripped_enroll_by = enroll_by_date.split("T")[0]
formatted_enroll_by = None
try:
Expand All @@ -264,26 +270,19 @@ def exec_ed_course_to_row(hit):
csv_row.append(hit['partners'][0]['name'])
else:
csv_row.append(None)
if hit.get('additional_metadata'):
start_date = None
additional_md = hit['additional_metadata']
if additional_md.get('start_date'):
start_date = parser.parse(additional_md['start_date']).strftime(DATE_FORMAT)
csv_row.append(start_date)

end_date = None
if additional_md.get('end_date'):
end_date = parser.parse(additional_md['end_date']).strftime(DATE_FORMAT)
csv_row.append(end_date)
formatted_enroll_by = fetch_and_format_registration_date(additional_md)
adv_course_run = hit.get('advertised_course_run', {})
if (start_date := adv_course_run.get('start'), end_date := adv_course_run.get('end')) and start_date and end_date:
csv_row.append(start_date and parser.parse(start_date).strftime(DATE_FORMAT))
csv_row.append(end_date and parser.parse(end_date).strftime(DATE_FORMAT))
formatted_enroll_by = fetch_and_format_registration_date(adv_course_run)
else:
csv_row.append(None) # no start date
csv_row.append(None) # no end date
formatted_enroll_by = None

csv_row.append(formatted_enroll_by)

adv_course_run = hit.get('advertised_course_run', {})
key = adv_course_run.get('key')

price = float(hit['entitlements'][0]['price'])
Expand Down
4 changes: 2 additions & 2 deletions enterprise_catalog/apps/api/v1/tests/test_export_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ def test_fetch_and_format_registration_date(self):
"""
# expected hit format from algolia, porperly reformatted for csv download
assert export_utils.fetch_and_format_registration_date(
{'registration_deadline': '2002-02-15T12:12:200'}
{'end': '2002-02-15T12:12:200'}
) == '02-15-2002'
# some other format from algolia, should return None
assert export_utils.fetch_and_format_registration_date(
{'registration_deadline': '02-15-2015T12:12:200'}
{'end': '02-15-2015T12:12:200'}
) is None
11 changes: 5 additions & 6 deletions enterprise_catalog/apps/catalog/algolia_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,20 +220,18 @@ def _has_enroll_by_deadline_passed(course_json_metadata, advertised_course_run):
Helper to determine if the enrollment deadline has passed for the given course
and advertised course run. For course metadata records with a `course_type` of "course" (e.g. OCM courses),
this is based on the verified upgrade deadline.
For 2u exec ed courses, this is based on the registration deadline.
For 2u exec ed courses, this is based on the enrollment_end deadline.
"""
enroll_by_deadline_timestamp = 0
if course_json_metadata.get('course_type') == EXEC_ED_2U_COURSE_TYPE:
additional_metadata = course_json_metadata.get('additional_metadata') or {}
registration_deadline = additional_metadata.get('registration_deadline')
if registration_deadline:
enrollment_end = advertised_course_run.get('end') or {}
if enrollment_end:
enroll_by_deadline_timestamp = datetime.datetime.strptime(
registration_deadline,
enrollment_end,
'%Y-%m-%dT%H:%M:%S%z',
).timestamp()
else:
enroll_by_deadline_timestamp = _get_verified_upgrade_deadline(advertised_course_run)

return enroll_by_deadline_timestamp < localized_utcnow().timestamp()


Expand Down Expand Up @@ -1080,6 +1078,7 @@ def _get_course_run(full_course_run):
'availability': full_course_run.get('availability'),
'start': full_course_run.get('start'),
'end': full_course_run.get('end'),
'enrollment_end': full_course_run.get('enrollment_end'),
'min_effort': full_course_run.get('min_effort'),
'max_effort': full_course_run.get('max_effort'),
'weeks_to_complete': full_course_run.get('weeks_to_complete'),
Expand Down
29 changes: 26 additions & 3 deletions enterprise_catalog/apps/catalog/tests/test_algolia_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,16 @@ class AlgoliaUtilsTests(TestCase):
{
'course_type': EXEC_ED_2U_COURSE_TYPE,
'expected_result': True,
'additional_metadata': {'registration_deadline': '2073-03-21T23:59:59Z'},
'start': _fake_upgrade_deadline(1),
'end': _fake_upgrade_deadline(30),
'enrollment_end': _fake_upgrade_deadline(1)
},
{
'course_type': EXEC_ED_2U_COURSE_TYPE,
'expected_result': False,
'additional_metadata': {'registration_deadline': '2021-03-21T23:59:59Z'},
'start': _fake_upgrade_deadline(-30),
'end': _fake_upgrade_deadline(-1),
'enrollment_end': _fake_upgrade_deadline(-30)
},
{
'course_type': EXEC_ED_2U_COURSE_TYPE,
Expand All @@ -92,7 +96,10 @@ def test_should_index_course(
course_run_availability='current',
seats=None,
course_type=COURSE,
additional_metadata=None
additional_metadata=None,
start='2023-01-29T23:59:59Z',
end='2023-02-28T23:59:59Z',
enrollment_end='2023-01-29T23:59:59Z'
):
"""
Verify that only a course that has a non-hidden advertised course run, at least one owner, and a marketing slug
Expand All @@ -113,6 +120,9 @@ def test_should_index_course(
'is_marketable': is_marketable,
'availability': course_run_availability,
'seats': seats or [],
'start': start,
'end': end,
'enrollment_end': enrollment_end
},
],
'owners': owners,
Expand Down Expand Up @@ -304,6 +314,7 @@ def test_get_course_subjects(self, course_metadata, expected_subjects):
'pacing_type': 'instructor_paced',
'start': '2013-10-16T14:00:00Z',
'end': '2014-10-16T14:00:00Z',
'enrollment_end': '2013-10-17T14:00:00Z',
'availability': 'Current',
'min_effort': 10,
'max_effort': 14,
Expand All @@ -316,6 +327,7 @@ def test_get_course_subjects(self, course_metadata, expected_subjects):
'pacing_type': 'instructor_paced',
'start': '2013-10-16T14:00:00Z',
'end': '2014-10-16T14:00:00Z',
'enrollment_end': '2013-10-17T14:00:00Z',
'availability': 'Current',
'min_effort': 10,
'max_effort': 14,
Expand All @@ -340,6 +352,7 @@ def test_get_course_subjects(self, course_metadata, expected_subjects):
'pacing_type': 'instructor_paced',
'start': '2013-10-16T14:00:00Z',
'end': '2014-10-16T14:00:00Z',
'enrollment_end': '2013-10-17T14:00:00Z',
'availability': 'Current',
'min_effort': 10,
'max_effort': 14,
Expand All @@ -359,6 +372,7 @@ def test_get_course_subjects(self, course_metadata, expected_subjects):
'pacing_type': 'instructor_paced',
'start': '2013-10-16T14:00:00Z',
'end': '2014-10-16T14:00:00Z',
'enrollment_end': '2013-10-17T14:00:00Z',
'availability': 'Current',
'min_effort': 10,
'max_effort': 14,
Expand All @@ -374,6 +388,7 @@ def test_get_course_subjects(self, course_metadata, expected_subjects):
'pacing_type': 'instructor_paced',
'start': '2013-10-16T14:00:00Z',
'end': '2014-10-16T14:00:00Z',
'enrollment_end': '2013-10-17T14:00:00Z',
'availability': 'Current',
'min_effort': 10,
'max_effort': 14,
Expand All @@ -390,6 +405,7 @@ def test_get_course_subjects(self, course_metadata, expected_subjects):
'pacing_type': 'instructor_paced',
'start': '2013-10-16T14:00:00Z',
'end': '2014-10-16T14:00:00Z',
'enrollment_end': '2013-10-17T14:00:00Z',
'availability': 'Current',
'min_effort': 10,
'max_effort': 14,
Expand Down Expand Up @@ -465,6 +481,7 @@ def test_get_upcoming_course_runs(self, searchable_course, expected_course_runs)
'availability': 'Archived',
'start': "2000-01-04T00:00:00Z",
'end': "2001-12-31T23:59:00Z",
'enrollment_end': '2000-01-04T00:00:00Z',
'min_effort': 2,
'max_effort': 6,
'weeks_to_complete': 6,
Expand All @@ -479,6 +496,7 @@ def test_get_upcoming_course_runs(self, searchable_course, expected_course_runs)
'availability': 'Current',
'start': "2018-01-04T00:00:00Z",
'end': "3022-12-31T23:59:00Z",
'enrollment_end': '2018-01-04T00:00:00Z',
'min_effort': 2,
'max_effort': 6,
'weeks_to_complete': 6,
Expand All @@ -493,6 +511,7 @@ def test_get_upcoming_course_runs(self, searchable_course, expected_course_runs)
'availability': 'Upcoming',
'start': "3000-01-04T00:00:00Z",
'end': "3022-12-31T23:59:00Z",
'enrollment_end': '3000-01-04T00:00:00Z',
'min_effort': 2,
'max_effort': 6,
'weeks_to_complete': 6,
Expand All @@ -507,6 +526,7 @@ def test_get_upcoming_course_runs(self, searchable_course, expected_course_runs)
'availability': 'Starting Soon',
'start': "3000-01-04T00:00:00Z",
'end': "3022-12-31T23:59:00Z",
'enrollment_end': '3000-01-04T00:00:00Z',
'min_effort': 2,
'max_effort': 6,
'weeks_to_complete': 6,
Expand All @@ -521,6 +541,7 @@ def test_get_upcoming_course_runs(self, searchable_course, expected_course_runs)
'availability': 'Current',
'start': "2018-01-04T00:00:00Z",
'end': "3022-12-31T23:59:00Z",
'enrollment_end': '2018-01-04T00:00:00Z',
'min_effort': 2,
'max_effort': 6,
'weeks_to_complete': 6,
Expand All @@ -532,6 +553,7 @@ def test_get_upcoming_course_runs(self, searchable_course, expected_course_runs)
'availability': 'Upcoming',
'start': "3000-01-04T00:00:00Z",
'end': "3022-12-31T23:59:00Z",
'enrollment_end': '3000-01-04T00:00:00Z',
'min_effort': 2,
'max_effort': 6,
'weeks_to_complete': 6,
Expand All @@ -543,6 +565,7 @@ def test_get_upcoming_course_runs(self, searchable_course, expected_course_runs)
'availability': 'Starting Soon',
'start': "3000-01-04T00:00:00Z",
'end': "3022-12-31T23:59:00Z",
'enrollment_end': '3000-01-04T00:00:00Z',
'min_effort': 2,
'max_effort': 6,
'weeks_to_complete': 6,
Expand Down

0 comments on commit aa9dddd

Please sign in to comment.