def linkedin_add_to_profile_url(self): """ Returns a URL to add a certificate to a LinkedIn profile (will autofill fields). Requires LinkedIn sharing to be enabled, either via a site configuration or a LinkedInAddToProfileConfiguration object being enabled. """ if self.effective_user.is_anonymous: return linkedin_config = LinkedInAddToProfileConfiguration.current() if linkedin_config.is_enabled(): try: user_certificate = GeneratedCertificate.eligible_certificates.get( user=self.effective_user, course_id=self.course_key) except GeneratedCertificate.DoesNotExist: return cert_url = self.request.build_absolute_uri( get_certificate_url(course_id=self.course_key, uuid=user_certificate.verify_uuid)) return linkedin_config.add_to_profile_url( self.overview.display_name, user_certificate.mode, cert_url, certificate=user_certificate, )
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 _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 _update_social_context(request, context, course, user, user_certificate, platform_name): """ Updates context dictionary with info required for social sharing. """ share_settings = microsite.get_value("SOCIAL_SHARING_SETTINGS", settings.SOCIAL_SHARING_SETTINGS) context['facebook_share_enabled'] = share_settings.get( 'CERTIFICATE_FACEBOOK', False) context['facebook_app_id'] = microsite.get_value("FACEBOOK_APP_ID", settings.FACEBOOK_APP_ID) 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 at {platform_name}. Take a look at my certificate." ).format(platform_name=platform_name)) share_url = request.build_absolute_uri( get_certificate_url(course_id=course.id, uuid=user_certificate.verify_uuid)) 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() linkedin_share_enabled = share_settings.get('CERTIFICATE_LINKEDIN', linkedin_config.enabled) if linkedin_share_enabled: context['linked_in_url'] = linkedin_config.add_to_profile_url( course.id, course.display_name, user_certificate.mode, smart_str(share_url))
def _update_social_context(request, context, course, user, user_certificate, platform_name): """ Updates context dictionary with info required for social sharing. """ share_settings = microsite.get_value("SOCIAL_SHARING_SETTINGS", settings.SOCIAL_SHARING_SETTINGS) context['facebook_share_enabled'] = share_settings.get('CERTIFICATE_FACEBOOK', False) context['facebook_app_id'] = microsite.get_value("FACEBOOK_APP_ID", settings.FACEBOOK_APP_ID) 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 at {platform_name}. Take a look at my certificate.").format( platform_name=platform_name ) ) share_url = request.build_absolute_uri(get_certificate_url(course_id=course.id, uuid=user_certificate.verify_uuid)) 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() linkedin_share_enabled = share_settings.get('CERTIFICATE_LINKEDIN', linkedin_config.enabled) if linkedin_share_enabled: context['linked_in_url'] = linkedin_config.add_to_profile_url( course.id, course.display_name, user_certificate.mode, smart_str(share_url) )
def _cert_info(user, course_overview, cert_status): """ Implements the logic for cert_info -- split out for testing. Arguments: user (User): A user. course_overview (CourseOverview): A course. """ # simplify the status for the template using this lookup table template_state = { CertificateStatuses.generating: 'generating', CertificateStatuses.downloadable: 'downloadable', CertificateStatuses.notpassing: 'notpassing', CertificateStatuses.restricted: 'restricted', CertificateStatuses.auditing: 'auditing', CertificateStatuses.audit_passing: 'auditing', CertificateStatuses.audit_notpassing: 'auditing', CertificateStatuses.unverified: 'unverified', } certificate_earned_but_not_available_status = 'certificate_earned_but_not_available' default_status = 'processing' default_info = { 'status': default_status, 'show_survey_button': False, 'can_unenroll': True, } if cert_status is None: return default_info status = template_state.get(cert_status['status'], default_status) is_hidden_status = status in ('unavailable', 'processing', 'generating', 'notpassing', 'auditing') if ( not certificates_viewable_for_course(course_overview) and (status in CertificateStatuses.PASSED_STATUSES) and course_overview.certificate_available_date ): status = certificate_earned_but_not_available_status if ( course_overview.certificates_display_behavior == 'early_no_info' and is_hidden_status ): return default_info status_dict = { 'status': status, 'mode': cert_status.get('mode', None), 'linked_in_url': None, 'can_unenroll': status not in DISABLE_UNENROLL_CERT_STATES, } if status != default_status and course_overview.end_of_course_survey_url is not None: status_dict.update({ 'show_survey_button': True, 'survey_url': process_survey_link(course_overview.end_of_course_survey_url, user)}) else: status_dict['show_survey_button'] = False if status == 'downloadable': # showing the certificate web view button if certificate is downloadable state and feature flags are enabled. if has_html_certificates_enabled(course_overview): if course_overview.has_any_active_web_certificate: status_dict.update({ 'show_cert_web_view': True, 'cert_web_view_url': get_certificate_url(course_id=course_overview.id, uuid=cert_status['uuid']) }) else: # don't show download certificate button if we don't have an active certificate for course status_dict['status'] = 'unavailable' elif 'download_url' not in cert_status: log.warning( u"User %s has a downloadable cert for %s, but no download url", user.username, course_overview.id ) return default_info else: status_dict['download_url'] = cert_status['download_url'] # If enabled, show the LinkedIn "add to profile" button # Clicking this button sends the user to LinkedIn where they # can add the certificate information to their profile. linkedin_config = LinkedInAddToProfileConfiguration.current() # posting certificates to LinkedIn is not currently # supported in White Labels if linkedin_config.enabled and not theming_helpers.is_request_in_themed_site(): status_dict['linked_in_url'] = linkedin_config.add_to_profile_url( course_overview.id, course_overview.display_name, cert_status.get('mode'), cert_status['download_url'] ) if status in {'generating', 'downloadable', 'notpassing', 'restricted', 'auditing', 'unverified'}: cert_grade_percent = -1 persisted_grade_percent = -1 persisted_grade = CourseGradeFactory().read(user, course=course_overview, create_if_needed=False) if persisted_grade is not None: persisted_grade_percent = persisted_grade.percent if 'grade' in cert_status: cert_grade_percent = float(cert_status['grade']) if cert_grade_percent == -1 and persisted_grade_percent == -1: # Note: as of 11/20/2012, we know there are students in this state-- cs169.1x, # who need to be regraded (we weren't tracking 'notpassing' at first). # We can add a log.warning here once we think it shouldn't happen. return default_info grades_input = [cert_grade_percent, persisted_grade_percent] max_grade = None if all(grade is None for grade in grades_input) else max(filter(lambda x: x is not None, grades_input)) status_dict['grade'] = text_type(max_grade) return status_dict
def _update_certificate_context(context, course, user, user_certificate): """ Build up the certificate web view context using the provided values (Helper method to keep the view clean) """ # Populate dynamic output values using the course/certificate data loaded above user_fullname = user.profile.name platform_name = microsite.get_value("platform_name", settings.PLATFORM_NAME) certificate_type = context.get('certificate_type') context['username'] = user.username context['course_mode'] = user_certificate.mode context['accomplishment_user_id'] = user.id context['accomplishment_copy_name'] = user_fullname context['accomplishment_copy_username'] = user.username context['accomplishment_copy_course_org'] = course.org context['accomplishment_copy_course_name'] = course.display_name context['course_image_url'] = course_image_url(course) context['share_settings'] = settings.FEATURES.get( 'SOCIAL_SHARING_SETTINGS', {}) try: badge = BadgeAssertion.objects.get( user=user, course_id=course.location.course_key) except BadgeAssertion.DoesNotExist: badge = None context['badge'] = badge # Override the defaults with any mode-specific static values context['certificate_id_number'] = user_certificate.verify_uuid context['certificate_verify_url'] = "{prefix}{uuid}{suffix}".format( prefix=context.get('certificate_verify_url_prefix'), uuid=user_certificate.verify_uuid, suffix=context.get('certificate_verify_url_suffix')) # Translators: The format of the date includes the full name of the month context['certificate_date_issued'] = _('{month} {day}, {year}').format( month=user_certificate.modified_date.strftime("%B"), day=user_certificate.modified_date.day, year=user_certificate.modified_date.year) 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) # Translators: Accomplishments describe the awards/certifications obtained by students on this platform context['accomplishment_copy_about'] = _( 'About {platform_name} Accomplishments').format( platform_name=platform_name) 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 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')) 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""".').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) # 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) # 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'] = _( "{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")) certificate_type_description = get_certificate_description( user_certificate.mode, certificate_type, platform_name) if certificate_type_description: context['certificate_type_description'] = certificate_type_description # 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, get_certificate_url(user_id=user.id, course_id=unicode(course.id), verify_uuid=user_certificate.verify_uuid)) # Translators: This line is displayed to a user who has completed a course and achieved a certification context['accomplishment_banner_opening'] = _( "{fullname}, you've earned a certificate!").format( fullname=user_fullname) # Translators: This line congratulates the user and instructs them to share their accomplishment on social networks context['accomplishment_banner_congrats'] = _( "Congratulations! This page summarizes all of the details of what " "you've accomplished. Show it off to family, friends, and colleagues " "in your social and professional networks.") # Translators: This line leads the reader to understand more about the certificate that a student has been awarded context['accomplishment_copy_more_about'] = _( "More about {fullname}'s accomplishment").format( fullname=user_fullname)
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'] = '© {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 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)
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'] = '© {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 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)
def _update_certificate_context(context, course, user, user_certificate): """ Build up the certificate web view context using the provided values (Helper method to keep the view clean) """ # Populate dynamic output values using the course/certificate data loaded above user_fullname = user.profile.name platform_name = microsite.get_value("platform_name", settings.PLATFORM_NAME) certificate_type = context.get('certificate_type') context['username'] = user.username context['course_mode'] = user_certificate.mode context['accomplishment_user_id'] = user.id context['accomplishment_copy_name'] = user_fullname context['accomplishment_copy_username'] = user.username context['accomplishment_copy_course_org'] = course.org context['accomplishment_copy_course_name'] = course.display_name try: badge = BadgeAssertion.objects.get(user=user, course_id=course.location.course_key) except BadgeAssertion.DoesNotExist: badge = None context['badge'] = badge # Override the defaults with any mode-specific static values context['certificate_id_number'] = user_certificate.verify_uuid context['certificate_verify_url'] = "{prefix}{uuid}{suffix}".format( prefix=context.get('certificate_verify_url_prefix'), uuid=user_certificate.verify_uuid, suffix=context.get('certificate_verify_url_suffix') ) # Translators: The format of the date includes the full name of the month context['certificate_date_issued'] = _('{month} {day}, {year}').format( month=user_certificate.modified_date.strftime("%B"), day=user_certificate.modified_date.day, year=user_certificate.modified_date.year ) 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 ) # Translators: Accomplishments describe the awards/certifications obtained by students on this platform context['accomplishment_copy_about'] = _('About {platform_name} Accomplishments').format( platform_name=platform_name ) 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 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') ) 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""".').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) # 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 ) # 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'] = _("{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") ) certificate_type_description = get_certificate_description(user_certificate.mode, certificate_type, platform_name) if certificate_type_description: context['certificate_type_description'] = certificate_type_description # 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, get_certificate_url( user_id=user.id, course_id=course.id.to_deprecated_string() ) ) # Translators: This line is displayed to a user who has completed a course and achieved a certification context['accomplishment_banner_opening'] = _("{fullname}, you've earned a certificate!").format( fullname=user_fullname ) # Translators: This line congratulates the user and instructs them to share their accomplishment on social networks context['accomplishment_banner_congrats'] = _("Congratulations! This page summarizes all of the details of what " "you've accomplished. Show it off to family, friends, and colleagues " "in your social and professional networks.") # Translators: This line leads the reader to understand more about the certificate that a student has been awarded context['accomplishment_copy_more_about'] = _("More about {fullname}'s accomplishment").format( fullname=user_fullname )
def _cert_info(user, course_overview, cert_status): """ Implements the logic for cert_info -- split out for testing. Arguments: user (User): A user. course_overview (CourseOverview): A course. """ # simplify the status for the template using this lookup table template_state = { CertificateStatuses.generating: 'generating', CertificateStatuses.downloadable: 'downloadable', CertificateStatuses.notpassing: 'notpassing', CertificateStatuses.restricted: 'restricted', CertificateStatuses.auditing: 'auditing', CertificateStatuses.audit_passing: 'auditing', CertificateStatuses.audit_notpassing: 'auditing', CertificateStatuses.unverified: 'unverified', } certificate_earned_but_not_available_status = 'certificate_earned_but_not_available' default_status = 'processing' default_info = { 'status': default_status, 'show_survey_button': False, 'can_unenroll': True, } if cert_status is None: return default_info status = template_state.get(cert_status['status'], default_status) is_hidden_status = status in ('unavailable', 'processing', 'generating', 'notpassing', 'auditing') if ( not certificates_viewable_for_course(course_overview) and (status in CertificateStatuses.PASSED_STATUSES) and course_overview.certificate_available_date ): status = certificate_earned_but_not_available_status if ( course_overview.certificates_display_behavior == 'early_no_info' and is_hidden_status ): return default_info status_dict = { 'status': status, 'mode': cert_status.get('mode', None), 'linked_in_url': None, 'can_unenroll': status not in DISABLE_UNENROLL_CERT_STATES, } if status != default_status and course_overview.end_of_course_survey_url is not None: status_dict.update({ 'show_survey_button': True, 'survey_url': process_survey_link(course_overview.end_of_course_survey_url, user)}) else: status_dict['show_survey_button'] = False if status == 'downloadable': # showing the certificate web view button if certificate is downloadable state and feature flags are enabled. if has_html_certificates_enabled(course_overview): if course_overview.has_any_active_web_certificate: status_dict.update({ 'show_cert_web_view': True, 'cert_web_view_url': get_certificate_url(course_id=course_overview.id, uuid=cert_status['uuid']) }) else: # don't show download certificate button if we don't have an active certificate for course status_dict['status'] = 'unavailable' elif 'download_url' not in cert_status: log.warning( u"User %s has a downloadable cert for %s, but no download url", user.username, course_overview.id ) return default_info else: status_dict['download_url'] = cert_status['download_url'] # If enabled, show the LinkedIn "add to profile" button # Clicking this button sends the user to LinkedIn where they # can add the certificate information to their profile. linkedin_config = LinkedInAddToProfileConfiguration.current() # posting certificates to LinkedIn is not currently # supported in White Labels if linkedin_config.enabled and not theming_helpers.is_request_in_themed_site(): status_dict['linked_in_url'] = linkedin_config.add_to_profile_url( course_overview.id, course_overview.display_name, cert_status.get('mode'), cert_status['download_url'] ) if status in {'generating', 'downloadable', 'notpassing', 'restricted', 'auditing', 'unverified'}: cert_grade_percent = -1 persisted_grade_percent = -1 persisted_grade = CourseGradeFactory().read(user, course=course_overview, create_if_needed=False) if persisted_grade is not None: persisted_grade_percent = persisted_grade.percent if 'grade' in cert_status: cert_grade_percent = float(cert_status['grade']) if cert_grade_percent == -1 and persisted_grade_percent == -1: # Note: as of 11/20/2012, we know there are students in this state-- cs169.1x, # who need to be regraded (we weren't tracking 'notpassing' at first). # We can add a log.warning here once we think it shouldn't happen. return default_info status_dict['grade'] = text_type(max(cert_grade_percent, persisted_grade_percent)) return status_dict
def prorgam_user_certificate(request, certificate_uuid): platform_name = configuration_helpers.get_value("platform_name", settings.PLATFORM_NAME) context = {} try: user_program_certificate = ProgramGeneratedCertificate.objects.get( verify_uuid=certificate_uuid, issued=True) user = user_program_certificate.user program_certificate_signs = ProgramCertificateSignatories.objects.filter( program=user_program_certificate.program) context['user_program_certificate'] = user_program_certificate context['program_certificate_signs'] = program_certificate_signs context['platform_name'] = platform_name context['course_id'] = user_program_certificate.program.id context['full_course_image_url'] = request.build_absolute_uri( user_program_certificate.program.banner_image.url) # Needed # Translators: 'All rights reserved' is a legal term used in copyrighting to protect published content reserved = _("All rights reserved") context[ 'copyright_text'] = u'© {year} {platform_name}. {reserved}.'.format( year=settings.COPYRIGHT_YEAR, platform_name=platform_name, reserved=reserved) # Needed # Translators: A 'Privacy Policy' is a legal document/statement describing a website's use of personal information context['company_privacy_urltext'] = _("Privacy Policy") # Needed # Translators: This line appears as a byline to a header image and describes the purpose of the page context['logo_subtitle'] = _("Certificate Validation") # Needed # Translators: Accomplishments describe the awards/certifications obtained by students on this platform context['accomplishment_copy_about'] = _( 'About {platform_name} Accomplishments').format( platform_name=platform_name) # Needed # Translators: This line appears on the page just before the generation date for the certificate context['certificate_date_issued_title'] = _("Issued On:") # Needed # 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." ).format(platform_name=platform_name) # Needed context['company_about_title'] = _("About {platform_name}").format( platform_name=platform_name) # Needed context['company_about_urltext'] = _( "Learn more about {platform_name}").format( platform_name=platform_name) # Needed banner docs # 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) # Needed # 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()) # Needed context[ 'accomplishment_copy_course_name'] = user_program_certificate.program.name # Needed # Translators: This text represents the description of course context['accomplishment_copy_course_description'] = _( 'a course of study offered by ' '{platform_name}.').format(platform_name=platform_name) user_fullname = user.profile.name # Needed context['accomplishment_user_id'] = user.id # Needed context['accomplishment_copy_name'] = user_fullname # Needed context['accomplishment_copy_username'] = user.username # Needed banner text # Translators: This line is displayed to a user who has completed a course and achieved a certification context['accomplishment_banner_opening'] = _( "{fullname}, you earned a certificate!").format( fullname=user_fullname) # Needed banner text # Translators: This line congratulates the user and instructs them to share their accomplishment on social networks context['accomplishment_banner_congrats'] = _( "Congratulations! This page summarizes what " "you accomplished. Show it off to family, friends, and colleagues " "in your social and professional networks.") # Needed # Translators: This line leads the reader to understand more about the certificate that a student has been awarded context['accomplishment_copy_more_about'] = _( "More about {fullname}'s accomplishment").format( fullname=user_fullname) # Needed for social sharing share_settings = configuration_helpers.get_value( "SOCIAL_SHARING_SETTINGS", settings.SOCIAL_SHARING_SETTINGS) context['facebook_share_enabled'] = share_settings.get( 'CERTIFICATE_FACEBOOK', False) context['facebook_app_id'] = configuration_helpers.get_value( "FACEBOOK_APP_ID", settings.FACEBOOK_APP_ID) 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 at {platform_name}. Take a look at my certificate." ).format(platform_name=platform_name)) # Need to change certificate url share_url = request.build_absolute_uri( reverse( 'openedx.core.djangoapps.micro_masters.views.prorgam_user_certificate', kwargs={'certificate_uuid': certificate_uuid})) 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() linkedin_share_enabled = share_settings.get('CERTIFICATE_LINKEDIN', linkedin_config.enabled) if linkedin_share_enabled: context['linked_in_url'] = linkedin_config.add_to_profile_url( course.id, context['accomplishment_copy_course_name'], user_certificate.mode, smart_str(share_url)) # certificate_type = context.get('certificate_type') # Override the defaults with any mode-specific static values # Needed context['certificate_id_number'] = certificate_uuid # Needed # Translators: The format of the date includes the full name of the month context['certificate_date_issued'] = _('{month} {day}, {year}').format( month=user_program_certificate.modified.strftime("%B"), day=user_program_certificate.modified.day, year=user_program_certificate.modified.year) # Needed # Translators: This text is bound to the HTML 'title' element of the page and appears in the browser title bar context['document_title'] = _("Certificate | {platform_name}").format( platform_name=platform_name) # Needed # 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 this {platform_name} " "Certificate of Completion in ").format( platform_name=platform_name) # Needed # Translators: This text describes the purpose (and therefore, value) of a course certificate context['certificate_info_description'] = _( "{platform_name} acknowledges achievements through " "certificates, which are awarded for course activities " "that {platform_name} students complete.").format( platform_name=platform_name, tos_url=context.get('company_tos_url')) return render_to_response("micro_masters/certificates/valid.html", context) except Exception, e: raise Http404