def render_to_fragment(self, request, program_uuid, **kwargs): # lint-amnesty, pylint: disable=arguments-differ """View details about a specific program.""" programs_config = kwargs.get('programs_config') or ProgramsApiConfig.current() user = request.user site = request.site if not programs_config.enabled or not request.user.is_authenticated: raise Http404 try: mobile_only = json.loads(request.GET.get('mobile_only', 'false')) except ValueError: mobile_only = False program_data, course_data = get_program_and_course_data(site, user, program_uuid, mobile_only) if not program_data: raise Http404 certificate_data = get_certificates(user, program_data) program_data.pop('courses') urls = get_program_urls(program_data) if not certificate_data: urls['program_record_url'] = None industry_pathways, credit_pathways = get_industry_and_credit_pathways(program_data, site) program_discussion_lti = ProgramDiscussionLTI(program_uuid, request) program_live_lti = ProgramLiveLTI(program_uuid, request) def program_tab_view_enabled() -> bool: return program_tab_view_is_enabled() and ( industry_pathways or credit_pathways or program_discussion_lti.is_configured or program_live_lti.is_configured ) context = { 'urls': urls, 'user_preferences': get_user_preferences(user), 'program_data': program_data, 'course_data': course_data, 'certificate_data': certificate_data, 'industry_pathways': industry_pathways, 'credit_pathways': credit_pathways, 'program_tab_view_enabled': program_tab_view_enabled(), 'discussion_fragment': { 'configured': program_discussion_lti.is_configured, 'iframe': program_discussion_lti.render_iframe() }, 'live_fragment': { 'configured': program_live_lti.is_configured, 'iframe': program_live_lti.render_iframe() } } html = render_to_string('learner_dashboard/program_details_fragment.html', context) program_details_fragment = Fragment(html) self.add_fragment_resource_urls(program_details_fragment) return program_details_fragment
def test_get_certificates(self, mock_get_credentials): """ Verify course and program certificates are found when present. Only one course run certificate should be returned for each course when the user has earned certificates in multiple runs of the same course. """ expected = [ { 'type': 'course', 'title': course_run['title'], 'url': course_run['certificate_url'], } for course_run in self._first_course_runs() ] expected.append({ 'type': 'program', 'title': self.program['title'], 'url': self.program_certificate_url, }) mock_get_credentials.return_value = [{ 'certificate_url': self.program_certificate_url }] certificates = get_certificates(self.user, self.program) self.assertEqual(certificates, expected)
def test_get_certificates(self, mock_get_credentials): """ Verify course and program certificates are found when present. Only one course run certificate should be returned for each course when the user has earned certificates in multiple runs of the same course. """ expected = [] for course in self.program['courses']: # Give all course runs a certificate URL, but only expect one to come # back. This verifies the break in the function under test that ensures # only one certificate per course comes back. for index, course_run in enumerate(course['course_runs']): course_run['certificate_url'] = self.course_certificate_url if index == 0: expected.append({ 'type': 'course', 'title': course_run['title'], 'url': self.course_certificate_url, }) expected.append({ 'type': 'program', 'title': self.program['title'], 'url': self.program_certificate_url, }) mock_get_credentials.return_value = [{ 'certificate_url': self.program_certificate_url }] certificates = get_certificates(self.user, self.program) self.assertEqual(certificates, expected)
def test_course_run_certificates_missing(self, mock_get_credentials): """ Verify program certificates are not included when the learner has not earned all course certificates. """ # make the first course have no certification, the second have no url... for course_index, course in enumerate(self.program['courses']): for index, course_run in enumerate(course['course_runs']): if course_index == 0: course_run['may_certify'] = False elif course_index == 1: course_run['certificate_url'] = False # ...but the third course should still be included expected = [{ 'type': 'course', 'title': self.program['courses'][2]['course_runs'][0]['title'], 'url': self.program['courses'][2]['course_runs'][0]['certificate_url'], }] mock_get_credentials.return_value = [{ 'certificate_url': self.program_certificate_url }] certificates = get_certificates(self.user, self.program) self.assertTrue(mock_get_credentials.called) self.assertEqual(certificates, expected)
def test_course_run_certificates_missing(self, mock_get_credentials): """ Verify an empty list is returned when course run certificates are missing, and that no attempt is made to retrieve program certificates. """ certificates = get_certificates(self.user, self.program) self.assertEqual(certificates, []) self.assertFalse(mock_get_credentials.called)
def render_to_fragment(self, request, program_uuid, **kwargs): """View details about a specific program.""" programs_config = kwargs.get( 'programs_config') or ProgramsApiConfig.current() if not programs_config.enabled or not request.user.is_authenticated(): raise Http404 meter = ProgramProgressMeter(request.site, request.user, uuid=program_uuid) program_data = meter.programs[0] if not program_data: raise Http404 try: mobile_only = json.loads(request.GET.get('mobile_only', 'false')) except ValueError: mobile_only = False program_data = ProgramDataExtender(program_data, request.user, mobile_only=mobile_only).extend() course_data = meter.progress(programs=[program_data], count_only=False)[0] certificate_data = get_certificates(request.user, program_data) program_data.pop('courses') skus = program_data.get('skus') ecommerce_service = EcommerceService() 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'), 'buy_button_url': ecommerce_service.get_checkout_page_url(*skus) } context = { 'urls': urls, 'user_preferences': get_user_preferences(request.user), 'program_data': program_data, 'course_data': course_data, 'certificate_data': certificate_data } html = render_to_string( 'learner_dashboard/program_details_fragment.html', context) program_details_fragment = Fragment(html) self.add_fragment_resource_urls(program_details_fragment) return program_details_fragment
def render_to_fragment(self, request, program_uuid, **kwargs): """View details about a specific program.""" programs_config = kwargs.get('programs_config') or ProgramsApiConfig.current() if not programs_config.enabled or not request.user.is_authenticated: raise Http404 meter = ProgramProgressMeter(request.site, request.user, uuid=program_uuid) program_data = meter.programs[0] if not program_data: raise Http404 try: mobile_only = json.loads(request.GET.get('mobile_only', 'false')) except ValueError: mobile_only = False program_data = ProgramDataExtender(program_data, request.user, mobile_only=mobile_only).extend() course_data = meter.progress(programs=[program_data], count_only=False)[0] certificate_data = get_certificates(request.user, program_data) program_data.pop('courses') skus = program_data.get('skus') ecommerce_service = EcommerceService() # TODO: Don't have business logic of course-certificate==record-available here in LMS. # Eventually, the UI should ask Credentials if there is a record available and get a URL from it. # But this is here for now so that we can gate this URL behind both this business logic and # a waffle flag. This feature is in active developoment. program_record_url = get_credentials_records_url(program_uuid=program_uuid) if not certificate_data: program_record_url = None 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'), 'buy_button_url': ecommerce_service.get_checkout_page_url(*skus), 'program_record_url': program_record_url, } context = { 'urls': urls, 'user_preferences': get_user_preferences(request.user), 'program_data': program_data, 'course_data': course_data, 'certificate_data': certificate_data } html = render_to_string('learner_dashboard/program_details_fragment.html', context) program_details_fragment = Fragment(html) self.add_fragment_resource_urls(program_details_fragment) return program_details_fragment
def program_details(request, program_uuid): """View details about a specific program.""" programs_config = ProgramsApiConfig.current() if not programs_config.enabled: raise Http404 meter = ProgramProgressMeter(request.user, uuid=program_uuid) program_data = meter.programs[0] if not program_data: raise Http404 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 = { 'urls': urls, 'show_program_listing': programs_config.enabled, 'nav_hidden': True, 'disable_courseware_js': True, 'uses_pattern_library': True, 'user_preferences': get_user_preferences(request.user) } if waffle.switch_is_active('new_program_progress'): course_data = meter.progress(programs=[program_data], count_only=False)[0] certificate_data = get_certificates(request.user, program_data) program_data.pop('courses') context.update({ 'program_data': program_data, 'course_data': course_data, 'certificate_data': certificate_data, }) return render_to_response( 'learner_dashboard/program_details_2017.html', context) else: context.update({'program_data': program_data}) return render_to_response('learner_dashboard/program_details.html', context)
def test_course_run_certificates_missing(self, mock_get_credentials): """ Verify program certificates are retrieved even if the learner has not earned any course certificates. """ expected = [{ 'type': 'program', 'title': self.program['title'], 'url': self.program_certificate_url, }] mock_get_credentials.return_value = [{'certificate_url': self.program_certificate_url}] certificates = get_certificates(self.user, self.program) self.assertTrue(mock_get_credentials.called) self.assertEqual(certificates, expected)
def test_program_certificate_missing(self, mock_get_credentials): """ Verify that the function can handle a missing program certificate. """ expected = [{ 'type': 'course', 'title': course_run['title'], 'url': course_run['certificate_url'], } for course_run in self._first_course_runs()] mock_get_credentials.return_value = [] certificates = get_certificates(self.user, self.program) self.assertEqual(certificates, expected)
def program_details(request, program_uuid): """View details about a specific program.""" programs_config = ProgramsApiConfig.current() if not programs_config.enabled: raise Http404 meter = ProgramProgressMeter(request.site, request.user, uuid=program_uuid) program_data = meter.programs[0] if not program_data: raise Http404 program_data = ProgramDataExtender(program_data, request.user).extend() course_data = meter.progress(programs=[program_data], count_only=False)[0] certificate_data = get_certificates(request.user, program_data) program_data.pop('courses') skus = program_data.get('skus') ecommerce_service = EcommerceService() 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'), 'buy_button_url': ecommerce_service.get_checkout_page_url(*skus) } context = { 'urls': urls, 'show_program_listing': programs_config.enabled, 'show_dashboard_tabs': True, 'nav_hidden': True, 'disable_courseware_js': True, 'uses_pattern_library': True, 'user_preferences': get_user_preferences(request.user), 'program_data': program_data, 'course_data': course_data, 'certificate_data': certificate_data } return render_to_response('learner_dashboard/program_details.html', context)
def program_details(request, program_uuid): """View details about a specific program.""" programs_config = ProgramsApiConfig.current() if not programs_config.enabled: raise Http404 meter = ProgramProgressMeter(request.user, uuid=program_uuid) program_data = meter.programs[0] if not program_data: raise Http404 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 = { 'urls': urls, 'show_program_listing': programs_config.enabled, 'nav_hidden': True, 'disable_courseware_js': True, 'uses_pattern_library': True, 'user_preferences': get_user_preferences(request.user) } if waffle.switch_is_active('new_program_progress'): course_data = meter.progress(programs=[program_data], count_only=False)[0] certificate_data = get_certificates(request.user, program_data) program_data.pop('courses') context.update({ 'program_data': program_data, 'course_data': course_data, 'certificate_data': certificate_data, }) return render_to_response('learner_dashboard/program_details_2017.html', context) else: context.update({'program_data': program_data}) return render_to_response('learner_dashboard/program_details.html', context)
def test_program_certificate_missing(self, mock_get_credentials): """ Verify that the function can handle a missing program certificate. """ expected = [ { 'type': 'course', 'title': course_run['title'], 'url': course_run['certificate_url'], } for course_run in self._first_course_runs() ] mock_get_credentials.return_value = [] certificates = get_certificates(self.user, self.program) self.assertEqual(certificates, expected)
def program_details(request, program_uuid): """View details about a specific program.""" programs_config = ProgramsApiConfig.current() if not programs_config.enabled: raise Http404 meter = ProgramProgressMeter(request.site, request.user, uuid=program_uuid) program_data = meter.programs[0] if not program_data: raise Http404 program_data = ProgramDataExtender(program_data, request.user).extend() course_data = meter.progress(programs=[program_data], count_only=False)[0] certificate_data = get_certificates(request.user, program_data) program_data.pop('courses') skus = program_data.get('skus') ecommerce_service = EcommerceService() 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'), 'buy_button_url': ecommerce_service.get_checkout_page_url(*skus) } context = { 'urls': urls, 'show_program_listing': programs_config.enabled, 'show_dashboard_tabs': True, 'nav_hidden': True, 'disable_courseware_js': True, 'uses_pattern_library': True, 'user_preferences': get_user_preferences(request.user), 'program_data': program_data, 'course_data': course_data, 'certificate_data': certificate_data } return render_to_response('learner_dashboard/program_details.html', context)
def test_program_certificate_missing(self, mock_get_credentials): """ Verify that the function can handle a missing program certificate. """ expected = [] for course in self.program['courses']: for index, course_run in enumerate(course['course_runs']): course_run['certificate_url'] = self.course_certificate_url if index == 0: expected.append({ 'type': 'course', 'title': course_run['title'], 'url': self.course_certificate_url, }) mock_get_credentials.return_value = [] certificates = get_certificates(self.user, self.program) self.assertEqual(certificates, expected)
def render_to_fragment(self, request, program_uuid, **kwargs): """View details about a specific program.""" programs_config = kwargs.get('programs_config') or ProgramsApiConfig.current() if not programs_config.enabled or not request.user.is_authenticated(): raise Http404 meter = ProgramProgressMeter(request.site, request.user, uuid=program_uuid) program_data = meter.programs[0] if not program_data: raise Http404 program_data = ProgramDataExtender(program_data, request.user).extend() course_data = meter.progress(programs=[program_data], count_only=False)[0] certificate_data = get_certificates(request.user, program_data) program_data.pop('courses') skus = program_data.get('skus') ecommerce_service = EcommerceService() 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'), 'buy_button_url': ecommerce_service.get_checkout_page_url(*skus) } context = { 'urls': urls, 'user_preferences': get_user_preferences(request.user), 'program_data': program_data, 'course_data': course_data, 'certificate_data': certificate_data } html = render_to_string('learner_dashboard/program_details_fragment.html', context) program_details_fragment = Fragment(html) self.add_fragment_resource_urls(program_details_fragment) return program_details_fragment
def get(self, request, program_uuid): """ Retrieves progress details of a user in a specified program. Args: request (Request): Django request object. program_uuid (string): URI element specifying uuid of the program. Return: """ user = request.user site = request.site program_data, course_data = get_program_and_course_data( site, user, program_uuid) if not program_data: return Response(status=404, data={'error_code': 'No program data available.'}) certificate_data = get_certificates(user, program_data) program_data.pop('courses') urls = get_program_urls(program_data) if not certificate_data: urls['program_record_url'] = None industry_pathways, credit_pathways = get_industry_and_credit_pathways( program_data, site) return Response({ 'urls': urls, 'program_data': program_data, 'course_data': course_data, 'certificate_data': certificate_data, 'industry_pathways': industry_pathways, 'credit_pathways': credit_pathways, })
def test_course_run_certificates_missing(self, mock_get_credentials): """ Verify program certificates are not included when the learner has not earned all course certificates. """ # make the first course have no certification, the second have no url... for course_index, course in enumerate(self.program['courses']): for index, course_run in enumerate(course['course_runs']): if course_index == 0: course_run['may_certify'] = False elif course_index == 1: course_run['certificate_url'] = False # ...but the third course should still be included expected = [{ 'type': 'course', 'title': self.program['courses'][2]['course_runs'][0]['title'], 'url': self.program['courses'][2]['course_runs'][0]['certificate_url'], }] mock_get_credentials.return_value = [{'certificate_url': self.program_certificate_url}] certificates = get_certificates(self.user, self.program) self.assertTrue(mock_get_credentials.called) self.assertEqual(certificates, expected)
def render_to_fragment(self, request, program_uuid, **kwargs): # lint-amnesty, pylint: disable=arguments-differ """View details about a specific program.""" programs_config = kwargs.get( 'programs_config') or ProgramsApiConfig.current() user = request.user if not programs_config.enabled or not request.user.is_authenticated: raise Http404 meter = ProgramProgressMeter(request.site, user, uuid=program_uuid) program_data = meter.programs[0] if not program_data: raise Http404 try: mobile_only = json.loads(request.GET.get('mobile_only', 'false')) except ValueError: mobile_only = False program_data = ProgramDataExtender(program_data, user, mobile_only=mobile_only).extend() course_data = meter.progress(programs=[program_data], count_only=False)[0] certificate_data = get_certificates(user, program_data) program_data.pop('courses') skus = program_data.get('skus') ecommerce_service = EcommerceService() # TODO: Don't have business logic of course-certificate==record-available here in LMS. # Eventually, the UI should ask Credentials if there is a record available and get a URL from it. # But this is here for now so that we can gate this URL behind both this business logic and # a waffle flag. This feature is in active developoment. program_record_url = get_credentials_records_url( program_uuid=program_uuid) if not certificate_data: program_record_url = None industry_pathways = [] credit_pathways = [] try: for pathway_id in program_data['pathway_ids']: pathway = get_pathways(request.site, pathway_id) if pathway and pathway['email']: if pathway['pathway_type'] == PathwayType.CREDIT.value: credit_pathways.append(pathway) elif pathway['pathway_type'] == PathwayType.INDUSTRY.value: industry_pathways.append(pathway) # if pathway caching did not complete fully (no pathway_ids) except KeyError: pass 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'), 'buy_button_url': ecommerce_service.get_checkout_page_url(*skus), 'program_record_url': program_record_url, } context = { 'urls': urls, 'user_preferences': get_user_preferences(user), 'program_data': program_data, 'course_data': course_data, 'certificate_data': certificate_data, 'industry_pathways': industry_pathways, 'credit_pathways': credit_pathways, 'program_discussions_enabled': program_discussions_is_enabled(), 'discussion_fragment': self.render_discussions_fragment(program_uuid, request) } html = render_to_string( 'learner_dashboard/program_details_fragment.html', context) program_details_fragment = Fragment(html) self.add_fragment_resource_urls(program_details_fragment) return program_details_fragment