def send_refund_notification(course_enrollment, refund_ids): """ Issue an email notification to the configured email recipient about a newly-initiated refund request. This function does not do any exception handling; callers are responsible for capturing and recovering from any errors. """ if microsite.is_request_in_microsite(): # this is not presently supported with the external service. raise NotImplementedError("Unable to send refund processing emails to microsite teams.") for_user = course_enrollment.user subject = _("[Refund] User-Requested Refund") message = _( "A refund request has been initiated for {username} ({email}). To process this request, please visit the link(s) below." # pylint: disable=line-too-long ).format(username=for_user.username, email=for_user.email) # TODO: this manipulation of API url is temporary, pending the introduction # of separate configuration items for the service's base url and api path. ecommerce_url = '://'.join(urlparse(settings.ECOMMERCE_API_URL)[:2]) refund_urls = ["{}/dashboard/refunds/{}/".format(ecommerce_url, refund_id) for refund_id in refund_ids] text_body = '\r\n'.join([message] + refund_urls + ['']) refund_links = ['<a href="{0}">{0}</a>'.format(url) for url in refund_urls] html_body = '<p>{}</p>'.format('<br>'.join([message] + refund_links)) email_message = EmailMultiAlternatives(subject, text_body, for_user.email, [settings.PAYMENT_SUPPORT_EMAIL]) email_message.attach_alternative(html_body, "text/html") email_message.send()
def get_template_path(relative_path, **kwargs): """ This is a proxy function to hide microsite_configuration behind comprehensive theming. """ if microsite.is_request_in_microsite(): relative_path = microsite.get_template_path(relative_path, **kwargs) return relative_path
def current(cls, *args): """ Get the current config model for the provider according to the enabled slugs for this site. The site configuration expects the value of THIRD_PARTY_AUTH_ENABLED_PROVIDERS to be a dict of backend_name and the slug being used for the configuration object. E.g. "THIRD_PARTY_AUTH_ENABLED_PROVIDERS":{ "google-oauth2":"my-slug-for-this-provider" } """ enabled_providers = microsite.get_value('THIRD_PARTY_AUTH_ENABLED_PROVIDERS', {}) # In a very specific case, azuread-oauth2 does not have a microsite context. if not microsite.is_request_in_microsite(): try: microsite.set_by_domain(get_current_request().site.domain) enabled_providers = microsite.get_value('THIRD_PARTY_AUTH_ENABLED_PROVIDERS', {}) microsite.clear() except Exception: # pylint: disable=broad-except pass if not enabled_providers: return super(OAuth2ProviderConfig, cls).current(*args) provider_slug = enabled_providers.get(args[0]) if provider_slug: return super(OAuth2ProviderConfig, cls).current(provider_slug) return super(OAuth2ProviderConfig, cls).current(None)
def send_refund_notification(course_enrollment, refund_ids): """ Issue an email notification to the configured email recipient about a newly-initiated refund request. This function does not do any exception handling; callers are responsible for capturing and recovering from any errors. """ if microsite.is_request_in_microsite(): # this is not presently supported with the external service. raise NotImplementedError("Unable to send refund processing emails to microsite teams.") for_user = course_enrollment.user subject = _("[Refund] User-Requested Refund") message = _( "A refund request has been initiated for {username} ({email}). " "To process this request, please visit the link(s) below." ).format(username=for_user.username, email=for_user.email) refund_urls = [ urljoin(settings.ECOMMERCE_PUBLIC_URL_ROOT, '/dashboard/refunds/{}/'.format(refund_id)) for refund_id in refund_ids ] text_body = '\r\n'.join([message] + refund_urls + ['']) refund_links = ['<a href="{0}">{0}</a>'.format(url) for url in refund_urls] html_body = '<p>{}</p>'.format('<br>'.join([message] + refund_links)) email_message = EmailMultiAlternatives(subject, text_body, for_user.email, [settings.PAYMENT_SUPPORT_EMAIL]) email_message.attach_alternative(html_body, "text/html") email_message.send()
def atp_check_certificate(request, course_id): log.info("atp_check_certificate start: " + str(datetime.datetime.now().strftime("%s"))) context = {} try: user = request.user username = user.username course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course = get_course_by_id(course_key) is_passed = CourseGradeFactory().create(user, course).passed if is_passed: certificate_url = '/api/atp/generate/certificate/' + course_id + '/' else: certificate_url = '' context['course_id'] = course_id context['username'] = username context['passed'] = is_passed context['certificate_url'] = certificate_url context['microsite'] = is_request_in_microsite() context['status'] = True except: context['status'] = False context['message'] = 'Error' log.info("atp_check_certificate end: " + str(datetime.datetime.now().strftime("%s"))) return JsonResponse(context)
def is_request_in_themed_site(): """ This is a proxy function to hide microsite_configuration behind comprehensive theming. """ # We need to give priority to theming/site-configuration over microsites return configuration_helpers.is_site_configuration_enabled( ) or microsite.is_request_in_microsite()
def send_refund_notification(course_enrollment, refund_ids): """ Issue an email notification to the configured email recipient about a newly-initiated refund request. This function does not do any exception handling; callers are responsible for capturing and recovering from any errors. """ if microsite.is_request_in_microsite(): # this is not presently supported with the external service. raise NotImplementedError( "Unable to send refund processing emails to microsite teams.") for_user = course_enrollment.user subject = _("[Refund] User-Requested Refund") message = _( "A refund request has been initiated for {username} ({email}). " "To process this request, please visit the link(s) below.").format( username=for_user.username, email=for_user.email) refund_urls = [ urljoin(settings.ECOMMERCE_PUBLIC_URL_ROOT, '/dashboard/refunds/{}/'.format(refund_id)) for refund_id in refund_ids ] text_body = '\r\n'.join([message] + refund_urls + ['']) refund_links = ['<a href="{0}">{0}</a>'.format(url) for url in refund_urls] html_body = '<p>{}</p>'.format('<br>'.join([message] + refund_links)) email_message = EmailMultiAlternatives(subject, text_body, for_user.email, [settings.PAYMENT_SUPPORT_EMAIL]) email_message.attach_alternative(html_body, "text/html") email_message.send()
def microsite_footer_context_processor(request): """ Checks the site name to determine whether to use the edX.org footer or the Open Source Footer. """ return dict( [ ("IS_REQUEST_IN_MICROSITE", microsite.is_request_in_microsite()) ] )
def get_template_path(relative_path, **kwargs): """ This is a proxy function to hide microsite_configuration behind comprehensive theming. """ # We need to give priority to theming over microsites # So, we apply microsite override only if there is no associated site theme # and associated microsite is present. if not current_request_has_associated_site_theme() and microsite.is_request_in_microsite(): relative_path = microsite.get_template_path(relative_path, **kwargs) return relative_path
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". """ # If we're already logged in, redirect to the dashboard if request.user.is_authenticated(): return redirect(reverse('dashboard')) # Retrieve the form descriptions from the user API form_descriptions = _get_form_descriptions(request) # If this is a microsite, revert to the old login/registration pages. # We need to do this for now to support existing themes. if microsite.is_request_in_microsite(): 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 = { 'disable_courseware_js': True, 'initial_mode': initial_mode, 'third_party_auth': json.dumps(_third_party_auth_context(request)), 'platform_name': settings.PLATFORM_NAME, 'responsive': True, # 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': form_descriptions['login'], 'registration_form_desc': form_descriptions['registration'], 'password_reset_form_desc': form_descriptions['password_reset'], # We need to pass these parameters so that the header's # "Sign In" button preserves the querystring params. 'enrollment_action': request.GET.get('enrollment_action'), 'course_id': request.GET.get('course_id'), 'course_mode': request.GET.get('course_mode'), } return render_to_response('student_account/login_and_register.html', context)
def _update_social_context(request, context, course, user, user_certificate, platform_name): """ Updates context dictionary with info required for social sharing. """ share_settings = getattr(settings, 'SOCIAL_SHARING_SETTINGS', {}) context['facebook_share_enabled'] = share_settings.get('CERTIFICATE_FACEBOOK', False) context['facebook_app_id'] = getattr(settings, "FACEBOOK_APP_ID", None) context['facebook_share_text'] = share_settings.get( 'CERTIFICATE_FACEBOOK_TEXT', _("I completed the {course_title} course on {platform_name}.").format( course_title=context['accomplishment_copy_course_name'], platform_name=platform_name ) ) context['twitter_share_enabled'] = share_settings.get('CERTIFICATE_TWITTER', False) context['twitter_share_text'] = share_settings.get( 'CERTIFICATE_TWITTER_TEXT', _("I completed a course on {platform_name}. Take a look at my certificate.").format( platform_name=platform_name ) ) share_url = request.build_absolute_uri( reverse( 'certificates:html_view', kwargs=dict(user_id=str(user.id), course_id=unicode(course.id)) ) ) context['share_url'] = share_url twitter_url = '' if context.get('twitter_share_enabled', False): twitter_url = 'https://twitter.com/intent/tweet?text={twitter_share_text}&url={share_url}'.format( twitter_share_text=smart_str(context['twitter_share_text']), share_url=urllib.quote_plus(smart_str(share_url)) ) context['twitter_url'] = twitter_url context['linked_in_url'] = None # 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 microsites/White Labels if linkedin_config.enabled and not microsite.is_request_in_microsite(): context['linked_in_url'] = linkedin_config.add_to_profile_url( course.id, course.display_name, user_certificate.mode, smart_str(request.build_absolute_uri(get_certificate_url( user_id=user.id, course_id=unicode(course.id) ))) )
def send_refund_notification(course_enrollment, refund_ids): """ Notify the support team of the refund request. """ tags = ['auto_refund'] if microsite.is_request_in_microsite(): # this is not presently supported with the external service. raise NotImplementedError("Unable to send refund processing emails to microsite 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(course_enrollment, refund_ids): """ Notify the support team of the refund request. """ tags = ["auto_refund"] if microsite.is_request_in_microsite(): # this is not presently supported with the external service. raise NotImplementedError("Unable to send refund processing emails to microsite 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 is_comprehensive_theming_enabled(): """ Returns boolean indicating whether comprehensive theming functionality is enabled or disabled. Example: >> is_comprehensive_theming_enabled() True Returns: (bool): True if comprehensive theming is enabled else False """ # Disable theming for microsites if microsite.is_request_in_microsite(): return False return settings.ENABLE_COMPREHENSIVE_THEMING
def _update_social_context(request, context, course, user, user_certificate, platform_name): """ Updates context dictionary with info required for social sharing. """ share_settings = getattr(settings, 'SOCIAL_SHARING_SETTINGS', {}) context['facebook_share_enabled'] = share_settings.get( 'CERTIFICATE_FACEBOOK', False) context['facebook_app_id'] = getattr(settings, "FACEBOOK_APP_ID", None) context['facebook_share_text'] = share_settings.get( 'CERTIFICATE_FACEBOOK_TEXT', _("I completed the {course_title} course on {platform_name}.").format( course_title=context['accomplishment_copy_course_name'], platform_name=platform_name)) context['twitter_share_enabled'] = share_settings.get( 'CERTIFICATE_TWITTER', False) context['twitter_share_text'] = share_settings.get( 'CERTIFICATE_TWITTER_TEXT', _("I completed a course on {platform_name}. Take a look at my certificate." ).format(platform_name=platform_name)) share_url = request.build_absolute_uri( reverse('certificates:html_view', kwargs=dict(user_id=str(user.id), course_id=unicode(course.id)))) context['share_url'] = share_url twitter_url = '' if context.get('twitter_share_enabled', False): twitter_url = 'https://twitter.com/intent/tweet?text={twitter_share_text}&url={share_url}'.format( twitter_share_text=smart_str(context['twitter_share_text']), share_url=urllib.quote_plus(smart_str(share_url))) context['twitter_url'] = twitter_url context['linked_in_url'] = None # 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 microsites/White Labels if linkedin_config.enabled and not microsite.is_request_in_microsite(): context['linked_in_url'] = linkedin_config.add_to_profile_url( course.id, course.display_name, user_certificate.mode, smart_str( request.build_absolute_uri( get_certificate_url(user_id=user.id, course_id=unicode(course.id)))))
def get_themed_template_path(relative_path, default_path, **kwargs): """ This is a proxy function to hide microsite_configuration behind comprehensive theming. The workflow considers the "Stanford theming" feature alongside of microsites. It returns the path of the themed template (i.e. relative_path) if Stanford theming is enabled AND microsite theming is disabled, otherwise it will return the path of either the microsite override template or the base lms template. :param relative_path: relative path of themed template :param default_path: relative path of the microsite's or lms template to use if theming is disabled or microsite is enabled """ is_stanford_theming_enabled = settings.FEATURES.get("USE_CUSTOM_THEME", False) is_microsite = microsite.is_request_in_microsite() if is_stanford_theming_enabled and not is_microsite: return relative_path return microsite.get_template_path(default_path, **kwargs)
def is_comprehensive_theming_enabled(): """ Returns boolean indicating whether comprehensive theming functionality is enabled or disabled. Example: >> is_comprehensive_theming_enabled() True Returns: (bool): True if comprehensive theming is enabled else False """ # We need to give priority to theming over microsites if settings.ENABLE_COMPREHENSIVE_THEMING and current_request_has_associated_site_theme(): return True # Disable theming for microsites # Microsite configurations take priority over the default site theme. if microsite.is_request_in_microsite(): return False return settings.ENABLE_COMPREHENSIVE_THEMING
def is_request_in_themed_site(): """ This is a proxy function to hide microsite_configuration behind comprehensive theming. """ return microsite.is_request_in_microsite()
def test_is_request_in_microsite(self): """ Tests microsite.is_request_in_microsite works as expected. """ microsite.set_by_domain(self.microsite_subdomain) self.assertTrue(microsite.is_request_in_microsite())
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) if settings.FEATURES.get("ENABLE_EDRAAK_LOGISTRATION", False): redirect_to = get_next_url_for_progs_login_page(request, initial_mode) return redirect(redirect_to) # Retrieve the form descriptions from the user API form_descriptions = _get_form_descriptions(request) # If this is a microsite, revert to the old login/registration pages. # We need to do this for now to support existing themes. # Microsites can use the new logistration page by setting # 'ENABLE_COMBINED_LOGIN_REGISTRATION' in their microsites configuration file. if microsite.is_request_in_microsite() and not microsite.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': 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, } # Edraak: Check if the origin is a safe (trusted) url. if so pass it # to the front end to allow navigating back to the originating # site after authentication. origin_url = request.GET.get('origin') if origin_url and is_origin_url_allowed(origin_url): context['data']['origin'] = origin_url return render_to_response('student_account/login_and_register.html', context)
def render_html_view(request, user_id, course_id): """ This public view generates an HTML representation of the specified student's certificate If a certificate is not available, we display a "Sorry!" screen instead """ # Create the initial view context, bootstrapping with Django settings and passed-in values context = {} context['platform_name'] = microsite.get_value("platform_name", settings.PLATFORM_NAME) context['course_id'] = course_id preview_mode = request.GET.get('preview', None) # Update the view context with the default ConfigurationModel settings configuration = CertificateHtmlViewConfiguration.get_config() # if we are in a microsite, then let's first see if there is an override # section in our config config_key = microsite.get_value('microsite_config_key', 'default') # if there is no special microsite override, then let's use default if config_key not in configuration: config_key = 'default' context.update(configuration.get(config_key, {})) # Translators: 'All rights reserved' is a legal term used in copyrighting to protect published content reserved = _("All rights reserved") context['copyright_text'] = '© {year} {platform_name}. {reserved}.'.format( year=settings.COPYRIGHT_YEAR, platform_name=context.get('platform_name'), reserved=reserved ) # Translators: This text is bound to the HTML 'title' element of the page and appears # in the browser title bar when a requested certificate is not found or recognized context['document_title'] = _("Invalid Certificate") # Translators: The & characters represent an ampersand character and can be ignored context['company_tos_urltext'] = _("Terms of Service & Honor Code") # Translators: A 'Privacy Policy' is a legal document/statement describing a website's use of personal information context['company_privacy_urltext'] = _("Privacy Policy") # Translators: This line appears as a byline to a header image and describes the purpose of the page context['logo_subtitle'] = _("Certificate Validation") invalid_template_path = 'certificates/invalid.html' # Kick the user back to the "Invalid" screen if the feature is disabled if not has_html_certificates_enabled(course_id): return render_to_response(invalid_template_path, context) # Load the core building blocks for the view context try: course_key = CourseKey.from_string(course_id) user = User.objects.get(id=user_id) course = modulestore().get_course(course_key) if not course: raise CourseDoesNotExist # Attempt to load the user's generated certificate data if preview_mode: user_certificate = GeneratedCertificate.objects.get( user=user, course_id=course_key, mode=preview_mode ) else: user_certificate = GeneratedCertificate.objects.get( user=user, course_id=course_key ) # If there's no generated certificate data for this user, we need to see if we're in 'preview' mode... # If we are, we'll need to create a mock version of the user_certificate container for previewing except GeneratedCertificate.DoesNotExist: if preview_mode and ( has_access(request.user, 'instructor', course) or has_access(request.user, 'staff', course) ): user_certificate = GeneratedCertificate( mode=preview_mode, verify_uuid=unicode(uuid4().hex), modified_date=datetime.now().date() ) else: return render_to_response(invalid_template_path, context) # For any other expected exceptions, kick the user back to the "Invalid" screen except (InvalidKeyError, CourseDoesNotExist, User.DoesNotExist): return render_to_response(invalid_template_path, context) # Badge Request Event Tracking Logic if 'evidence_visit' in request.GET: try: badge = BadgeAssertion.objects.get(user=user, course_id=course_key) tracker.emit( 'edx.badge.assertion.evidence_visited', { 'user_id': user.id, 'course_id': unicode(course_key), 'enrollment_mode': badge.mode, 'assertion_id': badge.id, 'assertion_image_url': badge.data['image'], 'assertion_json_url': badge.data['json']['id'], 'issuer': badge.data['issuer'], } ) except BadgeAssertion.DoesNotExist: log.warn( "Could not find badge for %s on course %s.", user.id, course_key, ) # Okay, now we have all of the pieces, time to put everything together # Get the active certificate configuration for this course # If we do not have an active certificate, we'll need to send the user to the "Invalid" screen # Passing in the 'preview' parameter, if specified, will return a configuration, if defined active_configuration = get_active_web_certificate(course, preview_mode) if active_configuration is None: return render_to_response(invalid_template_path, context) else: context['certificate_data'] = active_configuration # Append/Override the existing view context values with any mode-specific ConfigurationModel values context.update(configuration.get(user_certificate.mode, {})) # Append/Override the existing view context values with request-time values _update_certificate_context(context, course, user, user_certificate) share_url = request.build_absolute_uri( reverse( 'certificates:html_view', kwargs=dict(user_id=str(user_id), course_id=unicode(course_id)) ) ) context['share_url'] = share_url twitter_url = '' if context.get('twitter_share_enabled', False): twitter_url = 'https://twitter.com/intent/tweet?text={twitter_share_text}&url={share_url}'.format( twitter_share_text=smart_str(context['twitter_share_text']), share_url=urllib.quote_plus(smart_str(share_url)) ) context['twitter_url'] = twitter_url context['full_course_image_url'] = request.build_absolute_uri(course_image_url(course)) # 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 microsites/White Labels if linkedin_config.enabled and not microsite.is_request_in_microsite(): context['linked_in_url'] = linkedin_config.add_to_profile_url( course.id, course.display_name, user_certificate.mode, smart_str(request.build_absolute_uri(get_certificate_url( user_id=user.id, course_id=unicode(course.id) ))) ) else: context['linked_in_url'] = None # Microsites will need to be able to override any hard coded # content that was put into the context in the # _update_certificate_context() call above. For example the # 'company_about_description' talks about edX, which we most likely # do not want to keep in a microsite # # So we need to re-apply any configuration/content that # we are sourceing from the database. This is somewhat duplicative of # the code at the beginning of this method, but we # need the configuration at the top as some error code paths # require that to be set up early on in the pipeline # microsite_config_key = microsite.get_value('microsite_config_key') if microsite_config_key: context.update(configuration.get(microsite_config_key, {})) # track certificate evidence_visited event for analytics when certificate_user and accessing_user are different if request.user and request.user.id != user.id: emit_certificate_event('evidence_visited', user, course_id, course, { 'certificate_id': user_certificate.verify_uuid, 'enrollment_mode': user_certificate.mode, 'social_network': CertificateSocialNetworks.linkedin }) # Append/Override the existing view context values with any course-specific static values from Advanced Settings context.update(course.cert_html_view_overrides) # FINALLY, generate and send the output the client if settings.FEATURES.get('CUSTOM_CERTIFICATE_TEMPLATES_ENABLED', False): custom_template = get_certificate_template(course_key, user_certificate.mode) if custom_template: template = Template( custom_template, output_encoding='utf-8', input_encoding='utf-8', default_filters=['decode.utf8'], encoding_errors='replace', ) context = RequestContext(request, context) return HttpResponse(template.render(context)) return render_to_response("certificates/valid.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 microsite, revert to the old login/registration pages. # We need to do this for now to support existing themes. # Microsites can use the new logistration page by setting # 'ENABLE_COMBINED_LOGIN_REGISTRATION' in their microsites configuration file. if microsite.is_request_in_microsite() and not microsite.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 = { 'login_redirect_url': redirect_to, # This gets added to the query string of the "Sign In" button in the header 'disable_courseware_js': True, 'initial_mode': initial_mode, 'third_party_auth': json.dumps(_third_party_auth_context(request, redirect_to)), 'third_party_auth_hint': third_party_auth_hint or '', 'platform_name': settings.PLATFORM_NAME, 'responsive': True, # 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': form_descriptions['login'], 'registration_form_desc': form_descriptions['registration'], 'password_reset_form_desc': form_descriptions['password_reset'], } return render_to_response('student_account/login_and_register.html', context)
def open_source_footer_context_processor(request): """ Checks the site name to determine whether to use the edX.org footer or the Open Source Footer. """ return dict( [ ("IS_EDX_DOMAIN", settings.FEATURES.get('IS_EDX_DOMAIN', False)), ("ENABLE_CUSTOM_THEME", settings.FEATURES.get("USE_CUSTOM_THEME", False) and not microsite.is_request_in_microsite()) ] )
def is_request_in_themed_site(): """ This is a proxy function to hide microsite_configuration behind comprehensive theming. """ # We need to give priority to theming/site-configuration over microsites return configuration_helpers.is_site_configuration_enabled() or microsite.is_request_in_microsite()
def student_view(self, context=None, authoring=False): scheme = 'https' if settings.HTTPS == 'on' else 'http' lms_base = settings.ENV_TOKENS.get('LMS_BASE') if isinstance(context, QueryDict): context = context.dict() if microsite.is_request_in_microsite(): subdomain = microsite.get_value( "domain_prefix", None) or microsite.get_value('microsite_config_key') lms_base = "{}.{}".format(subdomain, lms_base) scorm_player_url = "" course_directory = self.scorm_file if self.scorm_player == 'SCORM_PKG_INTERNAL': # TODO: support initial filename other than index.html for internal players #scorm_player_url = '{}://{}{}'.format(scheme, lms_base, self.scorm_file) scorm_player_url = '{}{}'.format(self.scorm_file, '/index.html') elif self.scorm_player: player_config = DEFINED_PLAYERS[self.scorm_player] player = player_config['location'] if '://' in player: scorm_player_url = player else: scorm_player_url = '{}://{}{}'.format(scheme, lms_base, player) course_directory = '{}://{}{}'.format( scheme, lms_base, self.runtime.handler_url(self, "proxy_content")) html = self.resource_string("static/html/scormxblock.html") # don't call handlers if student_view is not called from within LMS # (not really a student) if not authoring: get_url = '{}://{}{}'.format( scheme, lms_base, self.runtime.handler_url(self, "get_raw_scorm_status")) set_url = '{}://{}{}'.format( scheme, lms_base, self.runtime.handler_url(self, "set_raw_scorm_status")) # PreviewModuleSystem (runtime Mixin from Studio) won't have a hostname else: # we don't want to get/set SCORM status from preview get_url = set_url = '#' # if display type is popup, don't use the full window width for the host iframe iframe_width = self.display_type == 'popup' and DEFAULT_IFRAME_WIDTH or self.display_width iframe_height = self.display_type == 'popup' and DEFAULT_IFRAME_HEIGHT or self.display_height try: player_config = json.loads(self.player_configuration) except ValueError: player_config = {} frag = Fragment() frag.add_content( MakoTemplate(text=html.format( self=self, scorm_player_url=scorm_player_url, get_url=get_url, set_url=set_url, iframe_width=iframe_width, iframe_height=iframe_height, player_config=player_config, scorm_file=course_directory)).render_unicode()) frag.add_css(self.resource_string("static/css/scormxblock.css")) context['block_id'] = self.url_name js = self.resource_string("static/js/src/scormxblock.js") jsfrag = MakoTemplate(js).render_unicode(**context) frag.add_javascript(jsfrag) # TODO: this will only work to display staff debug info if 'scormxblock' is one of the # categories of blocks that are specified in lms/templates/staff_problem_info.html so this will # for now have to be overridden in theme or directly in edx-platform # TODO: is there another way to approach this? key's location.category isn't mutable to spoof 'problem', # like setting the name in the entry point to 'problem'. Doesn't seem like a good idea. Better to # have 'staff debuggable' categories configurable in settings or have an XBlock declare itself staff debuggable if SCORM_DISPLAY_STAFF_DEBUG_INFO and not authoring: # don't show for author preview from courseware.access import has_access from courseware.courses import get_course_by_id course = get_course_by_id(self.xmodule_runtime.course_id) dj_user = self.xmodule_runtime._services['user']._django_user has_instructor_access = bool( has_access(dj_user, 'instructor', course)) if has_instructor_access: disable_staff_debug_info = settings.FEATURES.get( 'DISPLAY_DEBUG_INFO_TO_STAFF', True) and False or True block = self view = 'student_view' frag = add_staff_markup(dj_user, has_instructor_access, disable_staff_debug_info, block, view, frag, context) frag.initialize_js('ScormXBlock_{0}'.format(context['block_id'])) return frag
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 microsite, revert to the old login/registration pages. # We need to do this for now to support existing themes. if microsite.is_request_in_microsite(): 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 = { 'login_redirect_url': redirect_to, # This gets added to the query string of the "Sign In" button in the header 'disable_courseware_js': True, 'initial_mode': initial_mode, 'third_party_auth': json.dumps(_third_party_auth_context(request, redirect_to)), 'third_party_auth_hint': third_party_auth_hint or '', 'platform_name': settings.PLATFORM_NAME, 'responsive': True, # 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': form_descriptions['login'], 'registration_form_desc': form_descriptions['registration'], 'password_reset_form_desc': form_descriptions['password_reset'], } return render_to_response('student_account/login_and_register.html', context)