-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: ingest external course APIs (#2998)
* feat: ingest external course APIs * save work * save work * add migration * add admin updates * save work * create internal objects * feat: helper funcs * organize * remova extra change * fixes * refactor * refactor * more fixes and refactoring due to bad data * refactor & fmt * update app.json * add EMERITUS_API_KEY in ci.yml * more fixes * add tests * add tests + refactor * add timeout setting * add more tests * add docs * add feat flag * review changes in generate_course_readable_id * review changes in generate_course_readable_id * review changes * review changes * review changes * review changes * review changes * review changes * refactor * add celery beat scheduled task to sync emeritus course runs * fix tests * refactor tests * review changes * refactor * add count details * add counts log * fix tests * filter stats * add external id admin seacrh for course and course run
- Loading branch information
1 parent
b354094
commit 1118b17
Showing
16 changed files
with
1,542 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
129 changes: 129 additions & 0 deletions
129
courses/management/commands/sync_external_course_runs.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
"""Management command to sync external course runs""" | ||
|
||
from django.core.management.base import BaseCommand | ||
|
||
from courses.sync_external_courses.emeritus_api import ( | ||
EmeritusKeyMap, | ||
fetch_emeritus_courses, | ||
update_emeritus_course_runs, | ||
) | ||
from mitxpro import settings | ||
|
||
|
||
class Command(BaseCommand): | ||
"""Sync external course runs""" | ||
|
||
help = "Management command to sync external course runs from the vendor APIs." | ||
|
||
def add_arguments(self, parser): | ||
parser.add_argument( | ||
"--vendor-name", | ||
type=str, | ||
help="The name of the vendor i.e. `Emeritus`", | ||
required=True, | ||
) | ||
super().add_arguments(parser) | ||
|
||
def handle(self, *args, **options): # noqa: ARG002 | ||
"""Handle command execution""" | ||
if not settings.FEATURES.get("ENABLE_EXTERNAL_COURSE_SYNC", False): | ||
self.stdout.write( | ||
self.style.ERROR( | ||
"External Course Sync is disabled. You can enable it by turning on the feature flag " | ||
"`ENABLE_EXTERNAL_COURSE_SYNC`" | ||
) | ||
) | ||
return | ||
|
||
vendor_name = options["vendor_name"] | ||
if vendor_name.lower() == EmeritusKeyMap.PLATFORM_NAME.value.lower(): | ||
self.stdout.write(f"Starting course sync for {vendor_name}.") | ||
emeritus_course_runs = fetch_emeritus_courses() | ||
stats = update_emeritus_course_runs(emeritus_course_runs) | ||
self.stdout.write( | ||
self.style.SUCCESS( | ||
f"Number of Courses Created {len(stats['courses_created'])}." | ||
) | ||
) | ||
self.stdout.write( | ||
self.style.SUCCESS( | ||
f"External Course Codes: {stats['courses_created'] if stats['courses_created'] else None}.\n" | ||
) | ||
) | ||
self.stdout.write( | ||
self.style.SUCCESS( | ||
f"Number of existing Courses {len(stats['existing_courses'])}." | ||
) | ||
) | ||
self.stdout.write( | ||
self.style.SUCCESS( | ||
f"External Course Codes: {stats['existing_courses'] if stats['existing_courses'] else None}.\n" | ||
) | ||
) | ||
self.stdout.write( | ||
self.style.SUCCESS( | ||
f"Number of Course Runs Created {len(stats['course_runs_created'])}." | ||
) | ||
) | ||
self.stdout.write( | ||
self.style.SUCCESS( | ||
f"External Course Run Codes: {stats['course_runs_created'] if stats['course_runs_created'] else None}.\n" | ||
) | ||
) | ||
self.stdout.write( | ||
self.style.SUCCESS( | ||
f"Number of Course Runs Updated {len(stats['course_runs_updated'])}." | ||
) | ||
) | ||
self.stdout.write( | ||
self.style.SUCCESS( | ||
f"External Course Run Codes: {stats['course_runs_updated'] if stats['course_runs_updated'] else None}.\n" | ||
) | ||
) | ||
self.stdout.write( | ||
self.style.SUCCESS( | ||
f"Number of Courses Pages Created {len(stats['course_pages_created'])}." | ||
) | ||
) | ||
self.stdout.write( | ||
self.style.SUCCESS( | ||
f"External Course Codes: {stats['course_pages_created'] if stats['course_pages_created'] else None}.\n" | ||
) | ||
) | ||
self.stdout.write( | ||
self.style.SUCCESS( | ||
f"Number of Courses Pages Updated {len(stats['course_pages_updated'])}." | ||
) | ||
) | ||
self.stdout.write( | ||
self.style.SUCCESS( | ||
f"External Course Codes: {stats['course_pages_updated'] if stats['course_pages_updated'] else None}.\n" | ||
) | ||
) | ||
self.stdout.write( | ||
self.style.SUCCESS( | ||
f"Number of Course Runs Skipped due to bad data {len(stats['course_runs_skipped'])}." | ||
) | ||
) | ||
self.stdout.write( | ||
self.style.SUCCESS( | ||
f"External Course Codes: {stats['course_runs_skipped'] if stats['course_runs_skipped'] else None}.\n" | ||
) | ||
) | ||
self.stdout.write( | ||
self.style.SUCCESS( | ||
f"Number of Expired Course Runs {len(stats['course_runs_expired'])}." | ||
) | ||
) | ||
self.stdout.write( | ||
self.style.SUCCESS( | ||
f"External Course Codes: {stats['course_runs_expired'] if stats['course_runs_expired'] else None}.\n" | ||
) | ||
) | ||
self.stdout.write( | ||
self.style.SUCCESS( | ||
f"External course sync successful for {vendor_name}." | ||
) | ||
) | ||
else: | ||
self.stdout.write(self.style.ERROR(f"Unknown vendor name {vendor_name}.")) |
Empty file.
Oops, something went wrong.