def init_cache(self): """ This function plays the role of the ``cache_programs`` management command. """ all_programs = [ self.masters_program_1, self.masters_program_2, self.bachelors_program, self.no_type_program, self.masters_program_other_site ] cached_programs = { PROGRAM_CACHE_KEY_TPL.format(uuid=program['uuid']): program for program in all_programs } cache.set_many(cached_programs, None) programs_by_type = defaultdict(list) programs_by_type_slug = defaultdict(list) for program in all_programs: program_type = normalize_program_type(program.get('type')) program_type_slug = (program.get('type_attrs') or {}).get('slug') site_id = self.site.id if program == self.masters_program_other_site: site_id = self.other_site.id program_type_cache_key = PROGRAMS_BY_TYPE_CACHE_KEY_TPL.format( site_id=site_id, program_type=program_type) program_type_slug_cache_key = PROGRAMS_BY_TYPE_SLUG_CACHE_KEY_TPL.format( site_id=site_id, program_slug=program_type_slug) programs_by_type[program_type_cache_key].append(program['uuid']) programs_by_type_slug[program_type_slug_cache_key].append( program['uuid']) cache.set_many(programs_by_type, None) cache.set_many(programs_by_type_slug, None)
def get(self, request): """ How to respond to a GET request to this endpoint """ request_user = request.user programs = [] requested_program_type = normalize_program_type( request.GET.get('type', self.DEFAULT_PROGRAM_TYPE)) if request_user.is_staff: programs = get_programs_by_type(request.site, requested_program_type) else: program_dict = {} # Check if the user is a course staff of any course which is a part of a program. for staff_program in self.get_programs_user_is_course_staff_for( request_user, requested_program_type): program_dict.setdefault(staff_program['uuid'], staff_program) # Now get the program enrollments for user purely as a learner add to the list for learner_program in self._get_enrolled_programs_from_model( request_user): program_dict.setdefault(learner_program['uuid'], learner_program) programs = list(program_dict.values()) programs_in_which_user_has_access = [{ 'uuid': program['uuid'], 'slug': program['marketing_slug'] } for program in programs] return Response(programs_in_which_user_has_access, status.HTTP_200_OK)
def get(self, request): """ How to respond to a GET request to this endpoint """ request_user = request.user programs = [] requested_program_type = normalize_program_type( request.GET.get('type', self.DEFAULT_PROGRAM_TYPE)) if request_user.is_staff: programs = get_programs_by_type(request.site, requested_program_type) elif self.is_course_staff(request_user): programs = self.get_programs_user_is_course_staff_for( request_user, requested_program_type) else: program_enrollments = fetch_program_enrollments_by_student( user=request.user, program_enrollment_statuses=ProgramEnrollmentStatuses. __ACTIVE__, ) uuids = [ enrollment.program_uuid for enrollment in program_enrollments ] programs = get_programs(uuids=uuids) or [] programs_in_which_user_has_access = [{ 'uuid': program['uuid'], 'slug': program['marketing_slug'] } for program in programs] return Response(programs_in_which_user_has_access, status.HTTP_200_OK)
def get_programs_by_type(self, site, programs): """ Returns a dictionary mapping site-aware cache keys corresponding to program types to lists of program uuids with that type. """ programs_by_type = defaultdict(list) for program in programs.values(): program_type = normalize_program_type(program.get('type')) cache_key = PROGRAMS_BY_TYPE_CACHE_KEY_TPL.format(site_id=site.id, program_type=program_type) programs_by_type[cache_key].append(program['uuid']) return programs_by_type
def test_normalize_program_type(self): self.assertEqual('none', normalize_program_type(None)) self.assertEqual('false', normalize_program_type(False)) self.assertEqual('true', normalize_program_type(True)) self.assertEqual('', normalize_program_type('')) self.assertEqual('masters', normalize_program_type('Masters')) self.assertEqual('masters', normalize_program_type('masters'))
def test_normalize_program_type(self): assert 'none' == normalize_program_type(None) assert 'false' == normalize_program_type(False) assert 'true' == normalize_program_type(True) assert '' == normalize_program_type('') assert 'masters' == normalize_program_type('Masters') assert 'masters' == normalize_program_type('masters')
def test_handle_programs(self): """ Verify that the command requests and caches program UUIDs and details. """ # Ideally, this user would be created in the test setup and deleted in # the one test case which covers the case where the user is missing. However, # that deletion causes "OperationalError: no such table: wiki_attachmentrevision" # when run on Jenkins. UserFactory(username=self.catalog_integration.service_username) programs = { PROGRAM_CACHE_KEY_TPL.format(uuid=program['uuid']): program for program in self.programs } self.mock_list() self.mock_pathways(self.pathways) for uuid in self.uuids: program = programs[PROGRAM_CACHE_KEY_TPL.format(uuid=uuid)] self.mock_detail(uuid, program) call_command('cache_programs') cached_uuids = cache.get( SITE_PROGRAM_UUIDS_CACHE_KEY_TPL.format(domain=self.site_domain)) self.assertEqual(set(cached_uuids), set(self.uuids)) program_keys = list(programs.keys()) cached_programs = cache.get_many(program_keys) # Verify that the keys were all cache hits. self.assertEqual(set(cached_programs), set(programs)) # We can't use a set comparison here because these values are dictionaries # and aren't hashable. We've already verified that all programs came out # of the cache above, so all we need to do here is verify the accuracy of # the data itself. for key, program in cached_programs.items(): # cached programs have a pathways field added to them, remove before comparing del program['pathway_ids'] self.assertEqual(program, programs[key]) # the courses in the child program's first curriculum (the active one) # should point to both the child program and the first program # in the cache. for course in self.child_program['curricula'][0]['courses']: for course_run in course['course_runs']: course_run_cache_key = COURSE_PROGRAMS_CACHE_KEY_TPL.format( course_run_id=course_run['key']) self.assertIn(self.programs[0]['uuid'], cache.get(course_run_cache_key)) self.assertIn(self.child_program['uuid'], cache.get(course_run_cache_key)) # for each program, assert that the program's UUID is in a cached list of # program UUIDS by program type and a cached list of UUIDs by authoring organization for program in self.programs: program_type = normalize_program_type(program.get('type', 'None')) program_type_cache_key = PROGRAMS_BY_TYPE_CACHE_KEY_TPL.format( site_id=self.site.id, program_type=program_type) self.assertIn(program['uuid'], cache.get(program_type_cache_key)) for organization in program['authoring_organizations']: organization_cache_key = PROGRAMS_BY_ORGANIZATION_CACHE_KEY_TPL.format( org_key=organization['key']) self.assertIn(program['uuid'], cache.get(organization_cache_key))