Add endpoint for checking learner program enrollments

JIRA:EDUCATOR-4327
This commit is contained in:
Matt Hughes
2019-05-23 10:37:13 -04:00
parent b0f715d1c2
commit 047c379cab
5 changed files with 130 additions and 8 deletions

View File

@@ -208,6 +208,27 @@ class TestGetPrograms(CacheIsolationTestCase):
self.assertEqual(actual_program, [expected_program])
self.assertFalse(mock_warning.called)
def test_get_via_uuids(self, mock_warning, _mock_info):
first_program = ProgramFactory()
second_program = ProgramFactory()
cache.set(
PROGRAM_CACHE_KEY_TPL.format(uuid=first_program['uuid']),
first_program,
None
)
cache.set(
PROGRAM_CACHE_KEY_TPL.format(uuid=second_program['uuid']),
second_program,
None
)
results = get_programs(uuids=[first_program['uuid'], second_program['uuid']])
assert first_program in results
assert second_program in results
assert not mock_warning.called
@skip_unless_lms
@mock.patch(UTILS_MODULE + '.logger.info')

View File

@@ -30,6 +30,8 @@ from student.models import CourseEnrollment
logger = logging.getLogger(__name__)
missing_details_msg_tpl = u'Failed to get details for program {uuid} from the cache.'
def create_catalog_api_client(user, site=None):
"""Returns an API client which can be used to make Catalog API requests."""
@@ -82,7 +84,7 @@ def check_catalog_integration_and_get_user(error_message_field):
return None, catalog_integration
def get_programs(site=None, uuid=None, course=None): # pylint: disable=redefined-outer-name
def get_programs(site=None, uuid=None, uuids=None, course=None): # pylint: disable=redefined-outer-name
"""Read programs from the cache.
The cache is populated by a management command, cache_programs.
@@ -90,17 +92,16 @@ def get_programs(site=None, uuid=None, course=None): # pylint: disable=redefine
Keyword Arguments:
site (Site): django.contrib.sites.models object
uuid (string): UUID identifying a specific program to read from the cache.
uuids (list of string): UUIDs identifying a specific programs to read from the cache.
course (string): course id identifying a specific course run to read from the cache.
Returns:
list of dict, representing programs.
dict, if a specific program is requested.
"""
if len([arg for arg in (site, uuid, course) if arg is not None]) != 1:
if len([arg for arg in (site, uuid, uuids, course) if arg is not None]) != 1:
raise TypeError('get_programs takes exactly one argument')
missing_details_msg_tpl = u'Failed to get details for program {uuid} from the cache.'
if uuid:
program = cache.get(PROGRAM_CACHE_KEY_TPL.format(uuid=uuid))
if not program:
@@ -113,12 +114,22 @@ def get_programs(site=None, uuid=None, course=None): # pylint: disable=redefine
# Currently, the cache does not differentiate between a cache miss and a course
# without programs. After this is changed, log any cache misses here.
return []
else:
elif site:
uuids = cache.get(SITE_PROGRAM_UUIDS_CACHE_KEY_TPL.format(domain=site.domain), [])
if not uuids:
logger.warning(u'Failed to get program UUIDs from the cache for site {}.'.format(site.domain))
programs = cache.get_many([PROGRAM_CACHE_KEY_TPL.format(uuid=uuid) for uuid in uuids])
return get_programs_by_uuids(uuids)
def get_programs_by_uuids(uuids):
"""
Gets a list of programs for the provided uuids
"""
# a list of UUID objects would be a perfectly reasonable parameter to provide
uuid_strings = [six.text_type(handle) for handle in uuids]
programs = cache.get_many([PROGRAM_CACHE_KEY_TPL.format(uuid=handle) for handle in uuid_strings])
programs = list(programs.values())
# The get_many above sometimes fails to bring back details cached on one or
@@ -129,7 +140,7 @@ def get_programs(site=None, uuid=None, course=None): # pylint: disable=redefine
# immediately afterwards will succeed in bringing back all the keys. This
# behavior can be mitigated by trying again for the missing keys, which is
# what we do here. Splitting the get_many into smaller chunks may also help.
missing_uuids = set(uuids) - set(program['uuid'] for program in programs)
missing_uuids = set(uuid_strings) - set(program['uuid'] for program in programs)
if missing_uuids:
logger.info(
u'Failed to get details for {count} programs. Retrying.'.format(count=len(missing_uuids))
@@ -138,7 +149,7 @@ def get_programs(site=None, uuid=None, course=None): # pylint: disable=redefine
retried_programs = cache.get_many([PROGRAM_CACHE_KEY_TPL.format(uuid=uuid) for uuid in missing_uuids])
programs += list(retried_programs.values())
still_missing_uuids = set(uuids) - set(program['uuid'] for program in programs)
still_missing_uuids = set(uuid_strings) - set(program['uuid'] for program in programs)
for uuid in still_missing_uuids:
logger.warning(missing_details_msg_tpl.format(uuid=uuid))