def test_enabled_for_enrollment_flag_override(self): self.assertTrue( CourseDurationLimitConfig.enabled_for_enrollment(None, None, None)) self.assertTrue( CourseDurationLimitConfig.enabled_for_enrollment( Mock(name='enrollment'), Mock(name='user'), None)) self.assertTrue( CourseDurationLimitConfig.enabled_for_enrollment( Mock(name='enrollment'), None, Mock(name='course_key')))
def register_course_expired_message(request, course): """ Add a banner notifying the user of the user course expiration date if it exists. """ if not CourseDurationLimitConfig.enabled_for_enrollment(user=request.user, course_key=course.id): return expiration_date = get_user_course_expiration_date(request.user, course) if not expiration_date: return if is_masquerading_as_student(request.user, course.id) and timezone.now() > expiration_date: upgrade_message = _('This learner does not have access to this course. ' 'Their access expired on {expiration_date}.') PageLevelMessages.register_warning_message( request, HTML(upgrade_message).format( expiration_date=expiration_date.strftime('%b %-d') ) ) else: enrollment = CourseEnrollment.get_enrollment(request.user, course.id) if enrollment is None: return upgrade_deadline = enrollment.upgrade_deadline if upgrade_deadline is None: return now = timezone.now() course_upgrade_deadline = enrollment.course_upgrade_deadline if now > upgrade_deadline: upgrade_deadline = course_upgrade_deadline expiration_message = _('{strong_open}Audit Access Expires {expiration_date}{strong_close}' '{line_break}You lose all access to this course, including your progress, on ' '{expiration_date}.') upgrade_deadline_message = _('{line_break}Upgrade by {upgrade_deadline} to get unlimited access to the course ' 'as long as it exists on the site. {a_open}Upgrade now{sronly_span_open} to ' 'retain access past {expiration_date}{span_close}{a_close}') full_message = expiration_message if now < course_upgrade_deadline: full_message += upgrade_deadline_message PageLevelMessages.register_info_message( request, Text(full_message).format( a_open=HTML('<a href="{upgrade_link}">').format( upgrade_link=verified_upgrade_deadline_link(user=request.user, course=course) ), sronly_span_open=HTML('<span class="sr-only">'), sighted_only_span_open=HTML('<span aria-hidden="true">'), span_close=HTML('</span>'), a_close=HTML('</a>'), expiration_date=expiration_date.strftime('%b. %-d, %Y'), strong_open=HTML('<strong>'), strong_close=HTML('</strong>'), line_break=HTML('<br>'), upgrade_deadline=upgrade_deadline.strftime('%b. %-d, %Y') ) )
def test_enabled_for_enrollment_flag_override(self): self.assertTrue(CourseDurationLimitConfig.enabled_for_enrollment( None, None, None )) self.assertTrue(CourseDurationLimitConfig.enabled_for_enrollment( Mock(name='enrollment'), Mock(name='user'), None )) self.assertTrue(CourseDurationLimitConfig.enabled_for_enrollment( Mock(name='enrollment'), None, Mock(name='course_key') ))
def get_audit_access_expiration(user, course): """ Return the expiration date for the user's audit access to this course. """ if not CourseDurationLimitConfig.enabled_for_enrollment(user=user, course_key=course.id): return None return get_user_course_expiration_date(user, course)
def get_audit_access_expires(self, model): """ Returns expiration date for a course audit expiration, if any or null """ if not CourseDurationLimitConfig.enabled_for_enrollment(user=model.user, course_key=model.course.id): return None return get_user_course_expiration_date(model.user, model.course)
def get_audit_access_expires(self, model): """ Returns expiration date for a course audit expiration, if any or null """ if not CourseDurationLimitConfig.enabled_for_enrollment(model.user, model.course): return None return get_user_course_expiration_date(model.user, model.course)
def get_audit_access_expiration(user, course): """ Return the expiration date for the user's audit access to this course. """ if AUDIT_DEADLINE_FLAG.is_enabled(): if not CourseDurationLimitConfig.enabled_for_enrollment(user=user, course_key=course.id): return None return get_user_course_expiration_date(user, course) return None
def check_course_expired(user, course): """ Check if the course expired for the user. """ if not CourseDurationLimitConfig.enabled_for_enrollment(user=user, course_key=course.id): return ACCESS_GRANTED expiration_date = get_user_course_expiration_date(user, course) if expiration_date and timezone.now() > expiration_date: return AuditExpiredError(user, course, expiration_date) return ACCESS_GRANTED
def test_enabled_for_enrollment_failure(self): with pytest.raises(ValueError): CourseDurationLimitConfig.enabled_for_enrollment(None, None) with pytest.raises(ValueError): CourseDurationLimitConfig.enabled_for_enrollment( Mock(name='user'), None) with pytest.raises(ValueError): CourseDurationLimitConfig.enabled_for_enrollment( None, Mock(name='course_key'))
def test_enabled_for_enrollment( self, already_enrolled, pass_enrollment, enrolled_before_enabled, ): # Tweak the day to enable the config so that it is either before # or after today (which is when the enrollment will be created) if enrolled_before_enabled: enabled_as_of = date.today() + timedelta(days=1) else: enabled_as_of = date.today() - timedelta(days=1) CourseDurationLimitConfig.objects.create( enabled=True, course=self.course_overview, enabled_as_of=enabled_as_of, ) if already_enrolled: existing_enrollment = CourseEnrollmentFactory.create( user=self.user, course=self.course_overview, ) else: existing_enrollment = None if pass_enrollment: enrollment = existing_enrollment user = None course_key = None else: enrollment = None user = self.user course_key = self.course_overview.id if pass_enrollment: query_count = 4 else: query_count = 5 with self.assertNumQueries(query_count): enabled = CourseDurationLimitConfig.enabled_for_enrollment( enrollment=enrollment, user=user, course_key=course_key, ) self.assertEqual(not enrolled_before_enabled, enabled)
def test_enabled_for_enrollment( self, already_enrolled, pass_enrollment, enrolled_before_enabled, ): # Tweak the datetime to enable the config so that it is either before # or after now (which is when the enrollment will be created) if enrolled_before_enabled: enabled_as_of = timezone.now() + timedelta(days=1) else: enabled_as_of = timezone.now() - timedelta(days=1) CourseDurationLimitConfig.objects.create( enabled=True, course=self.course_overview, enabled_as_of=enabled_as_of, ) if already_enrolled: existing_enrollment = CourseEnrollmentFactory.create( user=self.user, course=self.course_overview, ) else: existing_enrollment = None if pass_enrollment: enrollment = existing_enrollment user = None course_key = None else: enrollment = None user = self.user course_key = self.course_overview.id query_count = 7 if pass_enrollment and already_enrolled: query_count = 6 with self.assertNumQueries(query_count): enabled = CourseDurationLimitConfig.enabled_for_enrollment( enrollment=enrollment, user=user, course_key=course_key, ) self.assertEqual(not enrolled_before_enabled, enabled)
def check_course_expired(user, course): """ Check if the course expired for the user. """ # masquerading course staff should always have access if get_course_masquerade(user, course.id): return ACCESS_GRANTED if not CourseDurationLimitConfig.enabled_for_enrollment(user=user, course_key=course.id): return ACCESS_GRANTED expiration_date = get_user_course_expiration_date(user, course) if expiration_date and timezone.now() > expiration_date: return AuditExpiredError(user, course, expiration_date) return ACCESS_GRANTED
def check_course_expired(user, course): """ Check if the course expired for the user. """ # masquerading course staff should always have access if get_course_masquerade(user, course.id): return ACCESS_GRANTED if not CourseDurationLimitConfig.enabled_for_enrollment(user=user, course_key=course.id): return ACCESS_GRANTED expiration_date = get_user_course_expiration_date(user, course) if expiration_date and timezone.now() > expiration_date: return AuditExpiredError(user, course, expiration_date) return ACCESS_GRANTED
def register_course_expired_message(request, course): """ Add a banner notifying the user of the user course expiration date if it exists. """ if CourseDurationLimitConfig.enabled_for_enrollment(user=request.user, course_key=course.id): expiration_date = get_user_course_expiration_date(request.user, course) if expiration_date: upgrade_message = _('Your access to this course expires on {expiration_date}. \ <a href="{upgrade_link}">Upgrade now</a> for unlimited access.') PageLevelMessages.register_info_message( request, HTML(upgrade_message).format( expiration_date=expiration_date.strftime('%b %-d'), upgrade_link=verified_upgrade_deadline_link(user=request.user, course=course) ) )
def get_user_course_duration(user, course): """ Return a timedelta measuring the duration of the course for a particular user. Business Logic: - Course access duration is bounded by the min and max duration. - If course fields are missing, default course access duration to MIN_DURATION. """ if not CourseDurationLimitConfig.enabled_for_enrollment(user, course): return None enrollment = CourseEnrollment.get_enrollment(user, course.id) if enrollment is None or enrollment.mode != CourseMode.AUDIT: return None verified_mode = CourseMode.verified_mode_for_course(course=course, include_expired=True) if not verified_mode: return None return get_expected_duration(course)
def test_enabled_for_enrollment_failure(self): with self.assertRaises(ValueError): CourseDurationLimitConfig.enabled_for_enrollment(None, None, None) with self.assertRaises(ValueError): CourseDurationLimitConfig.enabled_for_enrollment( Mock(name='enrollment'), Mock(name='user'), None ) with self.assertRaises(ValueError): CourseDurationLimitConfig.enabled_for_enrollment( Mock(name='enrollment'), None, Mock(name='course_key') )
def register_course_expired_message(request, course): """ Add a banner notifying the user of the user course expiration date if it exists. """ if not CourseDurationLimitConfig.enabled_for_enrollment( user=request.user, course_key=course.id): return expiration_date = get_user_course_expiration_date(request.user, course) if not expiration_date: return if is_masquerading_as_student( request.user, course.id) and timezone.now() > expiration_date: upgrade_message = _( 'This learner would not have access to this course. ' 'Their access expired on {expiration_date}.') PageLevelMessages.register_warning_message( request, HTML(upgrade_message).format( expiration_date=expiration_date.strftime('%b %-d'))) else: upgrade_message = _( 'Your access to this course expires on {expiration_date}. \ {a_open}Upgrade now {sronly_span_open}to retain access past {expiration_date}.\ {span_close}{a_close}{sighted_only_span_open}for unlimited access.{span_close}' ) PageLevelMessages.register_info_message( request, Text(upgrade_message).format( a_open=HTML('<a href="{upgrade_link}">').format( upgrade_link=verified_upgrade_deadline_link( user=request.user, course=course)), sronly_span_open=HTML('<span class="sr-only">'), sighted_only_span_open=HTML('<span aria-hidden="true">'), span_close=HTML('</span>'), a_close=HTML('</a>'), expiration_date=expiration_date.strftime('%b %-d'), ))
def register_course_expired_message(request, course): """ Add a banner notifying the user of the user course expiration date if it exists. """ if not CourseDurationLimitConfig.enabled_for_enrollment(user=request.user, course_key=course.id): return expiration_date = get_user_course_expiration_date(request.user, course) if not expiration_date: return if is_masquerading_as_student(request.user, course.id) and timezone.now() > expiration_date: upgrade_message = _('This learner would not have access to this course. ' 'Their access expired on {expiration_date}.') PageLevelMessages.register_warning_message( request, HTML(upgrade_message).format( expiration_date=expiration_date.strftime('%b %-d') ) ) else: upgrade_message = _('Your access to this course expires on {expiration_date}. \ {a_open}Upgrade now {sronly_span_open}to retain access past {expiration_date}.\ {span_close}{a_close}{sighted_only_span_open}for unlimited access.{span_close}') PageLevelMessages.register_info_message( request, Text(upgrade_message).format( a_open=HTML('<a href="{upgrade_link}">').format( upgrade_link=verified_upgrade_deadline_link(user=request.user, course=course) ), sronly_span_open=HTML('<span class="sr-only">'), sighted_only_span_open=HTML('<span aria-hidden="true">'), span_close=HTML('</span>'), a_close=HTML('</a>'), expiration_date=expiration_date.strftime('%b %-d'), ) )
def test_enabled_for_enrollment( self, already_enrolled, enrolled_before_enabled, ): # Tweak the datetime to enable the config so that it is either before # or after now (which is when the enrollment will be created) if enrolled_before_enabled: enabled_as_of = timezone.now() + timedelta(days=1) else: enabled_as_of = timezone.now() - timedelta(days=1) CourseDurationLimitConfig.objects.create( enabled=True, course=self.course_overview, enabled_as_of=enabled_as_of, ) if already_enrolled: existing_enrollment = CourseEnrollmentFactory.create( # lint-amnesty, pylint: disable=unused-variable user=self.user, course=self.course_overview, ) else: existing_enrollment = None user = self.user course_key = self.course_overview.id # lint-amnesty, pylint: disable=unused-variable query_count = 7 with self.assertNumQueries(query_count): enabled = CourseDurationLimitConfig.enabled_for_enrollment( user, self.course_overview) assert (not enrolled_before_enabled) == enabled
def generate_course_expired_message(user, course): """ Generate the message for the user course expiration date if it exists. """ if not CourseDurationLimitConfig.enabled_for_enrollment( user=user, course_key=course.id): return expiration_date = get_user_course_expiration_date(user, course) if not expiration_date: return if is_masquerading_as_specific_student( user, course.id) and timezone.now() > expiration_date: upgrade_message = _( 'This learner does not have access to this course. ' u'Their access expired on {expiration_date}.') return HTML(upgrade_message).format(expiration_date=strftime_localized( expiration_date, EXPIRATION_DATE_FORMAT_STR)) else: enrollment = CourseEnrollment.get_enrollment(user, course.id) if enrollment is None: return upgrade_deadline = enrollment.upgrade_deadline now = timezone.now() course_upgrade_deadline = enrollment.course_upgrade_deadline if (not upgrade_deadline) or (upgrade_deadline < now): upgrade_deadline = course_upgrade_deadline expiration_message = _( u'{strong_open}Audit Access Expires {expiration_date}{strong_close}' u'{line_break}You lose all access to this course, including your progress, on ' u'{expiration_date}.') upgrade_deadline_message = _( u'{line_break}Upgrade by {upgrade_deadline} to get unlimited access to the course ' u'as long as it exists on the site. {a_open}Upgrade now{sronly_span_open} to ' u'retain access past {expiration_date}{span_close}{a_close}') full_message = expiration_message if upgrade_deadline and now < upgrade_deadline: full_message += upgrade_deadline_message using_upgrade_messaging = True else: using_upgrade_messaging = False language = get_language() date_string = get_date_string() formatted_expiration_date = date_string.format( language=language, formatted_date=expiration_date.strftime("%Y-%m-%d"), formatted_date_localized=strftime_localized( expiration_date, EXPIRATION_DATE_FORMAT_STR)) if using_upgrade_messaging: formatted_upgrade_deadline = date_string.format( language=language, formatted_date=upgrade_deadline.strftime("%Y-%m-%d"), formatted_date_localized=strftime_localized( upgrade_deadline, EXPIRATION_DATE_FORMAT_STR)) return HTML(full_message).format( a_open=HTML(u'<a href="{upgrade_link}">').format( upgrade_link=verified_upgrade_deadline_link( user=user, course=course)), sronly_span_open=HTML('<span class="sr-only">'), span_close=HTML('</span>'), a_close=HTML('</a>'), expiration_date=HTML(formatted_expiration_date), strong_open=HTML('<strong>'), strong_close=HTML('</strong>'), line_break=HTML('<br>'), upgrade_deadline=HTML(formatted_upgrade_deadline)) else: return HTML(full_message).format( span_close=HTML('</span>'), expiration_date=HTML(formatted_expiration_date), strong_open=HTML('<strong>'), strong_close=HTML('</strong>'), line_break=HTML('<br>'), )
def generate_course_expired_message(user, course): """ Generate the message for the user course expiration date if it exists. """ if not CourseDurationLimitConfig.enabled_for_enrollment(user=user, course_key=course.id): return expiration_date = get_user_course_expiration_date(user, course) if not expiration_date: return if is_masquerading_as_specific_student(user, course.id) and timezone.now() > expiration_date: upgrade_message = _('This learner does not have access to this course. ' u'Their access expired on {expiration_date}.') return HTML(upgrade_message).format( expiration_date=strftime_localized(expiration_date, EXPIRATION_DATE_FORMAT_STR) ) else: enrollment = CourseEnrollment.get_enrollment(user, course.id) if enrollment is None: return upgrade_deadline = enrollment.upgrade_deadline now = timezone.now() course_upgrade_deadline = enrollment.course_upgrade_deadline if (not upgrade_deadline) or (upgrade_deadline < now): upgrade_deadline = course_upgrade_deadline expiration_message = _(u'{strong_open}Audit Access Expires {expiration_date}{strong_close}' u'{line_break}You lose all access to this course, including your progress, on ' u'{expiration_date}.') upgrade_deadline_message = _(u'{line_break}Upgrade by {upgrade_deadline} to get unlimited access to the course ' u'as long as it exists on the site. {a_open}Upgrade now{sronly_span_open} to ' u'retain access past {expiration_date}{span_close}{a_close}') full_message = expiration_message if upgrade_deadline and now < upgrade_deadline: full_message += upgrade_deadline_message using_upgrade_messaging = True else: using_upgrade_messaging = False language = get_language() date_string = get_date_string() formatted_expiration_date = date_string.format( language=language, formatted_date=expiration_date.strftime("%Y-%m-%d"), formatted_date_localized=strftime_localized(expiration_date, EXPIRATION_DATE_FORMAT_STR) ) if using_upgrade_messaging: formatted_upgrade_deadline = date_string.format( language=language, formatted_date=upgrade_deadline.strftime("%Y-%m-%d"), formatted_date_localized=strftime_localized(upgrade_deadline, EXPIRATION_DATE_FORMAT_STR) ) return HTML(full_message).format( a_open=HTML(u'<a href="{upgrade_link}">').format( upgrade_link=verified_upgrade_deadline_link(user=user, course=course) ), sronly_span_open=HTML('<span class="sr-only">'), span_close=HTML('</span>'), a_close=HTML('</a>'), expiration_date=HTML(formatted_expiration_date), strong_open=HTML('<strong>'), strong_close=HTML('</strong>'), line_break=HTML('<br>'), upgrade_deadline=HTML(formatted_upgrade_deadline) ) else: return HTML(full_message).format( span_close=HTML('</span>'), expiration_date=HTML(formatted_expiration_date), strong_open=HTML('<strong>'), strong_close=HTML('</strong>'), line_break=HTML('<br>'), )
def get(self, request, course_id, error=None): """Displays the course mode choice page. Args: request (`Request`): The Django Request object. course_id (unicode): The slash-separated course key. Keyword Args: error (unicode): If provided, display this error message on the page. Returns: Response """ course_key = CourseKey.from_string(course_id) # Check whether the user has access to this course # based on country access rules. embargo_redirect = embargo_api.redirect_if_blocked( course_key, user=request.user, ip_address=get_ip(request), url=request.path ) if embargo_redirect: return redirect(embargo_redirect) enrollment_mode, is_active = CourseEnrollment.enrollment_mode_for_user(request.user, course_key) modes = CourseMode.modes_for_course_dict(course_key) ecommerce_service = EcommerceService() # We assume that, if 'professional' is one of the modes, it should be the *only* mode. # If there are both modes, default to non-id-professional. has_enrolled_professional = (CourseMode.is_professional_slug(enrollment_mode) and is_active) if CourseMode.has_professional_mode(modes) and not has_enrolled_professional: purchase_workflow = request.GET.get("purchase_workflow", "single") verify_url = reverse('verify_student_start_flow', kwargs={'course_id': unicode(course_key)}) redirect_url = "{url}?purchase_workflow={workflow}".format(url=verify_url, workflow=purchase_workflow) if ecommerce_service.is_enabled(request.user): professional_mode = modes.get(CourseMode.NO_ID_PROFESSIONAL_MODE) or modes.get(CourseMode.PROFESSIONAL) if purchase_workflow == "single" and professional_mode.sku: redirect_url = ecommerce_service.get_checkout_page_url(professional_mode.sku) if purchase_workflow == "bulk" and professional_mode.bulk_sku: redirect_url = ecommerce_service.get_checkout_page_url(professional_mode.bulk_sku) return redirect(redirect_url) course = modulestore().get_course(course_key) # If there isn't a verified mode available, then there's nothing # to do on this page. Send the user to the dashboard. if not CourseMode.has_verified_mode(modes): return redirect(reverse('dashboard')) # If a user has already paid, redirect them to the dashboard. if is_active and (enrollment_mode in CourseMode.VERIFIED_MODES + [CourseMode.NO_ID_PROFESSIONAL_MODE]): # If the course has started redirect to course home instead if course.has_started(): return redirect(reverse('openedx.course_experience.course_home', kwargs={'course_id': course_key})) return redirect(reverse('dashboard')) donation_for_course = request.session.get("donation_for_course", {}) chosen_price = donation_for_course.get(unicode(course_key), None) if CourseEnrollment.is_enrollment_closed(request.user, course): locale = to_locale(get_language()) enrollment_end_date = format_datetime(course.enrollment_end, 'short', locale=locale) params = urllib.urlencode({'course_closed': enrollment_end_date}) return redirect('{0}?{1}'.format(reverse('dashboard'), params)) # When a credit mode is available, students will be given the option # to upgrade from a verified mode to a credit mode at the end of the course. # This allows students who have completed photo verification to be eligible # for univerity credit. # Since credit isn't one of the selectable options on the track selection page, # we need to check *all* available course modes in order to determine whether # a credit mode is available. If so, then we show slightly different messaging # for the verified track. has_credit_upsell = any( CourseMode.is_credit_mode(mode) for mode in CourseMode.modes_for_course(course_key, only_selectable=False) ) course_id = text_type(course_key) context = { "course_modes_choose_url": reverse( "course_modes_choose", kwargs={'course_id': course_id} ), "modes": modes, "has_credit_upsell": has_credit_upsell, "course_name": course.display_name_with_default, "course_org": course.display_org_with_default, "course_num": course.display_number_with_default, "chosen_price": chosen_price, "error": error, "responsive": True, "nav_hidden": True, "content_gating_enabled": ContentTypeGatingConfig.enabled_for_enrollment( user=request.user, course_key=course_key ), "course_duration_limit_enabled": CourseDurationLimitConfig.enabled_for_enrollment( user=request.user, course_key=course_key ), } context.update( get_experiment_user_metadata_context( course, request.user, ) ) title_content = _("Congratulations! You are now enrolled in {course_name}").format( course_name=course.display_name_with_default ) context["title_content"] = title_content if "verified" in modes: verified_mode = modes["verified"] context["suggested_prices"] = [ decimal.Decimal(x.strip()) for x in verified_mode.suggested_prices.split(",") if x.strip() ] context["currency"] = verified_mode.currency.upper() context["min_price"] = verified_mode.min_price context["verified_name"] = verified_mode.name context["verified_description"] = verified_mode.description if verified_mode.sku: context["use_ecommerce_payment_flow"] = ecommerce_service.is_enabled(request.user) context["ecommerce_payment_page"] = ecommerce_service.payment_page_url() context["sku"] = verified_mode.sku context["bulk_sku"] = verified_mode.bulk_sku context['currency_data'] = [] if waffle.switch_is_active('local_currency'): if 'edx-price-l10n' not in request.COOKIES: currency_data = get_currency_data() try: context['currency_data'] = json.dumps(currency_data) except TypeError: pass return render_to_response("course_modes/choose.html", context)
def get(self, request, course_id, error=None): # lint-amnesty, pylint: disable=too-many-statements """Displays the course mode choice page. Args: request (`Request`): The Django Request object. course_id (unicode): The slash-separated course key. Keyword Args: error (unicode): If provided, display this error message on the page. Returns: Response """ course_key = CourseKey.from_string(course_id) # Check whether the user has access to this course # based on country access rules. embargo_redirect = embargo_api.redirect_if_blocked( course_key, user=request.user, ip_address=get_client_ip(request)[0], url=request.path) if embargo_redirect: return redirect(embargo_redirect) enrollment_mode, is_active = CourseEnrollment.enrollment_mode_for_user( request.user, course_key) increment('track-selection.{}.{}'.format( enrollment_mode, 'active' if is_active else 'inactive')) increment('track-selection.views') if enrollment_mode is None: LOG.info( 'Rendering track selection for unenrolled user, referred by %s', request.META.get('HTTP_REFERER')) modes = CourseMode.modes_for_course_dict(course_key) ecommerce_service = EcommerceService() # We assume that, if 'professional' is one of the modes, it should be the *only* mode. # If there are both modes, default to 'no-id-professional'. has_enrolled_professional = ( CourseMode.is_professional_slug(enrollment_mode) and is_active) if CourseMode.has_professional_mode( modes) and not has_enrolled_professional: purchase_workflow = request.GET.get("purchase_workflow", "single") redirect_url = IDVerificationService.get_verify_location( course_id=course_key) if ecommerce_service.is_enabled(request.user): professional_mode = modes.get( CourseMode.NO_ID_PROFESSIONAL_MODE) or modes.get( CourseMode.PROFESSIONAL) if purchase_workflow == "single" and professional_mode.sku: redirect_url = ecommerce_service.get_checkout_page_url( professional_mode.sku) if purchase_workflow == "bulk" and professional_mode.bulk_sku: redirect_url = ecommerce_service.get_checkout_page_url( professional_mode.bulk_sku) return redirect(redirect_url) course = modulestore().get_course(course_key) # If there isn't a verified mode available, then there's nothing # to do on this page. Send the user to the dashboard. if not CourseMode.has_verified_mode(modes): return self._redirect_to_course_or_dashboard( course, course_key, request.user) # If a user has already paid, redirect them to the dashboard. if is_active and (enrollment_mode in CourseMode.VERIFIED_MODES + [CourseMode.NO_ID_PROFESSIONAL_MODE]): return self._redirect_to_course_or_dashboard( course, course_key, request.user) donation_for_course = request.session.get("donation_for_course", {}) chosen_price = donation_for_course.get(str(course_key), None) if CourseEnrollment.is_enrollment_closed(request.user, course): locale = to_locale(get_language()) enrollment_end_date = format_datetime(course.enrollment_end, 'short', locale=locale) params = six.moves.urllib.parse.urlencode( {'course_closed': enrollment_end_date}) return redirect('{}?{}'.format(reverse('dashboard'), params)) # When a credit mode is available, students will be given the option # to upgrade from a verified mode to a credit mode at the end of the course. # This allows students who have completed photo verification to be eligible # for university credit. # Since credit isn't one of the selectable options on the track selection page, # we need to check *all* available course modes in order to determine whether # a credit mode is available. If so, then we show slightly different messaging # for the verified track. has_credit_upsell = any( CourseMode.is_credit_mode(mode) for mode in CourseMode.modes_for_course(course_key, only_selectable=False)) course_id = str(course_key) gated_content = ContentTypeGatingConfig.enabled_for_enrollment( user=request.user, course_key=course_key) context = { "course_modes_choose_url": reverse("course_modes_choose", kwargs={'course_id': course_id}), "modes": modes, "has_credit_upsell": has_credit_upsell, "course_name": course.display_name_with_default, "course_org": course.display_org_with_default, "course_num": course.display_number_with_default, "chosen_price": chosen_price, "error": error, "responsive": True, "nav_hidden": True, "content_gating_enabled": gated_content, "course_duration_limit_enabled": CourseDurationLimitConfig.enabled_for_enrollment( request.user, course), } context.update( get_experiment_user_metadata_context( course, request.user, )) title_content = '' if enrollment_mode: title_content = _( "Congratulations! You are now enrolled in {course_name}" ).format(course_name=course.display_name_with_default) context["title_content"] = title_content if "verified" in modes: verified_mode = modes["verified"] context["suggested_prices"] = [ decimal.Decimal(x.strip()) for x in verified_mode.suggested_prices.split(",") if x.strip() ] price_before_discount = verified_mode.min_price course_price = price_before_discount enterprise_customer = enterprise_customer_for_request(request) LOG.info( '[e-commerce calculate API] Going to hit the API for user [%s] linked to [%s] enterprise', request.user.username, enterprise_customer.get('name') if isinstance( enterprise_customer, dict) else None # Test Purpose ) if enterprise_customer and verified_mode.sku: course_price = get_course_final_price(request.user, verified_mode.sku, price_before_discount) context["currency"] = verified_mode.currency.upper() context["currency_symbol"] = get_currency_symbol( verified_mode.currency.upper()) context["min_price"] = course_price context["verified_name"] = verified_mode.name context["verified_description"] = verified_mode.description # if course_price is equal to price_before_discount then user doesn't entitle to any discount. if course_price != price_before_discount: context["price_before_discount"] = price_before_discount if verified_mode.sku: context[ "use_ecommerce_payment_flow"] = ecommerce_service.is_enabled( request.user) context[ "ecommerce_payment_page"] = ecommerce_service.payment_page_url( ) context["sku"] = verified_mode.sku context["bulk_sku"] = verified_mode.bulk_sku context['currency_data'] = [] if waffle.switch_is_active('local_currency'): if 'edx-price-l10n' not in request.COOKIES: currency_data = get_currency_data() try: context['currency_data'] = json.dumps(currency_data) except TypeError: pass language = get_language() context['track_links'] = get_verified_track_links(language) duration = get_user_course_duration(request.user, course) deadline = duration and get_user_course_expiration_date( request.user, course) if deadline: formatted_audit_access_date = strftime_localized_html( deadline, 'SHORT_DATE') context['audit_access_deadline'] = formatted_audit_access_date fbe_is_on = deadline and gated_content # Route to correct Track Selection page. # REV-2133 TODO Value Prop: remove waffle flag after testing is completed # and happy path version is ready to be rolled out to all users. if VALUE_PROP_TRACK_SELECTION_FLAG.is_enabled(): if not error: # TODO: Remove by executing REV-2355 if not enterprise_customer_for_request( request): # TODO: Remove by executing REV-2342 if fbe_is_on: return render_to_response("course_modes/fbe.html", context) else: return render_to_response("course_modes/unfbe.html", context) # If error or enterprise_customer, failover to old choose.html page return render_to_response("course_modes/choose.html", context)
def register_course_expired_message(request, course): """ Add a banner notifying the user of the user course expiration date if it exists. """ if not CourseDurationLimitConfig.enabled_for_enrollment( user=request.user, course_key=course.id): return expiration_date = get_user_course_expiration_date(request.user, course) if not expiration_date: return if is_masquerading_as_specific_student( request.user, course.id) and timezone.now() > expiration_date: upgrade_message = _( 'This learner does not have access to this course. ' 'Their access expired on {expiration_date}.') PageLevelMessages.register_warning_message( request, HTML(upgrade_message).format(expiration_date=strftime_localized( expiration_date, '%b. %-d, %Y'))) else: enrollment = CourseEnrollment.get_enrollment(request.user, course.id) if enrollment is None: return upgrade_deadline = enrollment.upgrade_deadline now = timezone.now() course_upgrade_deadline = enrollment.course_upgrade_deadline if (not upgrade_deadline) or (upgrade_deadline < now): upgrade_deadline = course_upgrade_deadline expiration_message = _( '{strong_open}Audit Access Expires {expiration_date}{strong_close}' '{line_break}You lose all access to this course, including your progress, on ' '{expiration_date}.') upgrade_deadline_message = _( '{line_break}Upgrade by {upgrade_deadline} to get unlimited access to the course ' 'as long as it exists on the site. {a_open}Upgrade now{sronly_span_open} to ' 'retain access past {expiration_date}{span_close}{a_close}') full_message = expiration_message if upgrade_deadline and now < upgrade_deadline: full_message += upgrade_deadline_message using_upgrade_messaging = True else: using_upgrade_messaging = False language = get_language() language_is_es = language and language.split('-')[0].lower() == 'es' if language_is_es: formatted_expiration_date = strftime_localized( expiration_date, '%-d de %b. de %Y').lower() else: formatted_expiration_date = strftime_localized( expiration_date, '%b. %-d, %Y') if using_upgrade_messaging: if language_is_es: formatted_upgrade_deadline = strftime_localized( upgrade_deadline, '%-d de %b. de %Y').lower() else: formatted_upgrade_deadline = strftime_localized( upgrade_deadline, '%b. %-d, %Y') PageLevelMessages.register_info_message( request, Text(full_message).format( a_open=HTML('<a href="{upgrade_link}">').format( upgrade_link=verified_upgrade_deadline_link( user=request.user, course=course)), sronly_span_open=HTML('<span class="sr-only">'), span_close=HTML('</span>'), a_close=HTML('</a>'), expiration_date=formatted_expiration_date, strong_open=HTML('<strong>'), strong_close=HTML('</strong>'), line_break=HTML('<br>'), upgrade_deadline=formatted_upgrade_deadline)) else: PageLevelMessages.register_info_message( request, Text(full_message).format( span_close=HTML('</span>'), expiration_date=formatted_expiration_date, strong_open=HTML('<strong>'), strong_close=HTML('</strong>'), line_break=HTML('<br>'), ))
def date(self): if not CourseDurationLimitConfig.enabled_for_enrollment( self.user, self.course): return return get_user_course_expiration_date(self.user, self.course)