def render_to_fragment(self, request, **kwargs): """ Render the program listing fragment. """ user = request.user try: mobile_only = json.loads(request.GET.get('mobile_only', 'false')) except ValueError: mobile_only = False programs_config = kwargs.get('programs_config') or ProgramsApiConfig.current() if not programs_config.enabled or not user.is_authenticated: raise Http404 meter = ProgramProgressMeter(request.site, user, mobile_only=mobile_only) context = { 'marketing_url': get_program_marketing_url(programs_config), 'programs': meter.engaged_programs, 'progress': meter.progress() } html = render_to_string('learner_dashboard/programs_fragment.html', context) programs_fragment = Fragment(html) self.add_fragment_resource_urls(programs_fragment) return programs_fragment
def test_course_grade_results(self, mock_get_programs): grade_percent = .8 with mock_passing_grade(percent=grade_percent): course_run_key = generate_course_run_key() data = [ ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=course_run_key), ]), ] ) ] mock_get_programs.return_value = data self._create_enrollments(course_run_key) meter = ProgramProgressMeter(self.site, self.user) program = data[0] expected = [ ProgressFactory( uuid=program['uuid'], completed=[], in_progress=[program['courses'][0]], not_started=[], grades={course_run_key: grade_percent}, ) ] self.assertEqual(meter.progress(count_only=False), expected)
def test_course_progress(self, mock_get_programs): """ Verify that the progress meter can represent progress in terms of serialized courses. """ course_run_key = generate_course_run_key() data = [ ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=course_run_key), ]), ] ) ] mock_get_programs.return_value = data self._create_enrollments(course_run_key) meter = ProgramProgressMeter(self.user) program = data[0] expected = [ ProgressFactory( uuid=program['uuid'], completed=[], in_progress=[program['courses'][0]], not_started=[] ) ] self.assertEqual(meter.progress(count_only=False), expected)
def related_programs(self): """ Returns related program data if the effective_user is enrolled. Note: related programs can be None depending on the course. """ if self.effective_user.is_anonymous: return meter = ProgramProgressMeter(self.request.site, self.effective_user) inverted_programs = meter.invert_programs() related_programs = inverted_programs.get(str(self.course_key)) if related_programs is None: return related_progress = meter.progress(programs=related_programs) progress_by_program = { progress['uuid']: progress for progress in related_progress } programs = [{ 'progress': progress_by_program[program['uuid']], 'title': program['title'], 'slug': program['type_attrs']['slug'], 'url': program['detail_url'], 'uuid': program['uuid'] } for program in related_programs] return programs
def test_no_id_professional_in_progress(self, mock_get_programs): """ Verify that the progress meter treats no-id-professional enrollments as professional. """ course_run_key = generate_course_run_key() data = [ ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=course_run_key, type=CourseMode.PROFESSIONAL), ]), ] ) ] mock_get_programs.return_value = data CourseEnrollmentFactory( user=self.user, course_id=course_run_key, mode=CourseMode.NO_ID_PROFESSIONAL_MODE ) meter = ProgramProgressMeter(self.user) program = data[0] expected = [ ProgressFactory( uuid=program['uuid'], completed=[], in_progress=[program['courses'][0]], not_started=[] ) ] self.assertEqual(meter.progress(count_only=False), expected)
def handle(self, *args, **options): """ Command's entry point. """ should_commit = not options['no_commit'] email_sent_records = [] site = Site.objects.get_current() course_to_users_maps = self.get_passed_course_to_users_maps() for completed_course_id, users in course_to_users_maps.items(): course_linked_programs = get_programs(course=completed_course_id) course_linked_programs = self.sort_programs(course_linked_programs) if course_linked_programs: for user in users: meter = ProgramProgressMeter(site=site, user=user, include_course_entitlements=False) programs_progress = meter.progress(programs=course_linked_programs, count_only=False) suggested_program_progress, suggested_course_run = self.get_course_run_to_suggest( programs_progress, completed_course_id ) if suggested_course_run: suggested_program = self.get_program(course_linked_programs, suggested_program_progress) completed_course_run = self.get_course_run(suggested_program, completed_course_id) if should_commit: self.emit_event(user, suggested_program, suggested_course_run, completed_course_run) email_sent_records.append( f'User: {user.username}, Completed Course: {completed_course_id}, ' f'Suggested Course: {suggested_course_run["key"]}' ) LOGGER.info( '[Program Course Nudge Email] %s Emails sent. Records: %s', len(email_sent_records), email_sent_records, )
def test_course_progress(self, mock_get_programs): """ Verify that the progress meter can represent progress in terms of serialized courses. """ course_run_key = generate_course_run_key() data = [ ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=course_run_key), ]), ] ) ] mock_get_programs.return_value = data self._create_enrollments(course_run_key) meter = ProgramProgressMeter(self.site, self.user) program = data[0] expected = [ ProgressFactory( uuid=program['uuid'], completed=[], in_progress=[program['courses'][0]], not_started=[], grades={course_run_key: 0.0}, ) ] self.assertEqual(meter.progress(count_only=False), expected)
def test_course_grade_results(self, mock_get_programs): grade_percent = .8 with mock_passing_grade(percent=grade_percent): course_run_key = generate_course_run_key() data = [ ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=course_run_key), ]), ] ) ] mock_get_programs.return_value = data self._create_enrollments(course_run_key) meter = ProgramProgressMeter(self.site, self.user) program = data[0] expected = [ ProgressFactory( uuid=program['uuid'], completed=[], in_progress=[program['courses'][0]], not_started=[], grades={course_run_key: grade_percent}, ) ] self.assertEqual(meter.progress(count_only=False), expected)
def test_no_id_professional_in_progress(self, mock_get_programs): """ Verify that the progress meter treats no-id-professional enrollments as professional. """ course_run_key = generate_course_run_key() data = [ ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=course_run_key, type=CourseMode.PROFESSIONAL), ]), ] ) ] mock_get_programs.return_value = data CourseEnrollmentFactory( user=self.user, course_id=course_run_key, mode=CourseMode.NO_ID_PROFESSIONAL_MODE ) meter = ProgramProgressMeter(self.site, self.user) program = data[0] expected = [ ProgressFactory( uuid=program['uuid'], completed=[], in_progress=[program['courses'][0]], not_started=[] ) ] self.assertEqual(meter.progress(count_only=False), expected)
def render_to_fragment(self, request, **kwargs): """ Render the program listing fragment. """ user = request.user try: mobile_only = json.loads(request.GET.get('mobile_only', 'false')) except ValueError: mobile_only = False programs_config = kwargs.get( 'programs_config') or ProgramsApiConfig.current() if not programs_config.enabled or not user.is_authenticated: raise Http404 meter = ProgramProgressMeter(request.site, user, mobile_only=mobile_only) context = { 'marketing_url': get_program_marketing_url(programs_config, mobile_only), 'programs': meter.engaged_programs, 'progress': meter.progress() } html = render_to_string('learner_dashboard/programs_fragment.html', context) programs_fragment = Fragment(html) self.add_fragment_resource_urls(programs_fragment) return programs_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() 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 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 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 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_listing(request): """View a list of programs in which the user is engaged.""" programs_config = ProgramsApiConfig.current() if not programs_config.enabled: raise Http404 meter = ProgramProgressMeter(request.user) context = { 'disable_courseware_js': True, 'marketing_url': get_program_marketing_url(programs_config), 'nav_hidden': True, 'programs': meter.engaged_programs, 'progress': meter.progress(), 'show_program_listing': programs_config.enabled, 'uses_pattern_library': True, } return render_to_response('learner_dashboard/programs.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.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_in_progress_course_upgrade_deadline_check(self, offset, mock_get_programs): """ Verify that if the user's enrollment is not of the same type as the course run, the course will only count as in progress if there is another available seat with the right type for which the upgrade deadline has not passed. """ course_run_key = generate_course_run_key() now = datetime.datetime.now(utc) upgrade_deadline = None if not offset else str(now + datetime.timedelta( days=offset)) required_seat = SeatFactory(type='verified', upgrade_deadline=upgrade_deadline) enrolled_seat = SeatFactory(type='audit') seats = [required_seat, enrolled_seat] data = [ ProgramFactory(courses=[ CourseFactory(course_runs=[ CourseRunFactory( key=course_run_key, type='verified', seats=seats), ]), ]) ] mock_get_programs.return_value = data CourseEnrollmentFactory(user=self.user, course_id=course_run_key, mode='audit') meter = ProgramProgressMeter(self.site, self.user) program = data[0] expected = [ ProgressFactory(uuid=program['uuid'], completed=0, in_progress=1 if offset in [None, 1] else 0, not_started=1 if offset in [-1] else 0) ] self.assertEqual(meter.progress(count_only=True), 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 render_to_fragment(self, request, **kwargs): """ Render the program listing fragment. """ user = request.user programs_config = kwargs.get('programs_config') or ProgramsApiConfig.current() if not programs_config.enabled or not user.is_authenticated(): raise Http404 meter = ProgramProgressMeter(request.site, user) context = { 'marketing_url': get_program_marketing_url(programs_config), 'programs': meter.engaged_programs, 'progress': meter.progress() } html = render_to_string('learner_dashboard/programs_fragment.html', context) programs_fragment = Fragment(html) self.add_fragment_resource_urls(programs_fragment) return programs_fragment
def test_in_progress_course_upgrade_deadline_check(self, offset, mock_get_programs): """ Verify that if the user's enrollment is not of the same type as the course run, the course will only count as in progress if there is another available seat with the right type for which the upgrade deadline has not passed. """ course_run_key = generate_course_run_key() now = datetime.datetime.now(utc) upgrade_deadline = None if not offset else str(now + datetime.timedelta(days=offset)) required_seat = SeatFactory(type='verified', upgrade_deadline=upgrade_deadline) enrolled_seat = SeatFactory(type='audit') seats = [required_seat, enrolled_seat] data = [ ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=course_run_key, type='verified', seats=seats), ]), ] ) ] mock_get_programs.return_value = data CourseEnrollmentFactory(user=self.user, course_id=course_run_key, mode='audit') meter = ProgramProgressMeter(self.site, self.user) program = data[0] expected = [ ProgressFactory( uuid=program['uuid'], completed=0, in_progress=1 if offset in [None, 1] else 0, not_started=1 if offset in [-1] else 0, grades={course_run_key: 0.0}, ) ] self.assertEqual(meter.progress(count_only=True), expected)
def test_in_progress_course_upgrade_deadline_check(self, modifier, mock_get_programs): """ Verify that if the user's enrollment is not of the same type as the course run, the course will only count as in progress if there is another available seat with the right type, where the upgrade deadline has not expired. """ course_run_key = generate_course_run_key() now = datetime.datetime.now(utc) date_modifier = modifier * datetime.timedelta(days=1) seat_with_upgrade_deadline = SeatFactory(type='test', upgrade_deadline=str(now + date_modifier)) enrolled_seat = SeatFactory(type='verified') seats = [seat_with_upgrade_deadline, enrolled_seat] data = [ ProgramFactory( courses=[ CourseFactory(course_runs=[ CourseRunFactory(key=course_run_key, type='test', seats=seats), ]), ] ) ] mock_get_programs.return_value = data self._create_enrollments(course_run_key) meter = ProgramProgressMeter(self.user) program = data[0] expected = [ ProgressFactory( uuid=program['uuid'], completed=0, in_progress=1 if modifier == 1 else 0, not_started=1 if modifier == -1 else 0 ) ] self.assertEqual(meter.progress(count_only=True), expected)
def render_to_fragment(self, request, **kwargs): """ Render the program listing fragment. """ user = request.user programs_config = kwargs.get( 'programs_config') or ProgramsApiConfig.current() if not programs_config.enabled or not user.is_authenticated(): raise Http404 meter = ProgramProgressMeter(request.site, user) context = { 'marketing_url': get_program_marketing_url(programs_config), 'programs': meter.engaged_programs, 'progress': meter.progress() } html = render_to_string('learner_dashboard/programs_fragment.html', context) programs_fragment = Fragment(html) self.add_fragment_resource_urls(programs_fragment) return programs_fragment
def get(self, request, enterprise_uuid): """ Return a list of a enterprise learner's all enrolled programs with their progress. Args: request (Request): DRF request object. enterprise_uuid (string): UUID of an enterprise customer. """ user = request.user enrollments = self._get_enterprise_course_enrollments( enterprise_uuid, user) meter = ProgramProgressMeter(request.site, user, enrollments=enrollments, mobile_only=False, include_course_entitlements=False) engaged_programs = meter.engaged_programs progress = meter.progress(programs=engaged_programs) programs = self._extract_minimal_required_programs_data( engaged_programs) programs = self._combine_programs_data_and_progress(programs, progress) return Response(programs)
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
def get_experiment_user_metadata_context(course, user): """ Return a context dictionary with the keys used by the user_metadata.html. """ enrollment_mode = None enrollment_time = None enrollment = None # TODO: clean up as part of REVO-28 (START) has_non_audit_enrollments = None # TODO: clean up as part of REVO-28 (END) # TODO: clean up as part of REVEM-106 (START) program_key = None # TODO: clean up as part of REVEM-106 (END) try: # TODO: clean up as part of REVO-28 (START) user_enrollments = CourseEnrollment.objects.select_related( 'course').filter(user_id=user.id) audit_enrollments = user_enrollments.filter(mode='audit') has_non_audit_enrollments = (len(audit_enrollments) != len(user_enrollments)) # TODO: clean up as part of REVO-28 (END) enrollment = CourseEnrollment.objects.select_related('course').get( user_id=user.id, course_id=course.id) if enrollment.is_active: enrollment_mode = enrollment.mode enrollment_time = enrollment.created # TODO: clean up as part of REVEM-106 (START) # get program data for this course request = get_current_request() if request: enrollment_list = [enrollment] meter = ProgramProgressMeter(request.site, user, enrollments=enrollment_list) if meter.engaged_programs and meter.engaged_programs[0]: org_name = None courses_not_started = 0 courses_in_progress = 0 courses_completed = 0 program_data = meter.engaged_programs[0] program_data = ProgramDataExtender( program_data, user, mobile_only=False).extend() program_orgs = program_data.get( 'credit_backing_organizations') if program_orgs and program_orgs[0]: org = program_orgs[0] org_name = org.get('name') if meter.progress() and meter.progress()[0]: progress = meter.progress()[0] courses_not_started = progress.get('not_started') courses_in_progress = progress.get('in_progress') courses_completed = progress.get('completed') program_key = { 'uuid': program_data.get('uuid'), 'title': program_data.get('title'), 'marketing_url': program_data.get('marketing_url'), 'org_name': org_name, 'courses_not_started': courses_not_started, 'courses_in_progress': courses_in_progress, 'courses_completed': courses_completed, } # TODO: clean up as part of REVEM-106 (END) except CourseEnrollment.DoesNotExist: pass # Not enrolled, used the default None values # upgrade_link and upgrade_date should be None if user has passed their dynamic pacing deadline. upgrade_link, upgrade_date = check_and_get_upgrade_link_and_date( user, enrollment, course) has_staff_access = has_staff_access_to_preview_mode(user, course.id) forum_roles = [] if user.is_authenticated: forum_roles = list( Role.objects.filter( users=user, course_id=course.id).values_list('name').distinct()) # get user partition data if user.is_authenticated(): partition_groups = get_all_partitions_for_course(course) user_partitions = get_user_partition_groups(course.id, partition_groups, user, 'name') else: user_partitions = {} return { 'upgrade_link': upgrade_link, 'upgrade_price': unicode(get_cosmetic_verified_display_price(course)), 'enrollment_mode': enrollment_mode, 'enrollment_time': enrollment_time, 'pacing_type': 'self_paced' if course.self_paced else 'instructor_paced', 'upgrade_deadline': upgrade_date, 'course_key': course.id, 'course_start': course.start, 'course_end': course.end, 'has_staff_access': has_staff_access, 'forum_roles': forum_roles, 'partition_groups': user_partitions, # TODO: clean up as part of REVO-28 (START) 'has_non_audit_enrollments': has_non_audit_enrollments, # TODO: clean up as part of REVO-28 (END) # TODO: clean up as part of REVEM-106 (START) 'program_key_fields': program_key, # TODO: clean up as part of REVEM-106 (END) }