def footer_context_processor(request): # pylint: disable=unused-argument """ Checks the site name to determine whether to use the edX.org footer or the Open Source Footer. """ return dict( [ ("IS_REQUEST_IN_MICROSITE", is_request_in_themed_site()) ] )
def render_is_request_in_themed_site(context): __M_caller = context.caller_stack._push_frame() try: __M_writer = context.writer() return is_request_in_themed_site() return '' finally: context.caller_stack._pop_frame()
def checkout_receipt(request): """ Receipt view. """ page_title = _('Receipt') is_payment_complete = True payment_support_email = configuration_helpers.get_value('payment_support_email', settings.PAYMENT_SUPPORT_EMAIL) payment_support_link = '<a href=\"mailto:{email}\">{email}</a>'.format(email=payment_support_email) is_cybersource = all(k in request.POST for k in ('signed_field_names', 'decision', 'reason_code')) if is_cybersource and request.POST['decision'] != 'ACCEPT': # Cybersource may redirect users to this view if it couldn't recover # from an error while capturing payment info. is_payment_complete = False page_title = _('Payment Failed') reason_code = request.POST['reason_code'] # if the problem was with the info submitted by the user, we present more detailed messages. if is_user_payment_error(reason_code): error_summary = _("There was a problem with this transaction. You have not been charged.") error_text = _( "Make sure your information is correct, or try again with a different card or another form of payment." ) else: error_summary = _("A system error occurred while processing your payment. You have not been charged.") error_text = _("Please wait a few minutes and then try again.") for_help_text = _("For help, contact {payment_support_link}.").format(payment_support_link=payment_support_link) else: # if anything goes wrong rendering the receipt, it indicates a problem fetching order data. error_summary = _("An error occurred while creating your receipt.") error_text = None # nothing particularly helpful to say if this happens. for_help_text = _( "If your course does not appear on your dashboard, contact {payment_support_link}." ).format(payment_support_link=payment_support_link) commerce_configuration = CommerceConfiguration.current() # user order cache should be cleared when a new order is placed # so user can see new order in their order history. if is_payment_complete and commerce_configuration.enabled and commerce_configuration.is_cache_enabled: cache_key = commerce_configuration.CACHE_KEY + '.' + str(request.user.id) cache.delete(cache_key) context = { 'page_title': page_title, 'is_payment_complete': is_payment_complete, 'platform_name': configuration_helpers.get_value('platform_name', settings.PLATFORM_NAME), 'verified': SoftwareSecurePhotoVerification.verification_valid_or_pending(request.user).exists(), 'error_summary': error_summary, 'error_text': error_text, 'for_help_text': for_help_text, 'payment_support_email': payment_support_email, 'username': request.user.username, 'nav_hidden': True, 'is_request_in_themed_site': is_request_in_themed_site() } return render_to_response('commerce/checkout_receipt.html', context)
def checkout_receipt(request): """ Receipt view. """ page_title = _('Receipt') is_payment_complete = True payment_support_email = configuration_helpers.get_value('payment_support_email', settings.PAYMENT_SUPPORT_EMAIL) payment_support_link = HTML(u'<a href=\"mailto:{email}\">{email}</a>').format(email=payment_support_email) is_cybersource = all(k in request.POST for k in ('signed_field_names', 'decision', 'reason_code')) if is_cybersource and request.POST['decision'] != 'ACCEPT': # Cybersource may redirect users to this view if it couldn't recover # from an error while capturing payment info. is_payment_complete = False page_title = _('Payment Failed') reason_code = request.POST['reason_code'] # if the problem was with the info submitted by the user, we present more detailed messages. if is_user_payment_error(reason_code): error_summary = _("There was a problem with this transaction. You have not been charged.") error_text = _( "Make sure your information is correct, or try again with a different card or another form of payment." ) else: error_summary = _("A system error occurred while processing your payment. You have not been charged.") error_text = _("Please wait a few minutes and then try again.") for_help_text = _(u"For help, contact {payment_support_link}.").format(payment_support_link=payment_support_link) else: # if anything goes wrong rendering the receipt, it indicates a problem fetching order data. error_summary = _("An error occurred while creating your receipt.") error_text = None # nothing particularly helpful to say if this happens. for_help_text = _( u"If your course does not appear on your dashboard, contact {payment_support_link}." ).format(payment_support_link=payment_support_link) commerce_configuration = CommerceConfiguration.current() # user order cache should be cleared when a new order is placed # so user can see new order in their order history. if is_payment_complete and commerce_configuration.enabled and commerce_configuration.is_cache_enabled: cache_key = commerce_configuration.CACHE_KEY + '.' + str(request.user.id) cache.delete(cache_key) context = { 'page_title': page_title, 'is_payment_complete': is_payment_complete, 'platform_name': configuration_helpers.get_value('platform_name', settings.PLATFORM_NAME), 'verified': IDVerificationService.user_has_valid_or_pending(request.user), 'error_summary': error_summary, 'error_text': error_text, 'for_help_text': for_help_text, 'payment_support_email': payment_support_email, 'username': request.user.username, 'nav_hidden': True, 'is_request_in_themed_site': is_request_in_themed_site() } return render_to_response('commerce/checkout_receipt.html', context)
def send_refund_notification(course_product, refund_ids): """ Notify the support team of the refund request. """ tags = ['auto_refund'] if theming_helpers.is_request_in_themed_site(): # this is not presently supported with the external service. raise NotImplementedError("Unable to send refund processing emails to support teams.") student = course_product.user subject = _("[Refund] User-Requested Refund") body = generate_refund_notification_body(student, refund_ids) requester_name = student.profile.name or student.username create_zendesk_ticket(requester_name, student.email, subject, body, tags)
def send_refund_notification(course_enrollment, refund_ids): """ Notify the support team of the refund request. """ tags = ['auto_refund'] if theming_helpers.is_request_in_themed_site(): # this is not presently supported with the external service. raise NotImplementedError("Unable to send refund processing emails to support teams.") student = course_enrollment.user subject = _("[Refund] User-Requested Refund") body = generate_refund_notification_body(student, refund_ids) requester_name = student.profile.name or student.username create_zendesk_ticket(requester_name, student.email, subject, body, tags)
def _send_refund_notification(user, refund_ids): """ Notify the support team of the refund request. Returns: bool: True if we are able to send the notification. In this case that means we were able to create a ZenDesk ticket """ tags = ['auto_refund'] if theming_helpers.is_request_in_themed_site(): # this is not presently supported with the external service. raise NotImplementedError("Unable to send refund processing emails to support teams.") # Build the information for the ZenDesk ticket student = user subject = _("[Refund] User-Requested Refund") body = _generate_refund_notification_body(student, refund_ids) requester_name = student.profile.name or student.username return create_zendesk_ticket(requester_name, student.email, subject, body, tags)
def login_and_registration_form(request, initial_mode="login"): """Render the combined login/registration form, defaulting to login This relies on the JS to asynchronously load the actual form from the user_api. Keyword Args: initial_mode (string): Either "login" or "register". """ # Determine the URL to redirect to following login/registration/third_party_auth redirect_to = get_next_url_for_login_page(request) # If we're already logged in, redirect to the dashboard if request.user.is_authenticated(): return redirect(redirect_to) # Retrieve the form descriptions from the user API form_descriptions = _get_form_descriptions(request) # If this is a themed site, revert to the old login/registration pages. # We need to do this for now to support existing themes. # Themed sites can use the new logistration page by setting # 'ENABLE_COMBINED_LOGIN_REGISTRATION' in their theme/microsite # configuration settings. if is_request_in_themed_site() and not get_themed_value('ENABLE_COMBINED_LOGIN_REGISTRATION', False): if initial_mode == "login": return old_login_view(request) elif initial_mode == "register": return old_register_view(request) # Allow external auth to intercept and handle the request ext_auth_response = _external_auth_intercept(request, initial_mode) if ext_auth_response is not None: return ext_auth_response # Our ?next= URL may itself contain a parameter 'tpa_hint=x' that we need to check. # If present, we display a login page focused on third-party auth with that provider. third_party_auth_hint = None if '?' in redirect_to: try: next_args = urlparse.parse_qs(urlparse.urlparse(redirect_to).query) provider_id = next_args['tpa_hint'][0] if third_party_auth.provider.Registry.get(provider_id=provider_id): third_party_auth_hint = provider_id initial_mode = "hinted_login" except (KeyError, ValueError, IndexError): pass # Otherwise, render the combined login/registration page context = { 'data': { 'login_redirect_url': redirect_to, 'initial_mode': initial_mode, 'third_party_auth': _third_party_auth_context(request, redirect_to), 'third_party_auth_hint': third_party_auth_hint or '', 'platform_name': get_themed_value('PLATFORM_NAME', settings.PLATFORM_NAME), # Include form descriptions retrieved from the user API. # We could have the JS client make these requests directly, # but we include them in the initial page load to avoid # the additional round-trip to the server. 'login_form_desc': json.loads(form_descriptions['login']), 'registration_form_desc': json.loads(form_descriptions['registration']), 'password_reset_form_desc': json.loads(form_descriptions['password_reset']), }, 'login_redirect_url': redirect_to, # This gets added to the query string of the "Sign In" button in header 'responsive': True, 'allow_iframing': True, 'disable_courseware_js': True, 'disable_footer': True, } return render_to_response('student_account/login_and_register.html', context)
def login_and_registration_form(request, initial_mode="login"): """Render the combined login/registration form, defaulting to login This relies on the JS to asynchronously load the actual form from the user_api. Keyword Args: initial_mode (string): Either "login" or "register". """ # Determine the URL to redirect to following login/registration/third_party_auth redirect_to = get_next_url_for_login_page(request) # If we're already logged in, redirect to the dashboard if request.user.is_authenticated(): return redirect(redirect_to) # Retrieve the form descriptions from the user API form_descriptions = _get_form_descriptions(request) # If this is a themed site, revert to the old login/registration pages. # We need to do this for now to support existing themes. # Themed sites can use the new logistration page by setting # 'ENABLE_COMBINED_LOGIN_REGISTRATION' in their # configuration settings. if is_request_in_themed_site() and not configuration_helpers.get_value('ENABLE_COMBINED_LOGIN_REGISTRATION', False): if initial_mode == "login": return old_login_view(request) elif initial_mode == "register": return old_register_view(request) # Allow external auth to intercept and handle the request ext_auth_response = _external_auth_intercept(request, initial_mode) if ext_auth_response is not None: return ext_auth_response # Our ?next= URL may itself contain a parameter 'tpa_hint=x' that we need to check. # If present, we display a login page focused on third-party auth with that provider. third_party_auth_hint = None if '?' in redirect_to: try: next_args = urlparse.parse_qs(urlparse.urlparse(redirect_to).query) provider_id = next_args['tpa_hint'][0] if third_party_auth.provider.Registry.get(provider_id=provider_id): third_party_auth_hint = provider_id initial_mode = "hinted_login" except (KeyError, ValueError, IndexError): pass # Otherwise, render the combined login/registration page context = { 'data': { 'login_redirect_url': redirect_to, 'initial_mode': initial_mode, 'third_party_auth': _third_party_auth_context(request, redirect_to), 'third_party_auth_hint': third_party_auth_hint or '', 'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME), # Include form descriptions retrieved from the user API. # We could have the JS client make these requests directly, # but we include them in the initial page load to avoid # the additional round-trip to the server. 'login_form_desc': json.loads(form_descriptions['login']), 'registration_form_desc': json.loads(form_descriptions['registration']), 'password_reset_form_desc': json.loads(form_descriptions['password_reset']), }, 'login_redirect_url': redirect_to, # This gets added to the query string of the "Sign In" button in header 'responsive': True, 'allow_iframing': True, 'disable_courseware_js': True, 'disable_footer': not configuration_helpers.get_value( 'ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER', settings.FEATURES['ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER'] ), } return render_to_response('student_account/login_and_register.html', context)
def is_enabled(self): """ Check if the service is enabled and that the site is not a microsite. """ return self.config.checkout_on_ecommerce_service and not helpers.is_request_in_themed_site()
def login_and_registration_form(request, initial_mode="login"): """Render the combined login/registration form, defaulting to login This relies on the JS to asynchronously load the actual form from the user_api. Keyword Args: initial_mode (string): Either "login" or "register". """ # Determine the URL to redirect to following login/registration/third_party_auth redirect_to = get_next_url_for_login_page(request) # If we're already logged in, redirect to the dashboard if UserProfile.has_registered(request.user): return redirect(redirect_to) if third_party_auth.is_enabled(): force_provider_id = settings.FORCED_TPA_PROVIDER_ID if force_provider_id: force_provider = third_party_auth.provider.Registry.get( provider_id=force_provider_id, ) if force_provider and force_provider.display_for_login: running_pipeline = third_party_auth.pipeline.get(request) if not running_pipeline: if initial_mode in [pipeline.AUTH_ENTRY_LOGIN, pipeline.AUTH_ENTRY_REGISTER]: tpa_url = pipeline.get_login_url( force_provider_id, initial_mode, redirect_url=redirect_to, ) return redirect(tpa_url) # Retrieve the form descriptions from the user API form_descriptions = _get_form_descriptions(request) # Our ?next= URL may itself contain a parameter 'tpa_hint=x' that we need to check. # If present, we display a login page focused on third-party auth with that provider. third_party_auth_hint = None if '?' in redirect_to: try: next_args = urlparse.parse_qs(urlparse.urlparse(redirect_to).query) provider_id = next_args['tpa_hint'][0] if third_party_auth.provider.Registry.get(provider_id=provider_id): third_party_auth_hint = provider_id initial_mode = "hinted_login" except (KeyError, ValueError, IndexError): pass set_enterprise_branding_filter_param(request=request, provider_id=third_party_auth_hint) # If this is a themed site, revert to the old login/registration pages. # We need to do this for now to support existing themes. # Themed sites can use the new logistration page by setting # 'ENABLE_COMBINED_LOGIN_REGISTRATION' in their # configuration settings. if is_request_in_themed_site() and not configuration_helpers.get_value('ENABLE_COMBINED_LOGIN_REGISTRATION', False): if initial_mode == "login": return old_login_view(request) elif initial_mode == "register": return old_register_view(request) # Allow external auth to intercept and handle the request ext_auth_response = _external_auth_intercept(request, initial_mode) if ext_auth_response is not None: return ext_auth_response # Otherwise, render the combined login/registration page context = { 'data': { 'login_redirect_url': redirect_to, 'initial_mode': initial_mode, 'third_party_auth': _third_party_auth_context(request, redirect_to), 'third_party_auth_hint': third_party_auth_hint or '', 'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME), 'support_link': configuration_helpers.get_value('SUPPORT_SITE_LINK', settings.SUPPORT_SITE_LINK), 'privacy_policy_url': marketing_link('PRIVACY'), # Include form descriptions retrieved from the user API. # We could have the JS client make these requests directly, # but we include them in the initial page load to avoid # the additional round-trip to the server. 'login_form_desc': json.loads(form_descriptions['login']), 'registration_form_desc': json.loads(form_descriptions['registration']), 'password_reset_form_desc': json.loads(form_descriptions['password_reset']), }, 'login_redirect_url': redirect_to, # This gets added to the query string of the "Sign In" button in header 'responsive': True, 'allow_iframing': True, 'disable_courseware_js': True, 'disable_footer': not configuration_helpers.get_value( 'ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER', settings.FEATURES['ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER'] ), } return render_to_response('student_account/login_and_register.html', context)
def is_enabled(self, request): """ Check if the user is activated, if the service is enabled and that the site is not a microsite. """ return (request.user.is_active and self.config.checkout_on_ecommerce_service and not helpers.is_request_in_themed_site())
def _cert_info(user, course_overview, cert_status): """ Implements the logic for cert_info -- split out for testing. Arguments: user (User): A user. course_overview (CourseOverview): A course. """ # simplify the status for the template using this lookup table template_state = { CertificateStatuses.generating: 'generating', CertificateStatuses.downloadable: 'downloadable', CertificateStatuses.notpassing: 'notpassing', CertificateStatuses.restricted: 'restricted', CertificateStatuses.auditing: 'auditing', CertificateStatuses.audit_passing: 'auditing', CertificateStatuses.audit_notpassing: 'auditing', CertificateStatuses.unverified: 'unverified', } certificate_earned_but_not_available_status = 'certificate_earned_but_not_available' default_status = 'processing' default_info = { 'status': default_status, 'show_survey_button': False, 'can_unenroll': True, } if cert_status is None: return default_info status = template_state.get(cert_status['status'], default_status) is_hidden_status = status in ('unavailable', 'processing', 'generating', 'notpassing', 'auditing') if ( not certificates_viewable_for_course(course_overview) and (status in CertificateStatuses.PASSED_STATUSES) and course_overview.certificate_available_date ): status = certificate_earned_but_not_available_status if ( course_overview.certificates_display_behavior == 'early_no_info' and is_hidden_status ): return default_info status_dict = { 'status': status, 'mode': cert_status.get('mode', None), 'linked_in_url': None, 'can_unenroll': status not in DISABLE_UNENROLL_CERT_STATES, } if status != default_status and course_overview.end_of_course_survey_url is not None: status_dict.update({ 'show_survey_button': True, 'survey_url': process_survey_link(course_overview.end_of_course_survey_url, user)}) else: status_dict['show_survey_button'] = False if status == 'downloadable': # showing the certificate web view button if certificate is downloadable state and feature flags are enabled. if has_html_certificates_enabled(course_overview): if course_overview.has_any_active_web_certificate: status_dict.update({ 'show_cert_web_view': True, 'cert_web_view_url': get_certificate_url(course_id=course_overview.id, uuid=cert_status['uuid']) }) else: # don't show download certificate button if we don't have an active certificate for course status_dict['status'] = 'unavailable' elif 'download_url' not in cert_status: log.warning( u"User %s has a downloadable cert for %s, but no download url", user.username, course_overview.id ) return default_info else: status_dict['download_url'] = cert_status['download_url'] # If enabled, show the LinkedIn "add to profile" button # Clicking this button sends the user to LinkedIn where they # can add the certificate information to their profile. linkedin_config = LinkedInAddToProfileConfiguration.current() # posting certificates to LinkedIn is not currently # supported in White Labels if linkedin_config.enabled and not theming_helpers.is_request_in_themed_site(): status_dict['linked_in_url'] = linkedin_config.add_to_profile_url( course_overview.id, course_overview.display_name, cert_status.get('mode'), cert_status['download_url'] ) if status in {'generating', 'downloadable', 'notpassing', 'restricted', 'auditing', 'unverified'}: cert_grade_percent = -1 persisted_grade_percent = -1 persisted_grade = CourseGradeFactory().read(user, course=course_overview, create_if_needed=False) if persisted_grade is not None: persisted_grade_percent = persisted_grade.percent if 'grade' in cert_status: cert_grade_percent = float(cert_status['grade']) if cert_grade_percent == -1 and persisted_grade_percent == -1: # Note: as of 11/20/2012, we know there are students in this state-- cs169.1x, # who need to be regraded (we weren't tracking 'notpassing' at first). # We can add a log.warning here once we think it shouldn't happen. return default_info status_dict['grade'] = text_type(max(cert_grade_percent, persisted_grade_percent)) return status_dict
def login_and_registration_form(request, initial_mode="login"): """Render the combined login/registration form, defaulting to login This relies on the JS to asynchronously load the actual form from the user_api. Keyword Args: initial_mode (string): Either "login" or "register". """ # Determine the URL to redirect to following login/registration/third_party_auth redirect_to = get_next_url_for_login_page(request) # If we're already logged in, redirect to the dashboard # Note: We check for the existence of login-related cookies in addition to is_authenticated # since Django's SessionAuthentication middleware auto-updates session cookies but not # the other login-related cookies. See ARCH-282. if request.user.is_authenticated and are_logged_in_cookies_set(request): return redirect(redirect_to) # Retrieve the form descriptions from the user API form_descriptions = _get_form_descriptions(request) # Our ?next= URL may itself contain a parameter 'tpa_hint=x' that we need to check. # If present, we display a login page focused on third-party auth with that provider. third_party_auth_hint = None if '?' in redirect_to: try: next_args = six.moves.urllib.parse.parse_qs(six.moves.urllib.parse.urlparse(redirect_to).query) provider_id = next_args['tpa_hint'][0] tpa_hint_provider = third_party_auth.provider.Registry.get(provider_id=provider_id) if tpa_hint_provider: if tpa_hint_provider.skip_hinted_login_dialog: # Forward the user directly to the provider's login URL when the provider is configured # to skip the dialog. if initial_mode == "register": auth_entry = pipeline.AUTH_ENTRY_REGISTER else: auth_entry = pipeline.AUTH_ENTRY_LOGIN return redirect( pipeline.get_login_url(provider_id, auth_entry, redirect_url=redirect_to) ) third_party_auth_hint = provider_id initial_mode = "hinted_login" except (KeyError, ValueError, IndexError) as ex: log.exception(u"Unknown tpa_hint provider: %s", ex) # We are defaulting to true because all themes should now be using the newer page. if is_request_in_themed_site() and not configuration_helpers.get_value('ENABLE_COMBINED_LOGIN_REGISTRATION', True): if initial_mode == "login": return old_login_view(request) elif initial_mode == "register": return old_register_view(request) # Account activation message account_activation_messages = [ { 'message': message.message, 'tags': message.tags } for message in messages.get_messages(request) if 'account-activation' in message.tags ] account_recovery_messages = [ { 'message': message.message, 'tags': message.tags } for message in messages.get_messages(request) if 'account-recovery' in message.tags ] # Otherwise, render the combined login/registration page context = { 'data': { 'login_redirect_url': redirect_to, 'initial_mode': initial_mode, 'third_party_auth': _third_party_auth_context(request, redirect_to, third_party_auth_hint), 'third_party_auth_hint': third_party_auth_hint or '', 'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME), 'support_link': configuration_helpers.get_value('SUPPORT_SITE_LINK', settings.SUPPORT_SITE_LINK), 'password_reset_support_link': configuration_helpers.get_value( 'PASSWORD_RESET_SUPPORT_LINK', settings.PASSWORD_RESET_SUPPORT_LINK ) or settings.SUPPORT_SITE_LINK, 'account_activation_messages': account_activation_messages, 'account_recovery_messages': account_recovery_messages, # Include form descriptions retrieved from the user API. # We could have the JS client make these requests directly, # but we include them in the initial page load to avoid # the additional round-trip to the server. 'login_form_desc': json.loads(form_descriptions['login']), 'registration_form_desc': json.loads(form_descriptions['registration']), 'password_reset_form_desc': json.loads(form_descriptions['password_reset']), 'account_creation_allowed': configuration_helpers.get_value( 'ALLOW_PUBLIC_ACCOUNT_CREATION', settings.FEATURES.get('ALLOW_PUBLIC_ACCOUNT_CREATION', True)), 'is_account_recovery_feature_enabled': is_secondary_email_feature_enabled() }, 'login_redirect_url': redirect_to, # This gets added to the query string of the "Sign In" button in header 'responsive': True, 'allow_iframing': True, 'disable_courseware_js': True, 'combined_login_and_register': True, 'disable_footer': not configuration_helpers.get_value( 'ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER', settings.FEATURES['ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER'] ), } enterprise_customer = enterprise_customer_for_request(request) update_logistration_context_for_enterprise(request, context, enterprise_customer) response = render_to_response('student_account/login_and_register.html', context) handle_enterprise_cookies_for_logistration(request, response, context) return response
def login_and_registration_form(request, initial_mode="login"): """Render the combined login/registration form, defaulting to login This relies on the JS to asynchronously load the actual form from the user_api. Keyword Args: initial_mode (string): Either "login" or "register". """ # Determine the URL to redirect to following login/registration/third_party_auth redirect_to = get_next_url_for_login_page(request) # If we're already logged in, redirect to the dashboard if request.user.is_authenticated(): return redirect(redirect_to) # Retrieve the form descriptions from the user API form_descriptions = _get_form_descriptions(request) # Our ?next= URL may itself contain a parameter 'tpa_hint=x' that we need to check. # If present, we display a login page focused on third-party auth with that provider. third_party_auth_hint = None if '?' in redirect_to: try: next_args = urlparse.parse_qs(urlparse.urlparse(redirect_to).query) provider_id = next_args['tpa_hint'][0] tpa_hint_provider = third_party_auth.provider.Registry.get( provider_id=provider_id) if tpa_hint_provider: if tpa_hint_provider.skip_hinted_login_dialog: # Forward the user directly to the provider's login URL when the provider is configured # to skip the dialog. return redirect( pipeline.get_login_url(provider_id, pipeline.AUTH_ENTRY_LOGIN, redirect_url=redirect_to)) third_party_auth_hint = provider_id initial_mode = "hinted_login" except (KeyError, ValueError, IndexError): pass # If this is a themed site, revert to the old login/registration pages. # We need to do this for now to support existing themes. # Themed sites can use the new logistration page by setting # 'ENABLE_COMBINED_LOGIN_REGISTRATION' in their # configuration settings. if is_request_in_themed_site() and not configuration_helpers.get_value( 'ENABLE_COMBINED_LOGIN_REGISTRATION', False): if initial_mode == "login": return old_login_view(request) elif initial_mode == "register": return old_register_view(request) # Allow external auth to intercept and handle the request ext_auth_response = _external_auth_intercept(request, initial_mode) if ext_auth_response is not None: return ext_auth_response # Account activation message account_activation_messages = [{ 'message': message.message, 'tags': message.tags } for message in messages.get_messages(request) if 'account-activation' in message.tags] # Otherwise, render the combined login/registration page context = { 'data': { 'login_redirect_url': redirect_to, 'initial_mode': initial_mode, 'third_party_auth': _third_party_auth_context(request, redirect_to, third_party_auth_hint), 'third_party_auth_hint': third_party_auth_hint or '', 'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME), 'support_link': configuration_helpers.get_value('SUPPORT_SITE_LINK', settings.SUPPORT_SITE_LINK), 'password_reset_support_link': configuration_helpers.get_value( 'PASSWORD_RESET_SUPPORT_LINK', settings.PASSWORD_RESET_SUPPORT_LINK) or settings.SUPPORT_SITE_LINK, 'account_activation_messages': account_activation_messages, # Include form descriptions retrieved from the user API. # We could have the JS client make these requests directly, # but we include them in the initial page load to avoid # the additional round-trip to the server. 'login_form_desc': json.loads(form_descriptions['login']), 'registration_form_desc': json.loads(form_descriptions['registration']), 'password_reset_form_desc': json.loads(form_descriptions['password_reset']), 'account_creation_allowed': configuration_helpers.get_value( 'ALLOW_PUBLIC_ACCOUNT_CREATION', settings.FEATURES.get('ALLOW_PUBLIC_ACCOUNT_CREATION', True)) }, 'login_redirect_url': redirect_to, # This gets added to the query string of the "Sign In" button in header 'responsive': True, 'allow_iframing': True, 'disable_courseware_js': True, 'combined_login_and_register': True, 'disable_footer': not configuration_helpers.get_value( 'ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER', settings.FEATURES['ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER']), } context = update_context_for_enterprise(request, context) response = render_to_response('student_account/login_and_register.html', context) # Remove enterprise cookie so that subsequent requests show default login page. response.delete_cookie( configuration_helpers.get_value( "ENTERPRISE_CUSTOMER_COOKIE_NAME", settings.ENTERPRISE_CUSTOMER_COOKIE_NAME), domain=configuration_helpers.get_value("BASE_COOKIE_DOMAIN", settings.BASE_COOKIE_DOMAIN), ) return response
def _cert_info(user, course_overview, cert_status): """ Implements the logic for cert_info -- split out for testing. Arguments: user (User): A user. course_overview (CourseOverview): A course. """ # simplify the status for the template using this lookup table template_state = { CertificateStatuses.generating: 'generating', CertificateStatuses.downloadable: 'downloadable', CertificateStatuses.notpassing: 'notpassing', CertificateStatuses.restricted: 'restricted', CertificateStatuses.auditing: 'auditing', CertificateStatuses.audit_passing: 'auditing', CertificateStatuses.audit_notpassing: 'auditing', CertificateStatuses.unverified: 'unverified', } certificate_earned_but_not_available_status = 'certificate_earned_but_not_available' default_status = 'processing' default_info = { 'status': default_status, 'show_survey_button': False, 'can_unenroll': True, } if cert_status is None: return default_info status = template_state.get(cert_status['status'], default_status) is_hidden_status = status in ('unavailable', 'processing', 'generating', 'notpassing', 'auditing') if ( not certificates_viewable_for_course(course_overview) and (status in CertificateStatuses.PASSED_STATUSES) and course_overview.certificate_available_date ): status = certificate_earned_but_not_available_status if ( course_overview.certificates_display_behavior == 'early_no_info' and is_hidden_status ): return default_info status_dict = { 'status': status, 'mode': cert_status.get('mode', None), 'linked_in_url': None, 'can_unenroll': status not in DISABLE_UNENROLL_CERT_STATES, } if status != default_status and course_overview.end_of_course_survey_url is not None: status_dict.update({ 'show_survey_button': True, 'survey_url': process_survey_link(course_overview.end_of_course_survey_url, user)}) else: status_dict['show_survey_button'] = False if status == 'downloadable': # showing the certificate web view button if certificate is downloadable state and feature flags are enabled. if has_html_certificates_enabled(course_overview): if course_overview.has_any_active_web_certificate: status_dict.update({ 'show_cert_web_view': True, 'cert_web_view_url': get_certificate_url(course_id=course_overview.id, uuid=cert_status['uuid']) }) else: # don't show download certificate button if we don't have an active certificate for course status_dict['status'] = 'unavailable' elif 'download_url' not in cert_status: log.warning( u"User %s has a downloadable cert for %s, but no download url", user.username, course_overview.id ) return default_info else: status_dict['download_url'] = cert_status['download_url'] # If enabled, show the LinkedIn "add to profile" button # Clicking this button sends the user to LinkedIn where they # can add the certificate information to their profile. linkedin_config = LinkedInAddToProfileConfiguration.current() # posting certificates to LinkedIn is not currently # supported in White Labels if linkedin_config.enabled and not theming_helpers.is_request_in_themed_site(): status_dict['linked_in_url'] = linkedin_config.add_to_profile_url( course_overview.id, course_overview.display_name, cert_status.get('mode'), cert_status['download_url'] ) if status in {'generating', 'downloadable', 'notpassing', 'restricted', 'auditing', 'unverified'}: cert_grade_percent = -1 persisted_grade_percent = -1 persisted_grade = CourseGradeFactory().read(user, course=course_overview, create_if_needed=False) if persisted_grade is not None: persisted_grade_percent = persisted_grade.percent if 'grade' in cert_status: cert_grade_percent = float(cert_status['grade']) if cert_grade_percent == -1 and persisted_grade_percent == -1: # Note: as of 11/20/2012, we know there are students in this state-- cs169.1x, # who need to be regraded (we weren't tracking 'notpassing' at first). # We can add a log.warning here once we think it shouldn't happen. return default_info grades_input = [cert_grade_percent, persisted_grade_percent] max_grade = None if all(grade is None for grade in grades_input) else max(filter(lambda x: x is not None, grades_input)) status_dict['grade'] = text_type(max_grade) return status_dict
def login_and_registration_form(request, initial_mode="login"): """Render the combined login/registration form, defaulting to login This relies on the JS to asynchronously load the actual form from the user_api. Keyword Args: initial_mode (string): Either "login" or "register". """ # Determine the URL to redirect to following login/registration/third_party_auth redirect_to = get_next_url_for_login_page(request) # If we're already logged in, redirect to the dashboard if request.user.is_authenticated: return redirect(redirect_to) # Retrieve the form descriptions from the user API form_descriptions = _get_form_descriptions(request) # Our ?next= URL may itself contain a parameter 'tpa_hint=x' that we need to check. # If present, we display a login page focused on third-party auth with that provider. third_party_auth_hint = None if '?' in redirect_to: try: next_args = urlparse.parse_qs(urlparse.urlparse(redirect_to).query) provider_id = next_args['tpa_hint'][0] tpa_hint_provider = third_party_auth.provider.Registry.get(provider_id=provider_id) if tpa_hint_provider: if tpa_hint_provider.skip_hinted_login_dialog: # Forward the user directly to the provider's login URL when the provider is configured # to skip the dialog. if initial_mode == "register": auth_entry = pipeline.AUTH_ENTRY_REGISTER else: auth_entry = pipeline.AUTH_ENTRY_LOGIN return redirect( pipeline.get_login_url(provider_id, auth_entry, redirect_url=redirect_to) ) third_party_auth_hint = provider_id initial_mode = "hinted_login" except (KeyError, ValueError, IndexError) as ex: log.error("Unknown tpa_hint provider: %s", ex) # If this is a themed site, revert to the old login/registration pages. # We need to do this for now to support existing themes. # Themed sites can use the new logistration page by setting # 'ENABLE_COMBINED_LOGIN_REGISTRATION' in their # configuration settings. if is_request_in_themed_site() and not configuration_helpers.get_value('ENABLE_COMBINED_LOGIN_REGISTRATION', False): if initial_mode == "login": return old_login_view(request) elif initial_mode == "register": return old_register_view(request) # Allow external auth to intercept and handle the request ext_auth_response = _external_auth_intercept(request, initial_mode) if ext_auth_response is not None: return ext_auth_response # Account activation message account_activation_messages = [ { 'message': message.message, 'tags': message.tags } for message in messages.get_messages(request) if 'account-activation' in message.tags ] # Otherwise, render the combined login/registration page context = { 'data': { 'login_redirect_url': redirect_to, 'initial_mode': initial_mode, 'third_party_auth': _third_party_auth_context(request, redirect_to, third_party_auth_hint), 'third_party_auth_hint': third_party_auth_hint or '', 'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME), 'support_link': configuration_helpers.get_value('SUPPORT_SITE_LINK', settings.SUPPORT_SITE_LINK), 'password_reset_support_link': configuration_helpers.get_value( 'PASSWORD_RESET_SUPPORT_LINK', settings.PASSWORD_RESET_SUPPORT_LINK ) or settings.SUPPORT_SITE_LINK, 'account_activation_messages': account_activation_messages, # Include form descriptions retrieved from the user API. # We could have the JS client make these requests directly, # but we include them in the initial page load to avoid # the additional round-trip to the server. 'login_form_desc': json.loads(form_descriptions['login']), 'registration_form_desc': json.loads(form_descriptions['registration']), 'password_reset_form_desc': json.loads(form_descriptions['password_reset']), 'account_creation_allowed': configuration_helpers.get_value( 'ALLOW_PUBLIC_ACCOUNT_CREATION', settings.FEATURES.get('ALLOW_PUBLIC_ACCOUNT_CREATION', True)) }, 'login_redirect_url': redirect_to, # This gets added to the query string of the "Sign In" button in header 'responsive': True, 'allow_iframing': True, 'disable_courseware_js': True, 'combined_login_and_register': True, 'disable_footer': not configuration_helpers.get_value( 'ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER', settings.FEATURES['ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER'] ), } enterprise_customer = enterprise_customer_for_request(request) update_logistration_context_for_enterprise(request, context, enterprise_customer) response = render_to_response('student_account/login_and_register.html', context) handle_enterprise_cookies_for_logistration(request, response, context) return response