def get_programs(user, program_id=None): """Given a user, get programs from the Programs service. Returned value is cached depending on user permissions. Staff users making requests against Programs will receive unpublished programs, while regular users will only receive published programs. Arguments: user (User): The user to authenticate as when requesting programs. Keyword Arguments: program_id (int): Identifies a specific program for which to retrieve data. Returns: list of dict, representing programs returned by the Programs service. dict, if a specific program is requested. """ programs_config = ProgramsApiConfig.current() # Bypass caching for staff users, who may be creating Programs and want # to see them displayed immediately. cache_key = programs_config.CACHE_KEY if programs_config.is_cache_enabled and not user.is_staff else None programs = get_edx_api_data(programs_config, user, 'programs', resource_id=program_id, cache_key=cache_key) # Mix in munged MicroMasters data from the catalog. if not program_id: programs += [ munge_catalog_program(micromaster) for micromaster in get_catalog_programs(user, type='MicroMasters') ] return programs
def program_listing(request): """View a list of programs in which the user is engaged.""" programs_config = ProgramsApiConfig.current() if not programs_config.show_program_listing: raise Http404 meter = ProgramProgressMeter(request.user) engaged_programs = [ munge_catalog_program(program) for program in meter.engaged_programs ] progress = [ munge_progress_map(progress_map) for progress_map in meter.progress ] context = { 'credentials': get_programs_credentials(request.user), 'disable_courseware_js': True, 'marketing_url': get_program_marketing_url(programs_config), 'nav_hidden': True, 'programs': engaged_programs, 'progress': progress, 'show_program_listing': programs_config.show_program_listing, 'uses_pattern_library': True, } return render_to_response('learner_dashboard/programs.html', context)
def program_details_marketing(request, program_id): """View details about a specific program.""" programs_config = ProgramsApiConfig.current() if not programs_config.show_program_details: raise Http404 auth_user = authenticate( username='******', password='******') if request.user.is_anonymous() else request.user try: # If the ID is a UUID, the requested program resides in the catalog. uuid.UUID(program_id) program_data = get_catalog_programs(auth_user, uuid=program_id) if program_data: program_data = munge_catalog_program(program_data) except ValueError: program_data = utils.get_programs(auth_user, program_id=program_id) if not program_data: raise Http404 program_data = utils.ProgramDataExtender(program_data, auth_user).extend() urls = { 'program_listing_url': reverse('program_listing_view'), 'track_selection_url': strip_course_id( reverse('course_modes_choose', kwargs={'course_id': FAKE_COURSE_KEY})), 'commerce_api_url': reverse('commerce_api:v0:baskets:create'), } context = { 'program_data': program_data, 'urls': urls, 'show_program_listing': programs_config.show_program_listing, 'nav_hidden': True, 'disable_courseware_js': True, 'uses_pattern_library': True, 'user_preferences': get_user_preferences(auth_user) } return render_to_response( 'learner_dashboard/program_details_marketing.html', context)
def assert_munged(self, program): munged = munge_catalog_program(program) expected = { 'id': program['uuid'], 'name': program['title'], 'subtitle': program['subtitle'], 'category': program['type'], 'marketing_slug': program['marketing_slug'], 'organizations': [{ 'display_name': organization['name'], 'key': organization['key'] } for organization in program['authoring_organizations']], 'course_codes': [{ 'display_name': course['title'], 'key': course['key'], 'organization': { 'display_name': course['owners'][0]['name'], 'key': course['owners'][0]['key'] }, 'run_modes': [{ 'course_key': course_run['key'], 'run_key': CourseKey.from_string(course_run['key']).run, 'mode_slug': course_run['type'], 'marketing_url': course_run['marketing_url'], } for course_run in course['course_runs']], } for course in program['courses']], 'banner_image_urls': { 'w1440h480': program['banner_image']['large']['url'], 'w726h242': program['banner_image']['medium']['url'], 'w435h145': program['banner_image']['small']['url'], 'w348h116': program['banner_image']['x-small']['url'], }, 'detail_url': program.get('detail_url'), } self.assertEqual(munged, expected)
def test_programs_listed(self, mock_get_programs): """ Verify that the response contains accurate programs data when programs are engaged. """ self.create_programs_config() mock_get_programs.return_value = self.data CourseEnrollmentFactory(user=self.user, course_id=self.course.id) # pylint: disable=no-member response = self.client.get(self.url) actual = self.load_serialized_data(response, 'programsData') actual = sorted(actual, key=self.program_sort_key) for index, actual_program in enumerate(actual): expected_program = munge_catalog_program(self.data[index]) self.assert_dict_contains_subset(actual_program, expected_program)
def test_munge_catalog_program(self): munged = utils.munge_catalog_program(self.catalog_program) expected = { 'id': self.catalog_program['uuid'], 'name': self.catalog_program['title'], 'subtitle': self.catalog_program['subtitle'], 'category': self.catalog_program['type'], 'marketing_slug': self.catalog_program['marketing_slug'], 'organizations': [ { 'display_name': organization['name'], 'key': organization['key'] } for organization in self.catalog_program['authoring_organizations'] ], 'course_codes': [ { 'display_name': course['title'], 'key': course['key'], 'organization': { 'display_name': course['owners'][0]['name'], 'key': course['owners'][0]['key'] }, 'run_modes': [ { 'course_key': run['key'], 'run_key': CourseKey.from_string(run['key']).run, 'mode_slug': 'verified' } for run in course['course_runs'] ], } for course in self.catalog_program['courses'] ], 'banner_image_urls': { 'w1440h480': self.catalog_program['banner_image']['large']['url'], 'w726h242': self.catalog_program['banner_image']['medium']['url'], 'w435h145': self.catalog_program['banner_image']['small']['url'], 'w348h116': self.catalog_program['banner_image']['x-small']['url'], }, } self.assertEqual(munged, expected)
def setUp(self): super(TestProgramDataExtender, self).setUp() self.user = UserFactory() self.client.login(username=self.user.username, password=self.password) self.course = ModuleStoreCourseFactory() self.course.start = datetime.datetime.now(utc) - datetime.timedelta( days=1) self.course.end = datetime.datetime.now(utc) + datetime.timedelta( days=1) self.course = self.update_course(self.course, self.user.id) # pylint: disable=no-member organization = OrganizationFactory() course_run = CourseRunFactory(key=unicode(self.course.id)) # pylint: disable=no-member course = CourseFactory(course_runs=[course_run]) program = ProgramFactory(authoring_organizations=[organization], courses=[course]) self.program = munge_catalog_program(program) self.course_code = self.program['course_codes'][0] self.run_mode = self.course_code['run_modes'][0]
def program_details(request, program_id): """View details about a specific program.""" programs_config = ProgramsApiConfig.current() if not programs_config.show_program_details: raise Http404 try: # If the ID is a UUID, the requested program resides in the catalog. uuid.UUID(program_id) program_data = get_catalog_programs(request.user, uuid=program_id) if program_data: program_data = munge_catalog_program(program_data) except ValueError: program_data = utils.get_programs(request.user, program_id=program_id) if not program_data: raise Http404 program_data = utils.ProgramDataExtender(program_data, request.user).extend() urls = { "program_listing_url": reverse("program_listing_view"), "track_selection_url": strip_course_id(reverse("course_modes_choose", kwargs={"course_id": FAKE_COURSE_KEY})), "commerce_api_url": reverse("commerce_api:v0:baskets:create"), } context = { "program_data": program_data, "urls": urls, "show_program_listing": programs_config.show_program_listing, "nav_hidden": True, "disable_courseware_js": True, "uses_pattern_library": True, "user_preferences": get_user_preferences(request.user), } return render_to_response("learner_dashboard/program_details.html", context)
def test_munge_catalog_program(self): munged = utils.munge_catalog_program(self.catalog_program) expected = { "id": self.catalog_program["uuid"], "name": self.catalog_program["title"], "subtitle": self.catalog_program["subtitle"], "category": self.catalog_program["type"], "marketing_slug": self.catalog_program["marketing_slug"], "organizations": [ {"display_name": organization["name"], "key": organization["key"]} for organization in self.catalog_program["authoring_organizations"] ], "course_codes": [ { "display_name": course["title"], "key": course["key"], "organization": {"display_name": course["owners"][0]["name"], "key": course["owners"][0]["key"]}, "run_modes": [ { "course_key": run["key"], "run_key": CourseKey.from_string(run["key"]).run, "mode_slug": "verified", } for run in course["course_runs"] ], } for course in self.catalog_program["courses"] ], "banner_image_urls": { "w1440h480": self.catalog_program["banner_image"]["large"]["url"], "w726h242": self.catalog_program["banner_image"]["medium"]["url"], "w435h145": self.catalog_program["banner_image"]["small"]["url"], "w348h116": self.catalog_program["banner_image"]["x-small"]["url"], }, } self.assertEqual(munged, expected)
def test_get_completed_programs(self, mock_get_completed_courses): """ Verify that completed programs are found, using the cache when possible. """ data = [ factories.Program(), ] self._mock_programs_api(data) munged_program = munge_catalog_program(data[0]) course_codes = munged_program['course_codes'] mock_get_completed_courses.return_value = [{ 'course_id': run_mode['course_key'], 'mode': run_mode['mode_slug'] } for run_mode in course_codes[0]['run_modes']] for _ in range(2): result = tasks.get_completed_programs(self.user) self.assertEqual(result[0], munged_program['id']) # Verify that only one request to the catalog was made (i.e., the cache was hit). self._assert_num_requests(1)
def program_details(request, program_uuid): """View details about a specific program.""" programs_config = ProgramsApiConfig.current() if not programs_config.show_program_details: raise Http404 program_data = get_programs(uuid=program_uuid) if not program_data: raise Http404 program_data = munge_catalog_program(program_data) program_data = ProgramDataExtender(program_data, request.user).extend() urls = { 'program_listing_url': reverse('program_listing_view'), 'track_selection_url': strip_course_id( reverse('course_modes_choose', kwargs={'course_id': FAKE_COURSE_KEY})), 'commerce_api_url': reverse('commerce_api:v0:baskets:create'), } context = { 'program_data': program_data, 'urls': urls, 'show_program_listing': programs_config.show_program_listing, 'nav_hidden': True, 'disable_courseware_js': True, 'uses_pattern_library': True, 'user_preferences': get_user_preferences(request.user) } return render_to_response('learner_dashboard/program_details.html', context)