예제 #1
0
 def _certificate_html_view_configuration(self, configuration_string, enabled=True):
     """
     This will create a certificate html configuration
     """
     config = CertificateHtmlViewConfiguration(enabled=enabled, configuration=configuration_string)
     config.save()
     return config
예제 #2
0
 def _certificate_html_view_configuration(self, configuration_string, enabled=True):
     """
     This will create a certificate html configuration
     """
     config = CertificateHtmlViewConfiguration(enabled=enabled, configuration=configuration_string)
     config.save()
     return config
예제 #3
0
 def test_clean_bad_json(self):
     """
     Tests if bad JSON string was given.
     """
     self.config = CertificateHtmlViewConfiguration(
         configuration='{"bad":"test"')
     self.assertRaises(ValidationError, self.config.clean)
예제 #4
0
 def setUp(self):
     super(CertificateHtmlViewConfigurationTest, self).setUp()
     self.configuration_string = """{
         "default": {
             "url": "http://www.edx.org",
             "logo_src": "http://www.edx.org/static/images/logo.png"
         },
         "honor": {
             "logo_src": "http://www.edx.org/static/images/honor-logo.png"
         }
     }"""
     self.config = CertificateHtmlViewConfiguration(configuration=self.configuration_string)
예제 #5
0
    def test_certificate_without_branding_urls(self):
        """
        Test that links from CertificateHtmlViewConfiguration are used if
        corresponding microsite or marketing urls are not present.
        """
        self._add_course_certificates(count=1, signatory_count=1, is_active=True)

        self.course.save()
        self.store.update_item(self.course, self.user.id)
        configuration = CertificateHtmlViewConfiguration.get_config()

        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        response = self.client.get(test_url, HTTP_HOST=settings.MICROSITE_TEST_HOSTNAME)

        # ABOUT is not present in MICROSITE_CONFIGURATION['test_microsite']["urls"] or MKTG_URL_LINK_MAP,
        #  so web certificate will use CertificateHtmlViewConfiguration url.
        self.assertContains(
            response,
            configuration['microsites']['testmicrosite']['company_about_url'],
        )
        # PRIVACY is not present in MICROSITE_CONFIGURATION['test_microsite']["urls"] or MKTG_URL_LINK_MAP,
        # so web certificate will use CertificateHtmlViewConfiguration url.
        self.assertContains(
            response,
            configuration['microsites']['testmicrosite']['company_privacy_url'],
        )
        # TOS_AND_HONOR is not present in MICROSITE_CONFIGURATION['test_microsite']["urls"] or MKTG_URL_LINK_MAP,
        # so web certificate will use CertificateHtmlViewConfiguration url.
        self.assertContains(
            response,
            configuration['microsites']['testmicrosite']['company_tos_url'],
        )
예제 #6
0
 def setUp(self):
     super(CertificateHtmlViewConfigurationTest, self).setUp()
     self.configuration_string = """{
         "default": {
             "url": "http://www.edx.org",
             "logo_src": "http://www.edx.org/static/images/logo.png"
         },
         "honor": {
             "logo_src": "http://www.edx.org/static/images/honor-logo.png"
         }
     }"""
     self.config = CertificateHtmlViewConfiguration(configuration=self.configuration_string)
예제 #7
0
def render_html_view(request, user_id, course_id):
    """
    This public view generates an HTML representation of the specified user and course
    If a certificate is not available, we display a "Sorry!" screen instead
    """
    preview_mode = request.GET.get('preview', None)
    platform_name = microsite.get_value("platform_name", settings.PLATFORM_NAME)
    configuration = CertificateHtmlViewConfiguration.get_config()
    # Create the initial view context, bootstrapping with Django settings and passed-in values
    context = {}
    _update_context_with_basic_info(context, course_id, platform_name, configuration)
    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 course and user objects
    try:
        course_key = CourseKey.from_string(course_id)
        user = User.objects.get(id=user_id)
        course = modulestore().get_course(course_key)

    # For any other expected exceptions, kick the user back to the "Invalid" screen
    except (InvalidKeyError, ItemNotFoundError, User.DoesNotExist):
        return render_to_response(invalid_template_path, context)

    # Load user's certificate
    user_certificate = _get_user_certificate(request, user, course_key, course, preview_mode)
    if not user_certificate:
        return render_to_response(invalid_template_path, context)

    # 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)
    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 organization info
    _update_organization_context(context, course)

    # Append course info
    _update_course_context(request, context, course, platform_name)

    # Append user info
    _update_context_with_user_info(context, user, user_certificate)

    # Append social sharing info
    _update_social_context(request, context, course, user, user_certificate, platform_name)

    # Append/Override the existing view context values with certificate specific values
    _update_certificate_context(context, user_certificate, platform_name)

    # Append badge info
    _update_badge_context(context, course, user)

    # Append microsite overrides
    _update_microsite_context(context, configuration)

    # Add certificate header/footer data to current context
    context.update(get_certificate_header_context(is_secure=request.is_secure()))
    context.update(get_certificate_footer_context())

    # Append/Override the existing view context values with any course-specific static values from Advanced Settings
    context.update(course.cert_html_view_overrides)

    # Track certificate view events
    _track_certificate_events(request, context, course, user, user_certificate)

    # FINALLY, render appropriate certificate
    return _render_certificate_template(request, context, course, user_certificate)
예제 #8
0
def render_html_view(request):
    """
    This view generates an HTML representation of the specified student's certificate
    If a certificate is not available, we display a "Sorry!" screen instead
    """
    # Initialize the template context and bootstrap with default values from configuration
    context = {}
    configuration = CertificateHtmlViewConfiguration.get_config()
    context = configuration.get('default', {})

    invalid_template_path = 'certificates/invalid.html'

    # 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")

    # Feature Flag check
    if not settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False):
        return render_to_response(invalid_template_path, context)

    course_id = request.GET.get('course', None)
    context['course'] = course_id
    if not course_id:
        return render_to_response(invalid_template_path, context)

    # Course Lookup
    try:
        course_key = CourseKey.from_string(course_id)
    except InvalidKeyError:
        return render_to_response(invalid_template_path, context)
    course = modulestore().get_course(course_key)
    if not course:
        return render_to_response(invalid_template_path, context)

    # Certificate Lookup
    try:
        certificate = GeneratedCertificate.objects.get(
            user=request.user,
            course_id=course_key
        )
    except GeneratedCertificate.DoesNotExist:
        return render_to_response(invalid_template_path, context)

    # Override the defaults with any mode-specific static values
    context.update(configuration.get(certificate.mode, {}))
    # Override further with any course-specific static values
    context.update(course.cert_html_view_overrides)

    # Populate dynamic output values using the course/certificate data loaded above
    user_fullname = request.user.profile.name
    platform_name = context.get('platform_name')
    context['accomplishment_copy_name'] = user_fullname
    context['accomplishment_copy_course_org'] = course.org
    context['accomplishment_copy_course_name'] = course.display_name
    context['certificate_id_number'] = certificate.verify_uuid
    context['certificate_verify_url'] = "{prefix}{uuid}{suffix}".format(
        prefix=context.get('certificate_verify_url_prefix'),
        uuid=certificate.verify_uuid,
        suffix=context.get('certificate_verify_url_suffix')
    )
    context['logo_alt'] = platform_name

    accd_course_org_html = '<span class="detail--xuniversity">{partner_name}</span>'.format(partner_name=course.org)
    accd_platform_name_html = '<span class="detail--company">{platform_name}</span>'.format(platform_name=platform_name)
    # Translators: This line appears on the certificate after the name of a course, and provides more
    # information about the organizations providing the course material to platform users
    context['accomplishment_copy_course_description'] = _('a course of study offered by {partner_name}, '
                                                          'through {platform_name}.').format(
        partner_name=accd_course_org_html,
        platform_name=accd_platform_name_html
    )

    context['accomplishment_more_title'] = _("More Information About {user_name}'s Certificate:").format(
        user_name=user_fullname
    )

    # Translators:  This line appears on the page just before the generation date for the certificate
    context['certificate_date_issued_title'] = _("Issued On:")

    # Translators:  The format of the date includes the full name of the month
    context['certificate_date_issued'] = _('{month} {day}, {year}').format(
        month=certificate.modified_date.strftime("%B"),
        day=certificate.modified_date.day,
        year=certificate.modified_date.year
    )

    # Translators:  The Certificate ID Number is an alphanumeric value unique to each individual certificate
    context['certificate_id_number_title'] = _('Certificate ID Number')

    context['certificate_info_title'] = _('About {platform_name} Certificates').format(
        platform_name=platform_name
    )

    # Translators: This text describes the purpose (and therefore, value) of a course certificate
    # 'verifying your identity' refers to the process for establishing the authenticity of the student
    context['certificate_info_description'] = _("{platform_name} acknowledges achievements through certificates, which "
                                                "are awarded for various activities {platform_name} students complete "
                                                "under the <a href='{tos_url}'>{platform_name} Honor Code</a>.  Some "
                                                "certificates require completing additional steps, such as "
                                                "<a href='{verified_cert_url}'> verifying your identity</a>.").format(
        platform_name=platform_name,
        tos_url=context.get('company_tos_url'),
        verified_cert_url=context.get('company_verified_certificate_url')
    )

    # Translators:  Certificate Types correspond to the different enrollment options available for a given course
    context['certificate_type_title'] = _('{certificate_type} Certificate').format(
        certificate_type=context.get('certificate_type')
    )

    context['certificate_verify_title'] = _("How {platform_name} Validates Student Certificates").format(
        platform_name=platform_name
    )

    # Translators:  This text describes the validation mechanism for a certificate file (known as GPG security)
    context['certificate_verify_description'] = _('Certificates issued by {platform_name} are signed by a gpg key so '
                                                  'that they can be validated independently by anyone with the '
                                                  '{platform_name} public key. For independent verification, '
                                                  '{platform_name} uses what is called a '
                                                  '"detached signature"&quot;".').format(platform_name=platform_name)

    context['certificate_verify_urltext'] = _("Validate this certificate for yourself")

    # Translators:  This text describes (at a high level) the mission and charter the edX platform and organization
    context['company_about_description'] = _("{platform_name} offers interactive online classes and MOOCs from the "
                                             "world's best universities, including MIT, Harvard, Berkeley, University "
                                             "of Texas, and many others.  {platform_name} is a non-profit online "
                                             "initiative created by founding partners Harvard and MIT.").format(
        platform_name=platform_name
    )

    context['company_about_title'] = _("About {platform_name}").format(platform_name=platform_name)

    context['company_about_urltext'] = _("Learn more about {platform_name}").format(platform_name=platform_name)

    context['company_courselist_urltext'] = _("Learn with {platform_name}").format(platform_name=platform_name)

    context['company_careers_urltext'] = _("Work at {platform_name}").format(platform_name=platform_name)

    context['company_contact_urltext'] = _("Contact {platform_name}").format(platform_name=platform_name)

    context['company_privacy_urltext'] = _("Privacy Policy")

    context['company_tos_urltext'] = _("Terms of Service &amp; Honor Code")

    # Translators:  This text appears near the top of the certficate and describes the guarantee provided by edX
    context['document_banner'] = _("{platform_name} acknowledges the following student accomplishment").format(
        platform_name=platform_name
    )

    context['logo_subtitle'] = _("Certificate Validation")

    if certificate.mode == 'honor':
        # Translators:  This text describes the 'Honor' course certificate type.
        context['certificate_type_description'] = _("An {cert_type} Certificate signifies that an {platform_name} "
                                                    "learner has agreed to abide by {platform_name}'s honor code and "
                                                    "completed all of the required tasks for this course under its "
                                                    "guidelines.").format(
            cert_type=context.get('certificate_type'),
            platform_name=platform_name
        )
    elif certificate.mode == 'verified':
        # Translators:  This text describes the 'ID Verified' course certificate type, which is a higher level of
        # verification offered by edX.  This type of verification is useful for professional education/certifications
        context['certificate_type_description'] = _("An {cert_type} Certificate signifies that an {platform_name} "
                                                    "learner has agreed to abide by {platform_name}'s honor code and "
                                                    "completed all of the required tasks for this course under its "
                                                    "guidelines, as well as having their photo ID checked to verify "
                                                    "their identity.").format(
            cert_type=context.get('certificate_type'),
            platform_name=platform_name
        )
    elif certificate.mode == 'xseries':
        # Translators:  This text describes the 'XSeries' course certificate type.  An XSeries is a collection of
        # courses related to each other in a meaningful way, such as a specific topic or theme, or even an organization
        context['certificate_type_description'] = _("An {cert_type} Certificate demonstrates a high level of "
                                                    "achievement in a program of study, and includes verification of "
                                                    "the student's identity.").format(
            cert_type=context.get('certificate_type')
        )

    # Translators:  This is the copyright line which appears at the bottom of the certificate page/screen
    context['copyright_text'] = _('&copy; {year} {platform_name}. All rights reserved.').format(
        year=datetime.now().year,
        platform_name=platform_name
    )

    # Translators:  This text represents the verification of the certificate
    context['document_meta_description'] = _('This is a valid {platform_name} certificate for {user_name}, '
                                             'who participated in {partner_name} {course_number}').format(
        platform_name=platform_name,
        user_name=user_fullname,
        partner_name=course.org,
        course_number=course.number
    )

    # Translators:  This text is bound to the HTML 'title' element of the page and appears in the browser title bar
    context['document_title'] = _("Valid {partner_name} {course_number} Certificate | {platform_name}").format(
        partner_name=course.org,
        course_number=course.number,
        platform_name=platform_name
    )

    # Translators:  This text fragment appears after the student's name (displayed in a large font) on the certificate
    # screen.  The text describes the accomplishment represented by the certificate information displayed to the user
    context['accomplishment_copy_description_full'] = _("successfully completed, received a passing grade, and was "
                                                        "awarded a {platform_name} {certificate_type} "
                                                        "Certificate of Completion in ").format(
        platform_name=platform_name,
        certificate_type=context.get("certificate_type")
    )

    return render_to_response("certificates/valid.html", context)
예제 #9
0
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 view context and bootstrap with Django settings and passed-in values
    context = {}
    context['platform_name'] = settings.PLATFORM_NAME
    context['course_id'] = course_id

    # Update the view context with the default ConfigurationModel settings
    configuration = CertificateHtmlViewConfiguration.get_config()
    context.update(configuration.get('default', {}))

    # 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")
    invalid_template_path = 'certificates/invalid.html'

    # Kick the user back to the "Invalid" screen if the feature is disabled
    if not settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False):
        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
        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 request.GET.get('preview', None):
            user_certificate = GeneratedCertificate(
                mode=request.GET.get('preview'),
                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)

    # 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
    active_configuration = get_active_web_certificate(course, request.GET.get('preview'))
    if active_configuration is None and request.GET.get('preview') 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)

    # Append/Override the existing view context values with any course-specific static values from Advanced Settings
    context.update(course.cert_html_view_overrides)

    # Override further with any course-specific static values
    context.update(course.cert_html_view_overrides)

    return render_to_response("certificates/valid.html", context)
예제 #10
0
def render_html_view(request, user_id, course_id):
    """
    This public view generates an HTML representation of the specified user and course
    If a certificate is not available, we display a "Sorry!" screen instead
    """
    try:
        user_id = int(user_id)
    except ValueError:
        raise Http404

    preview_mode = request.GET.get('preview', None)
    platform_name = configuration_helpers.get_value("platform_name", settings.PLATFORM_NAME)
    configuration = CertificateHtmlViewConfiguration.get_config()
    # Create the initial view context, bootstrapping with Django settings and passed-in values
    context = {}
    _update_context_with_basic_info(context, course_id, platform_name, configuration)
    invalid_template_path = 'certificates/invalid.html'

    # Kick the user back to the "Invalid" screen if the feature is disabled globally
    if not settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False):
        return render_to_response(invalid_template_path, context)

    # Load the course and user objects
    try:
        course_key = CourseKey.from_string(course_id)
        user = User.objects.get(id=user_id)
        course = get_course_by_id(course_key)

    # For any course or user exceptions, kick the user back to the "Invalid" screen
    except (InvalidKeyError, User.DoesNotExist, Http404) as exception:
        error_str = (
            "Invalid cert: error finding course %s or user with id "
            "%d. Specific error: %s"
        )
        log.info(error_str, course_id, user_id, str(exception))
        return render_to_response(invalid_template_path, context)

    # Kick the user back to the "Invalid" screen if the feature is disabled for the course
    if not course.cert_html_view_enabled:
        log.info(
            "Invalid cert: HTML certificates disabled for %s. User id: %d",
            course_id,
            user_id,
        )
        return render_to_response(invalid_template_path, context)

    # Load user's certificate
    user_certificate = _get_user_certificate(request, user, course_key, course, preview_mode)
    if not user_certificate:
        log.info(
            "Invalid cert: User %d does not have eligible cert for %s.",
            user_id,
            course_id,
        )
        return render_to_response(invalid_template_path, context)

    # 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:
        log.info(
            "Invalid cert: course %s does not have an active configuration. User id: %d",
            course_id,
            user_id,
        )
        return render_to_response(invalid_template_path, context)

    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 organization info
    _update_organization_context(context, course)

    # Append course info
    _update_course_context(request, context, course, course_key, platform_name)

    # Append course run info from discovery
    _update_context_with_catalog_data(context, course_key)

    # Append user info
    _update_context_with_user_info(context, user, user_certificate)

    # Append social sharing info
    _update_social_context(request, context, course, user, user_certificate, platform_name)

    # Append/Override the existing view context values with certificate specific values
    _update_certificate_context(context, course, user_certificate, platform_name)

    # Append badge info
    _update_badge_context(context, course, user)

    # Append site configuration overrides
    _update_configuration_context(context, configuration)

    # Add certificate header/footer data to current context
    context.update(get_certificate_header_context(is_secure=request.is_secure()))
    context.update(get_certificate_footer_context())

    # Append/Override the existing view context values with any course-specific static values from Advanced Settings
    context.update(course.cert_html_view_overrides)

    # Track certificate view events
    _track_certificate_events(request, context, course, user, user_certificate)

    # FINALLY, render appropriate certificate
    return _render_certificate_template(request, context, course, user_certificate)
예제 #11
0
 def test_clean_bad_json(self):
     """
     Tests if bad JSON string was given.
     """
     self.config = CertificateHtmlViewConfiguration(configuration='{"bad":"test"')
     self.assertRaises(ValidationError, self.config.clean)
예제 #12
0
class CertificateHtmlViewConfigurationTest(TestCase):
    """
    Test the CertificateHtmlViewConfiguration model.
    """
    def setUp(self):
        super(CertificateHtmlViewConfigurationTest, self).setUp()
        self.configuration_string = """{
            "default": {
                "url": "http://www.edx.org",
                "logo_src": "http://www.edx.org/static/images/logo.png"
            },
            "honor": {
                "logo_src": "http://www.edx.org/static/images/honor-logo.png"
            }
        }"""
        self.config = CertificateHtmlViewConfiguration(configuration=self.configuration_string)

    def test_create(self):
        """
        Tests creation of configuration.
        """
        self.config.save()
        self.assertEquals(self.config.configuration, self.configuration_string)

    def test_clean_bad_json(self):
        """
        Tests if bad JSON string was given.
        """
        self.config = CertificateHtmlViewConfiguration(configuration='{"bad":"test"')
        self.assertRaises(ValidationError, self.config.clean)

    def test_get(self):
        """
        Tests get configuration from saved string.
        """
        self.config.enabled = True
        self.config.save()
        expected_config = {
            "default": {
                "url": "http://www.edx.org",
                "logo_src": "http://www.edx.org/static/images/logo.png"
            },
            "honor": {
                "logo_src": "http://www.edx.org/static/images/honor-logo.png"
            }
        }
        self.assertEquals(self.config.get_config(), expected_config)

    def test_get_not_enabled_returns_blank(self):
        """
        Tests get configuration that is not enabled.
        """
        self.config.enabled = False
        self.config.save()
        self.assertEquals(len(self.config.get_config()), 0)

    @override_settings(FEATURES=FEATURES_INVALID_FILE_PATH)
    def test_get_no_database_no_file(self):
        """
        Tests get configuration that is not enabled.
        """
        self.config.configuration = ''
        self.config.save()
        self.assertEquals(self.config.get_config(), {})
예제 #13
0
def render_html_view(request, user_id, course_id):
    """
    This public view generates an HTML representation of the specified user and course
    If a certificate is not available, we display a "Sorry!" screen instead
    """
    try:
        user_id = int(user_id)
    except ValueError:
        raise Http404

    preview_mode = request.GET.get('preview', None)
    platform_name = configuration_helpers.get_value("platform_name",
                                                    settings.PLATFORM_NAME)
    configuration = CertificateHtmlViewConfiguration.get_config()

    # Kick the user back to the "Invalid" screen if the feature is disabled globally
    if not settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False):
        return _render_invalid_certificate(course_id, platform_name,
                                           configuration)

    # Load the course and user objects
    try:
        course_key = CourseKey.from_string(course_id)
        user = User.objects.get(id=user_id)
        course = get_course_by_id(course_key)

    # For any course or user exceptions, kick the user back to the "Invalid" screen
    except (InvalidKeyError, User.DoesNotExist, Http404) as exception:
        error_str = ("Invalid cert: error finding course %s or user with id "
                     "%d. Specific error: %s")
        log.info(error_str, course_id, user_id, str(exception))
        return _render_invalid_certificate(course_id, platform_name,
                                           configuration)

    # Kick the user back to the "Invalid" screen if the feature is disabled for the course
    if not course.cert_html_view_enabled:
        log.info(
            "Invalid cert: HTML certificates disabled for %s. User id: %d",
            course_id,
            user_id,
        )
        return _render_invalid_certificate(course_id, platform_name,
                                           configuration)

    # Load user's certificate
    user_certificate = _get_user_certificate(request, user, course_key, course,
                                             preview_mode)
    if not user_certificate:
        log.info(
            "Invalid cert: User %d does not have eligible cert for %s.",
            user_id,
            course_id,
        )
        return _render_invalid_certificate(course_id, platform_name,
                                           configuration)

    # 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:
        log.info(
            "Invalid cert: course %s does not have an active configuration. User id: %d",
            course_id,
            user_id,
        )
        return _render_invalid_certificate(course_id, platform_name,
                                           configuration)

    # Get data from Discovery service that will be necessary for rendering this Certificate.
    catalog_data = _get_catalog_data_for_course(course_key)

    # Determine whether to use the standard or custom template to render the certificate.
    custom_template = None
    custom_template_language = None
    if settings.FEATURES.get('CUSTOM_CERTIFICATE_TEMPLATES_ENABLED', False):
        custom_template, custom_template_language = _get_custom_template_and_language(
            course.id, user_certificate.mode,
            catalog_data.pop('content_language', None))

    # Determine the language that should be used to render the certificate.
    # For the standard certificate template, use the user language. For custom templates, use
    # the language associated with the template.
    user_language = translation.get_language()
    certificate_language = custom_template_language if custom_template else user_language

    # Generate the certificate context in the correct language, then render the template.
    with translation.override(certificate_language):
        context = {'user_language': user_language}

        _update_context_with_basic_info(context, course_id, platform_name,
                                        configuration)

        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 organization info
        _update_organization_context(context, course)

        # Append course info
        _update_course_context(request, context, course, course_key,
                               platform_name)

        # Append course run info from discovery
        context.update(catalog_data)

        # Append user info
        _update_context_with_user_info(context, user, user_certificate)

        # Append social sharing info
        _update_social_context(request, context, course, user,
                               user_certificate, platform_name)

        # Append/Override the existing view context values with certificate specific values
        _update_certificate_context(context, course, user_certificate,
                                    platform_name)

        # Append badge info
        _update_badge_context(context, course, user)

        # Append site configuration overrides
        _update_configuration_context(context, configuration)

        # Add certificate header/footer data to current context
        context.update(
            get_certificate_header_context(is_secure=request.is_secure()))
        context.update(get_certificate_footer_context())

        # Append/Override the existing view context values with any course-specific static values from Advanced Settings
        context.update(course.cert_html_view_overrides)

        # Track certificate view events
        _track_certificate_events(request, context, course, user,
                                  user_certificate)

        # Render the certificate
        return _render_valid_certificate(request, context, custom_template)
예제 #14
0
def render_html_view(request, user_id, course_id):
    """
    This public view generates an HTML representation of the specified user and course
    If a certificate is not available, we display a "Sorry!" screen instead
    """
    try:
        user_id = int(user_id)
    except ValueError:
        raise Http404

    preview_mode = request.GET.get('preview', None)
    platform_name = configuration_helpers.get_value("platform_name", settings.PLATFORM_NAME)
    configuration = CertificateHtmlViewConfiguration.get_config()

    # Kick the user back to the "Invalid" screen if the feature is disabled globally
    if not settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False):
        return _render_invalid_certificate(course_id, platform_name, configuration)

    # Load the course and user objects
    try:
        course_key = CourseKey.from_string(course_id)
        user = User.objects.get(id=user_id)
        course = get_course_by_id(course_key)

    # For any course or user exceptions, kick the user back to the "Invalid" screen
    except (InvalidKeyError, User.DoesNotExist, Http404) as exception:
        error_str = (
            "Invalid cert: error finding course %s or user with id "
            "%d. Specific error: %s"
        )
        log.info(error_str, course_id, user_id, str(exception))
        return _render_invalid_certificate(course_id, platform_name, configuration)

    # Kick the user back to the "Invalid" screen if the feature is disabled for the course
    if not course.cert_html_view_enabled:
        log.info(
            "Invalid cert: HTML certificates disabled for %s. User id: %d",
            course_id,
            user_id,
        )
        return _render_invalid_certificate(course_id, platform_name, configuration)

    # Load user's certificate
    user_certificate = _get_user_certificate(request, user, course_key, course, preview_mode)
    if not user_certificate:
        log.info(
            "Invalid cert: User %d does not have eligible cert for %s.",
            user_id,
            course_id,
        )
        return _render_invalid_certificate(course_id, platform_name, configuration)

    # 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:
        log.info(
            "Invalid cert: course %s does not have an active configuration. User id: %d",
            course_id,
            user_id,
        )
        return _render_invalid_certificate(course_id, platform_name, configuration)

    # Get data from Discovery service that will be necessary for rendering this Certificate.
    catalog_data = _get_catalog_data_for_course(course_key)

    # Determine whether to use the standard or custom template to render the certificate.
    custom_template = None
    custom_template_language = None
    if settings.FEATURES.get('CUSTOM_CERTIFICATE_TEMPLATES_ENABLED', False):
        custom_template, custom_template_language = _get_custom_template_and_language(
            course.id,
            user_certificate.mode,
            catalog_data.pop('content_language', None)
        )

    # Determine the language that should be used to render the certificate.
    # For the standard certificate template, use the user language. For custom templates, use
    # the language associated with the template.
    user_language = translation.get_language()
    certificate_language = custom_template_language if custom_template else user_language

    # Generate the certificate context in the correct language, then render the template.
    with translation.override(certificate_language):
        context = {'user_language': user_language}

        _update_context_with_basic_info(context, course_id, platform_name, configuration)

        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 organization info
        _update_organization_context(context, course)

        # Append course info
        _update_course_context(request, context, course, course_key, platform_name)

        # Append course run info from discovery
        context.update(catalog_data)

        # Append user info
        _update_context_with_user_info(context, user, user_certificate)

        # Append social sharing info
        _update_social_context(request, context, course, user, user_certificate, platform_name)

        # Append/Override the existing view context values with certificate specific values
        _update_certificate_context(context, course, user_certificate, platform_name)

        # Append badge info
        _update_badge_context(context, course, user)

        # Append site configuration overrides
        _update_configuration_context(context, configuration)

        # Add certificate header/footer data to current context
        context.update(get_certificate_header_context(is_secure=request.is_secure()))
        context.update(get_certificate_footer_context())

        # Append/Override the existing view context values with any course-specific static values from Advanced Settings
        context.update(course.cert_html_view_overrides)

        # Track certificate view events
        _track_certificate_events(request, context, course, user, user_certificate)

        # Render the certificate
        return _render_valid_certificate(request, context, custom_template)
예제 #15
0
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

    # 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'] = '&copy; {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 &amp; characters represent an ampersand character and can be ignored
    context['company_tos_urltext'] = _("Terms of Service &amp; 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 settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False):
        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
        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 request.GET.get('preview', None):
            user_certificate = GeneratedCertificate(
                mode=request.GET.get('preview'),
                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:
            logger.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, request.GET.get('preview'))
    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)

    # 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
    return render_to_response("certificates/valid.html", context)
예제 #16
0
def render_html_view(request, user_id, course_id):
    """
    This public view generates an HTML representation of the specified user and course
    If a certificate is not available, we display a "Sorry!" screen instead
    """
    try:
        user_id = int(user_id)
    except ValueError:
        raise Http404

    preview_mode = request.GET.get('preview', None)
    platform_name = microsite.get_value("platform_name",
                                        settings.PLATFORM_NAME)
    configuration = CertificateHtmlViewConfiguration.get_config()
    # Create the initial view context, bootstrapping with Django settings and passed-in values
    context = {}
    _update_context_with_basic_info(context, course_id, platform_name,
                                    configuration)
    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):
        log.info(
            "Invalid cert: HTML certificates disabled for %s. User id: %d",
            course_id,
            user_id,
        )
        return render_to_response(invalid_template_path, context)

    # Load the course and user objects
    try:
        course_key = CourseKey.from_string(course_id)
        user = User.objects.get(id=user_id)
        course = modulestore().get_course(course_key)

    # For any other expected exceptions, kick the user back to the "Invalid" screen
    except (InvalidKeyError, ItemNotFoundError,
            User.DoesNotExist) as exception:
        error_str = ("Invalid cert: error finding course %s or user with id "
                     "%d. Specific error: %s")
        log.info(error_str, course_id, user_id, str(exception))
        return render_to_response(invalid_template_path, context)

    # Load user's certificate
    user_certificate = _get_user_certificate(request, user, course_key, course,
                                             preview_mode)
    if not user_certificate:
        log.info(
            "Invalid cert: User %d does not have eligible cert for %s.",
            user_id,
            course_id,
        )
        return render_to_response(invalid_template_path, context)

    # 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:
        log.info(
            "Invalid cert: course %s does not have an active configuration. User id: %d",
            course_id,
            user_id,
        )
        return render_to_response(invalid_template_path, context)

    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 organization info
    _update_organization_context(context, course)

    # Append course info
    _update_course_context(request, context, course, platform_name)

    # Append user info
    _update_context_with_user_info(context, user, user_certificate)

    # Append social sharing info
    _update_social_context(request, context, course, user, user_certificate,
                           platform_name)

    # Append/Override the existing view context values with certificate specific values
    _update_certificate_context(context, user_certificate, platform_name)

    # Append badge info
    _update_badge_context(context, course, user)

    # Append microsite overrides
    _update_microsite_context(context, configuration)

    # Add certificate header/footer data to current context
    context.update(
        get_certificate_header_context(is_secure=request.is_secure()))
    context.update(get_certificate_footer_context())

    # Append/Override the existing view context values with any course-specific static values from Advanced Settings
    context.update(course.cert_html_view_overrides)

    # Track certificate view events
    _track_certificate_events(request, context, course, user, user_certificate)

    # FINALLY, render appropriate certificate
    return _render_certificate_template(request, context, course,
                                        user_certificate)
예제 #17
0
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

    # 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'] = '&copy; {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 &amp; characters represent an ampersand character and can be ignored
    context['company_tos_urltext'] = _("Terms of Service &amp; 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
        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 request.GET.get('preview', None):
            user_certificate = GeneratedCertificate(
                mode=request.GET.get('preview'),
                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, request.GET.get('preview'))
    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)

    # 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()
    if linkedin_config.enabled:
        context['linked_in_url'] = linkedin_config.add_to_profile_url(
            course.id,
            course.display_name,
            user_certificate.mode,
            request.build_absolute_uri(get_certificate_url(
                user_id=user.id,
                course_id=unicode(course.id)
            ))
        )

    # 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)
            context = RequestContext(request, context)
            return HttpResponse(template.render(context))

    return render_to_response("certificates/valid.html", context)
예제 #18
0
class CertificateHtmlViewConfigurationTest(TestCase):
    """
    Test the CertificateHtmlViewConfiguration model.
    """
    def setUp(self):
        super(CertificateHtmlViewConfigurationTest, self).setUp()
        self.configuration_string = """{
            "default": {
                "url": "http://www.edx.org",
                "logo_src": "http://www.edx.org/static/images/logo.png"
            },
            "honor": {
                "logo_src": "http://www.edx.org/static/images/honor-logo.png"
            }
        }"""
        self.config = CertificateHtmlViewConfiguration(
            configuration=self.configuration_string)

    def test_create(self):
        """
        Tests creation of configuration.
        """
        self.config.save()
        self.assertEquals(self.config.configuration, self.configuration_string)

    def test_clean_bad_json(self):
        """
        Tests if bad JSON string was given.
        """
        self.config = CertificateHtmlViewConfiguration(
            configuration='{"bad":"test"')
        self.assertRaises(ValidationError, self.config.clean)

    def test_get(self):
        """
        Tests get configuration from saved string.
        """
        self.config.enabled = True
        self.config.save()
        expected_config = {
            "default": {
                "url": "http://www.edx.org",
                "logo_src": "http://www.edx.org/static/images/logo.png"
            },
            "honor": {
                "logo_src": "http://www.edx.org/static/images/honor-logo.png"
            }
        }
        self.assertEquals(self.config.get_config(), expected_config)

    def test_get_not_enabled_returns_blank(self):
        """
        Tests get configuration that is not enabled.
        """
        self.config.enabled = False
        self.config.save()
        self.assertEquals(len(self.config.get_config()), 0)

    @override_settings(FEATURES=FEATURES_INVALID_FILE_PATH)
    def test_get_no_database_no_file(self):
        """
        Tests get configuration that is not enabled.
        """
        self.config.configuration = ''
        self.config.save()
        self.assertEquals(self.config.get_config(), {})
예제 #19
0
def render_html_view(request):
    """
    This view generates an HTML representation of the specified student's certificate
    If a certificate is not available, we display a "Sorry!" screen instead
    """
    # Initialize the template context and bootstrap with default values from configuration
    context = {}
    configuration = CertificateHtmlViewConfiguration.get_config()
    context = configuration.get('default', {})

    invalid_template_path = 'certificates/invalid.html'

    # 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")

    # Feature Flag check
    if not settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False):
        return render_to_response(invalid_template_path, context)

    course_id = request.GET.get('course', None)
    context['course'] = course_id
    if not course_id:
        return render_to_response(invalid_template_path, context)

    # Course Lookup
    try:
        course_key = CourseKey.from_string(course_id)
    except InvalidKeyError:
        return render_to_response(invalid_template_path, context)
    course = modulestore().get_course(course_key)
    if not course:
        return render_to_response(invalid_template_path, context)

    # Certificate Lookup
    try:
        certificate = GeneratedCertificate.objects.get(user=request.user,
                                                       course_id=course_key)
    except GeneratedCertificate.DoesNotExist:
        return render_to_response(invalid_template_path, context)

    # Override the defaults with any mode-specific static values
    context.update(configuration.get(certificate.mode, {}))
    # Override further with any course-specific static values
    context.update(course.cert_html_view_overrides)

    # Populate dynamic output values using the course/certificate data loaded above
    user_fullname = request.user.profile.name
    platform_name = context.get('platform_name')
    context['accomplishment_copy_name'] = user_fullname
    context['accomplishment_copy_course_org'] = course.org
    context['accomplishment_copy_course_name'] = course.display_name
    context['certificate_id_number'] = certificate.verify_uuid
    context['certificate_verify_url'] = "{prefix}{uuid}{suffix}".format(
        prefix=context.get('certificate_verify_url_prefix'),
        uuid=certificate.verify_uuid,
        suffix=context.get('certificate_verify_url_suffix'))
    context['logo_alt'] = platform_name

    accd_course_org_html = '<span class="detail--xuniversity">{partner_name}</span>'.format(
        partner_name=course.org)
    accd_platform_name_html = '<span class="detail--company">{platform_name}</span>'.format(
        platform_name=platform_name)
    # Translators: This line appears on the certificate after the name of a course, and provides more
    # information about the organizations providing the course material to platform users
    context['accomplishment_copy_course_description'] = _(
        'a course of study offered by {partner_name}, '
        'through {platform_name}.').format(
            partner_name=accd_course_org_html,
            platform_name=accd_platform_name_html)

    context['accomplishment_more_title'] = _(
        "More Information About {user_name}'s Certificate:").format(
            user_name=user_fullname)

    # Translators:  This line appears on the page just before the generation date for the certificate
    context['certificate_date_issued_title'] = _("Issued On:")

    # Translators:  The format of the date includes the full name of the month
    context['certificate_date_issued'] = _('{month} {day}, {year}').format(
        month=certificate.modified_date.strftime("%B"),
        day=certificate.modified_date.day,
        year=certificate.modified_date.year)

    # Translators:  The Certificate ID Number is an alphanumeric value unique to each individual certificate
    context['certificate_id_number_title'] = _('Certificate ID Number')

    context['certificate_info_title'] = _('About {platform_name} Certificates'
                                          ).format(platform_name=platform_name)

    # Translators: This text describes the purpose (and therefore, value) of a course certificate
    # 'verifying your identity' refers to the process for establishing the authenticity of the student
    context['certificate_info_description'] = _(
        "{platform_name} acknowledges achievements through certificates, which "
        "are awarded for various activities {platform_name} students complete "
        "under the <a href='{tos_url}'>{platform_name} Honor Code</a>.  Some "
        "certificates require completing additional steps, such as "
        "<a href='{verified_cert_url}'> verifying your identity</a>.").format(
            platform_name=platform_name,
            tos_url=context.get('company_tos_url'),
            verified_cert_url=context.get('company_verified_certificate_url'))

    # Translators:  Certificate Types correspond to the different enrollment options available for a given course
    context['certificate_type_title'] = _(
        '{certificate_type} Certfificate').format(
            certificate_type=context.get('certificate_type'))

    context['certificate_verify_title'] = _(
        "How {platform_name} Validates Student Certificates").format(
            platform_name=platform_name)

    # Translators:  This text describes the validation mechanism for a certificate file (known as GPG security)
    context['certificate_verify_description'] = _(
        'Certificates issued by {platform_name} are signed by a gpg key so '
        'that they can be validated independently by anyone with the '
        '{platform_name} public key. For independent verification, '
        '{platform_name} uses what is called a '
        '"detached signature"&quot;".').format(platform_name=platform_name)

    context['certificate_verify_urltext'] = _(
        "Validate this certificate for yourself")

    # Translators:  This text describes (at a high level) the mission and charter the edX platform and organization
    context['company_about_description'] = _(
        "{platform_name} offers interactive online classes and MOOCs from the "
        "world's best universities, including MIT, Harvard, Berkeley, University "
        "of Texas, and many others.  {platform_name} is a non-profit online "
        "initiative created by founding partners Harvard and MIT.").format(
            platform_name=platform_name)

    context['company_about_title'] = _("About {platform_name}").format(
        platform_name=platform_name)

    context['company_about_urltext'] = _(
        "Learn more about {platform_name}").format(platform_name=platform_name)

    context['company_courselist_urltext'] = _(
        "Learn with {platform_name}").format(platform_name=platform_name)

    context['company_careers_urltext'] = _("Work at {platform_name}").format(
        platform_name=platform_name)

    context['company_contact_urltext'] = _("Contact {platform_name}").format(
        platform_name=platform_name)

    context['company_privacy_urltext'] = _("Privacy Policy")

    context['company_tos_urltext'] = _("Terms of Service &amp; Honor Code")

    # Translators:  This text appears near the top of the certficate and describes the guarantee provided by edX
    context['document_banner'] = _(
        "{platform_name} acknowledges the following student accomplishment"
    ).format(platform_name=platform_name)

    context['logo_subtitle'] = _("Certificate Validation")

    if certificate.mode == 'honor':
        # Translators:  This text describes the 'Honor' course certificate type.
        context['certificate_type_description'] = _(
            "An {cert_type} Certificate signifies that an {platform_name} "
            "learner has agreed to abide by {platform_name}'s honor code and "
            "completed all of the required tasks for this course under its "
            "guidelines.").format(cert_type=context.get('certificate_type'),
                                  platform_name=platform_name)
    elif certificate.mode == 'verified':
        # Translators:  This text describes the 'ID Verified' course certificate type, which is a higher level of
        # verification offered by edX.  This type of verification is useful for professional education/certifications
        context['certificate_type_description'] = _(
            "An {cert_type} Certificate signifies that an {platform_name} "
            "learner has agreed to abide by {platform_name}'s honor code and "
            "completed all of the required tasks for this course under its "
            "guidelines, as well as having their photo ID checked to verify "
            "their identity.").format(
                cert_type=context.get('certificate_type'),
                platform_name=platform_name)
    elif certificate.mode == 'xseries':
        # Translators:  This text describes the 'XSeries' course certificate type.  An XSeries is a collection of
        # courses related to each other in a meaningful way, such as a specific topic or theme, or even an organization
        context['certificate_type_description'] = _(
            "An {cert_type} Certificate demonstrates a high level of "
            "achievement in a program of study, and includes verification of "
            "the student's identity.").format(
                cert_type=context.get('certificate_type'))

    # Translators:  This is the copyright line which appears at the bottom of the certificate page/screen
    context['copyright_text'] = _(
        '&copy; {year} {platform_name}. All rights reserved.').format(
            year=datetime.now().year, platform_name=platform_name)

    # Translators:  This text represents the verification of the certificate
    context['document_meta_description'] = _(
        'This is a valid {platform_name} certificate for {user_name}, '
        'who participated in {partner_name} {course_number}').format(
            platform_name=platform_name,
            user_name=user_fullname,
            partner_name=course.org,
            course_number=course.number)

    # Translators:  This text is bound to the HTML 'title' element of the page and appears in the browser title bar
    context['document_title'] = _(
        "Valid {partner_name} {course_number} Certificate | {platform_name}"
    ).format(partner_name=course.org,
             course_number=course.number,
             platform_name=platform_name)

    # Translators:  This text fragment appears after the student's name (displayed in a large font) on the certificate
    # screen.  The text describes the accomplishment represented by the certificate information displayed to the user
    context['accomplishment_copy_description_full'] = _(
        "successfully completed, received a passing grade, and was "
        "awarded a {platform_name} {certificate_type} "
        "Certificate of Completion in ").format(
            platform_name=platform_name,
            certificate_type=context.get("certificate_type"))

    return render_to_response("certificates/valid.html", context)