Commit f854726e by Will Daly

Add tracking code to LinkedIn URL.

Add client-side analytics event for LinkedIn Add to Profile button click.

Add management command for generating certs for testing.

Update styling of the certificate messages.
parent 36855475
......@@ -29,6 +29,17 @@ class CourseAccessRoleAdmin(admin.ModelAdmin):
'id', 'user', 'org', 'course_id', 'role'
)
class LinkedInAddToProfileConfigurationAdmin(admin.ModelAdmin):
"""Admin interface for the LinkedIn Add to Profile configuration. """
class Meta:
model = LinkedInAddToProfileConfiguration
# Exclude deprecated fields
exclude = ('dashboard_tracking_code',)
admin.site.register(UserProfile)
admin.site.register(UserTestGroup)
......@@ -45,4 +56,4 @@ admin.site.register(CourseAccessRole, CourseAccessRoleAdmin)
admin.site.register(DashboardConfiguration, ConfigurationModelAdmin)
admin.site.register(LinkedInAddToProfileConfiguration)
admin.site.register(LinkedInAddToProfileConfiguration, LinkedInAddToProfileConfigurationAdmin)
......@@ -1467,34 +1467,88 @@ class LinkedInAddToProfileConfiguration(ConfigurationModel):
# Deprecated
dashboard_tracking_code = models.TextField(default="", blank=True)
def add_to_profile_url(self, course_name, enrollment_mode, cert_url, source="o"):
trk_partner_name = models.CharField(
max_length=10,
default="",
blank=True,
help_text=ugettext_lazy(
u"Short identifier for the LinkedIn partner used in the tracking code. "
u"(Example: 'edx') "
u"If no value is provided, tracking codes will not be sent to LinkedIn."
)
)
def add_to_profile_url(self, course_key, course_name, cert_mode, cert_url, source="o", target="dashboard"):
"""Construct the URL for the "add to profile" button.
Arguments:
course_key (CourseKey): The identifier for the course.
course_name (unicode): The display name of the course.
enrollment_mode (str): The enrollment mode of the user (e.g. "verified", "honor", "professional")
cert_mode (str): The course mode of the user's certificate (e.g. "verified", "honor", "professional")
cert_url (str): The download URL for the certificate.
Keyword Arguments:
source (str): Either "o" (for onsite/UI), "e" (for emails), or "m" (for mobile)
target (str): An identifier for the occurrance of the button.
"""
params = OrderedDict([
('_ed', self.company_identifier),
('pfCertificationName', self._cert_name(course_name, enrollment_mode).encode('utf-8')),
('pfCertificationName', self._cert_name(course_name, cert_mode).encode('utf-8')),
('pfCertificationUrl', cert_url),
('source', source)
])
tracking_code = self._tracking_code(course_key, cert_mode, target)
if tracking_code is not None:
params['trk'] = tracking_code
return u'http://www.linkedin.com/profile/add?{params}'.format(
params=urlencode(params)
)
def _cert_name(self, course_name, enrollment_mode):
def _cert_name(self, course_name, cert_mode):
"""Name of the certification, for display on LinkedIn. """
return self.MODE_TO_CERT_NAME.get(
enrollment_mode,
cert_mode,
_(u"{platform_name} Certificate for {course_name}")
).format(
platform_name=settings.PLATFORM_NAME,
course_name=course_name
)
def _tracking_code(self, course_key, cert_mode, target):
"""Create a tracking code for the button.
Tracking codes are used by LinkedIn to collect
analytics about certifications users are adding
to their profiles.
The tracking code format is:
&trk=[partner name]-[certificate type]-[date]-[target field]
In our case, we're sending:
&trk=edx-{COURSE ID}_{COURSE MODE}-{TARGET}
If no partner code is configured, then this will
return None, indicating that tracking codes are disabled.
Arguments:
course_key (CourseKey): The identifier for the course.
cert_mode (str): The enrollment mode for the course.
target (str): Identifier for where the button is located.
Returns:
unicode or None
"""
return (
u"{partner}-{course_key}_{cert_mode}-{target}".format(
partner=self.trk_partner_name,
course_key=unicode(course_key),
cert_mode=cert_mode,
target=target
)
if self.trk_partner_name else None
)
# -*- coding: utf-8 -*-
"""Tests for LinkedIn Add to Profile configuration. """
import ddt
from urllib import urlencode
from django.test import TestCase
from opaque_keys.edx.locator import CourseLocator
from student.models import LinkedInAddToProfileConfiguration
@ddt.ddt
class LinkedInAddToProfileUrlTests(TestCase):
"""Tests for URL generation of LinkedInAddToProfileConfig. """
COURSE_KEY = CourseLocator(org="edx", course="DemoX", run="Demo_Course")
COURSE_NAME = u"Test Course ☃"
CERT_URL = u"http://s3.edx/cert"
@ddt.data(
('honor', u'edX+Honor+Code+Certificate+for+Test+Course+%E2%98%83'),
('verified', u'edX+Verified+Certificate+for+Test+Course+%E2%98%83'),
('professional', u'edX+Professional+Certificate+for+Test+Course+%E2%98%83'),
('default_mode', u'edX+Certificate+for+Test+Course+%E2%98%83')
)
@ddt.unpack
def test_linked_in_url(self, cert_mode, expected_cert_name):
config = LinkedInAddToProfileConfiguration(
company_identifier='0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9',
enabled=True
)
expected_url = (
'http://www.linkedin.com/profile/add'
'?_ed=0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9&'
'pfCertificationName={expected_cert_name}&'
'pfCertificationUrl=http%3A%2F%2Fs3.edx%2Fcert&'
'source=o'
).format(expected_cert_name=expected_cert_name)
actual_url = config.add_to_profile_url(
self.COURSE_KEY,
self.COURSE_NAME,
cert_mode,
self.CERT_URL
)
self.assertEqual(actual_url, expected_url)
def test_linked_in_url_tracking_code(self):
config = LinkedInAddToProfileConfiguration(
company_identifier="abcd123",
trk_partner_name="edx",
enabled=True
)
expected_param = urlencode({
'trk': u'edx-{course_key}_honor-dashboard'.format(
course_key=self.COURSE_KEY
)
})
actual_url = config.add_to_profile_url(
self.COURSE_KEY,
self.COURSE_NAME,
'honor',
self.CERT_URL
)
self.assertIn(expected_param, actual_url)
......@@ -17,7 +17,6 @@ from django.contrib.sessions.middleware import SessionMiddleware
from django.core.urlresolvers import reverse
from django.test import TestCase
from django.test.client import RequestFactory, Client
from django.test.utils import override_settings
from mock import Mock, patch
from opaque_keys.edx.locations import SlashSeparatedCourseKey
......@@ -49,13 +48,6 @@ log = logging.getLogger(__name__)
class CourseEndingTest(TestCase):
"""Test things related to course endings: certificates, surveys, etc"""
def setUp(self):
super(CourseEndingTest, self).setUp()
# Clear the model-based config cache to avoid
# interference between tests.
cache.clear()
def test_process_survey_link(self):
username = "fred"
user = Mock(username=username)
......@@ -198,118 +190,6 @@ class CourseEndingTest(TestCase):
}
self.assertIsNone(_cert_info(user, course2, cert_status, course_mode))
def test_linked_in_url_with_unicode_course_display_name(self):
"""Test with unicode display name values."""
user = Mock(username="fred")
survey_url = "http://a_survey.com"
course = Mock(
end_of_course_survey_url=survey_url,
certificates_display_behavior='end',
display_name=u'edx/abc/courseregisters®'
)
download_url = 'http://s3.edx/cert'
cert_status = {
'status': 'downloadable', 'grade': '67',
'download_url': download_url,
'mode': 'honor'
}
LinkedInAddToProfileConfiguration(
company_identifier='0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9',
enabled=True
).save()
status_dict = _cert_info(user, course, cert_status, 'honor')
expected_url = (
'http://www.linkedin.com/profile/add'
'?_ed=0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9&'
'pfCertificationName=edX+Honor+Code+Certificate+for+edx%2Fabc%2Fcourseregisters%C2%AE&'
'pfCertificationUrl=http%3A%2F%2Fs3.edx%2Fcert&'
'source=o'
)
self.assertEqual(expected_url, status_dict['linked_in_url'])
def test_linked_in_url_not_exists_without_config(self):
user = Mock(username="fred")
survey_url = "http://a_survey.com"
course = Mock(
display_name="Demo Course",
end_of_course_survey_url=survey_url,
certificates_display_behavior='end'
)
download_url = 'http://s3.edx/cert'
cert_status = {
'status': 'downloadable', 'grade': '67',
'download_url': download_url,
'mode': 'verified'
}
self.assertEqual(
_cert_info(user, course, cert_status, 'verified'),
{
'status': 'ready',
'show_disabled_download_button': False,
'show_download_url': True,
'download_url': download_url,
'show_survey_button': True,
'survey_url': survey_url,
'grade': '67',
'mode': 'verified',
'linked_in_url': None
}
)
# Enabling the configuration will cause the LinkedIn
# "add to profile" button to appear.
# We need to clear the cache again to make sure we
# pick up the modified configuration.
cache.clear()
LinkedInAddToProfileConfiguration(
company_identifier='0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9',
enabled=True
).save()
status_dict = _cert_info(user, course, cert_status, 'honor')
expected_url = (
'http://www.linkedin.com/profile/add'
'?_ed=0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9&'
'pfCertificationName=edX+Verified+Certificate+for+Demo+Course&'
'pfCertificationUrl=http%3A%2F%2Fs3.edx%2Fcert&'
'source=o'
)
self.assertEqual(expected_url, status_dict['linked_in_url'])
@ddt.data(
('honor', 'edX Honor Code Certificate for DemoX'),
('verified', 'edX Verified Certificate for DemoX'),
('professional', 'edX Professional Certificate for DemoX'),
('default_mode', 'edX Certificate for DemoX')
)
@ddt.unpack
def test_linked_in_url_certificate_types(self, cert_mode, cert_name):
user = Mock(username="fred")
course = Mock(
display_name='DemoX',
end_of_course_survey_url='http://example.com',
certificates_display_behavior='end'
)
cert_status = {
'status': 'downloadable',
'grade': '67',
'download_url': 'http://edx.org',
'mode': cert_mode
}
LinkedInAddToProfileConfiguration(
company_identifier="abcd123",
enabled=True
).save()
status_dict = _cert_info(user, course, cert_status, cert_mode)
self.assertIn(cert_name.replace(' ', '+'), status_dict['linked_in_url'])
class DashboardTest(ModuleStoreTestCase):
"""
......@@ -518,10 +398,7 @@ class DashboardTest(ModuleStoreTestCase):
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
def test_linked_in_add_to_profile_btn_not_appearing_without_config(self):
"""
without linked-in config don't show Add Certificate to LinkedIn button
"""
# Without linked-in config don't show Add Certificate to LinkedIn button
self.client.login(username="jack", password="test")
CourseModeFactory.create(
......@@ -557,12 +434,8 @@ class DashboardTest(ModuleStoreTestCase):
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
def test_linked_in_add_to_profile_btn_with_certificate(self):
"""
If user has a certificate with valid linked-in config then Add Certificate to LinkedIn button
should be visible. and it has URL value with valid parameters.
"""
# If user has a certificate with valid linked-in config then Add Certificate to LinkedIn button
# should be visible. and it has URL value with valid parameters.
self.client.login(username="jack", password="test")
LinkedInAddToProfileConfiguration(
company_identifier='0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9',
......
......@@ -361,6 +361,7 @@ def _cert_info(user, course, cert_status, course_mode):
linkedin_config = LinkedInAddToProfileConfiguration.current()
if linkedin_config.enabled:
status_dict['linked_in_url'] = linkedin_config.add_to_profile_url(
course.id,
course.display_name,
cert_status.get('mode'),
cert_status['download_url']
......
"""Utility for testing certificate display.
This command will create a fake certificate for a user
in a course. The certificate will display on the student's
dashboard, but no PDF will be generated.
Example usage:
$ ./manage.py lms create_fake_cert test_user edX/DemoX/Demo_Course --mode honor --grade 0.89
"""
import logging
from django.core.management.base import BaseCommand, CommandError
from django.contrib.auth.models import User
from optparse import make_option
from opaque_keys.edx.keys import CourseKey
from certificates.models import GeneratedCertificate, CertificateStatuses
LOGGER = logging.getLogger(__name__)
class Command(BaseCommand):
"""Create a fake certificate for a user in a course. """
USAGE = u'Usage: create_fake_cert <USERNAME> <COURSE_KEY> --mode <MODE> --status <STATUS> --grade <GRADE>'
option_list = BaseCommand.option_list + (
make_option(
'-m', '--mode',
metavar='CERT_MODE',
dest='cert_mode',
default='honor',
help='The course mode of the certificate (e.g. "honor", "verified", or "professional")'
),
make_option(
'-s', '--status',
metavar='CERT_STATUS',
dest='status',
default=CertificateStatuses.downloadable,
help='The status of the certificate'
),
make_option(
'-g', '--grade',
metavar='CERT_GRADE',
dest='grade',
default='',
help='The grade for the course, as a decimal (e.g. "0.89" for 89%)'
),
)
def handle(self, *args, **options):
"""Create a fake certificate for a user.
Arguments:
username (unicode): Identifier for the certificate's user.
course_key (unicode): Identifier for the certificate's course.
Keyword Arguments:
cert_mode (str): The mode of the certificate (e.g "honor")
status (str): The status of the certificate (e.g. "downloadable")
grade (str): The grade of the certificate (e.g "0.89" for 89%)
Raises:
CommandError
"""
if len(args) < 2:
raise CommandError(self.USAGE)
user = User.objects.get(username=args[0])
course_key = CourseKey.from_string(args[1])
cert_mode = options.get('cert_mode', 'honor')
status = options.get('status', CertificateStatuses.downloadable)
grade = options.get('grade', '')
cert, created = GeneratedCertificate.objects.get_or_create(
user=user,
course_id=course_key
)
cert.mode = cert_mode
cert.status = status
cert.grade = grade
if status == CertificateStatuses.downloadable:
cert.download_uuid = 'test'
cert.verify_uuid = 'test'
cert.download_url = 'http://www.example.com'
cert.save()
if created:
LOGGER.info(
u"Created certificate for user %s in course %s "
u"with mode %s, status %s, "
u"and grade %s",
user.id, unicode(course_key),
cert_mode, status, grade
)
else:
LOGGER.info(
u"Updated certificate for user %s in course %s "
u"with mode %s, status %s, "
u"and grade %s",
user.id, unicode(course_key),
cert_mode, status, grade
)
"""Tests for the create_fake_certs management command. """
from django.test import TestCase
from django.core.management.base import CommandError
from opaque_keys.edx.locator import CourseLocator
from student.tests.factories import UserFactory
from certificates.management.commands import create_fake_cert
from certificates.models import GeneratedCertificate
class CreateFakeCertTest(TestCase):
"""Tests for the create_fake_certs management command. """
USERNAME = "test"
COURSE_KEY = CourseLocator(org='edX', course='DemoX', run='Demo_Course')
def setUp(self):
super(CreateFakeCertTest, self).setUp()
self.user = UserFactory.create(username=self.USERNAME)
def test_create_fake_cert(self):
# No existing cert, so create it
self._run_command(
self.USERNAME,
unicode(self.COURSE_KEY),
cert_mode='verified',
grade='0.89'
)
cert = GeneratedCertificate.objects.get(user=self.user, course_id=self.COURSE_KEY)
self.assertEqual(cert.status, 'downloadable')
self.assertEqual(cert.mode, 'verified')
self.assertEqual(cert.grade, '0.89')
self.assertEqual(cert.download_uuid, 'test')
self.assertEqual(cert.download_url, 'http://www.example.com')
# Cert already exists; modify it
self._run_command(
self.USERNAME,
unicode(self.COURSE_KEY),
cert_mode='honor'
)
cert = GeneratedCertificate.objects.get(user=self.user, course_id=self.COURSE_KEY)
self.assertEqual(cert.mode, 'honor')
def test_too_few_args(self):
with self.assertRaisesRegexp(CommandError, 'Usage'):
self._run_command(self.USERNAME)
def _run_command(self, *args, **kwargs):
"""Run the management command to generate a fake cert. """
command = create_fake_cert.Command()
return command.handle(*args, **kwargs)
......@@ -51,6 +51,21 @@
// Track clicks of the "verify now" button.
window.analytics.trackLink(verifyButtonLinks, 'edx.bi.user.verification.resumed', generateProperties);
// Track clicks of the LinkedIn "Add to Profile" button
window.analytics.trackLink(
$('.action-linkedin-profile'),
'edx.bi.user.linkedin_add_to_profile',
function( element ) {
var $el = $( element );
return {
category: 'linkedin',
label: $el.data('course-id'),
mode: $el.data('certificate-mode')
};
}
);
// Generate the properties object to be passed along with business intelligence events.
function generateProperties(element) {
var $el = $(element),
......
......@@ -612,8 +612,11 @@
// ====================
// UI: message
.message {
.wrapper-message-primary {
@include clearfix();
}
.message {
border-radius: 3px;
display: none;
z-index: 10;
......@@ -887,13 +890,18 @@
}
&.course-status-processing {
background-color: $gray-l5;
border: 0;
}
&.course-status-certnotavailable {
background-color: $gray-l5;
border: 0;
}
&.course-status-certrendering {
background-color: $gray-l5;
border: 0;
.cta {
margin-top: 2px;
......@@ -907,10 +915,10 @@
.message-copy {
width: flex-grid(6, 12);
position: relative;
float: left;
@include float(left);
}
.actions {
.actions-primary {
width: flex-grid(6, 12);
position: relative;
@include float(right);
......@@ -950,6 +958,24 @@
}
}
.actions-secondary {
margin-top: ($baseline/2);
border-top: 1px solid $gray-l4;
padding-top: ($baseline/2);
.action-share {
@include float(right);
margin: 0;
}
}
.certificate-explanation {
@extend %t-copy-sub1;
margin-top: ($baseline/2);
border-top: 1px solid $gray-l4;
padding-top: ($baseline/2);
}
.verification-reminder {
width: flex-grid(8, 12);
position: relative;
......
<%page args="cert_status, course, enrollment" />
<%! from django.utils.translation import ugettext as _ %>
<%namespace name='static' file='../static_content.html'/>
<%
cert_name_short = course.cert_name_short
......@@ -25,61 +26,76 @@ else:
<div class="message message-status ${status_css_class} is-shown">
% if cert_status['status'] == 'processing':
<p class="message-copy">${_("Final course details are being wrapped up at this time. Your final standing will be available shortly.")}</p>
<p class="message-copy">${_("Final course details are being wrapped up at this time. Your final standing will be available shortly.")}</p>
% elif cert_status['status'] in ('generating', 'ready', 'notpassing', 'restricted'):
<p class="message-copy">${_("Your final grade:")}
<span class="grade-value">${"{0:.0f}%".format(float(cert_status['grade'])*100)}</span>.
% if cert_status['status'] == 'notpassing' and enrollment.mode != 'audit':
${_("Grade required for a {cert_name_short}:").format(cert_name_short=cert_name_short)} <span class="grade-value">
${"{0:.0f}%".format(float(course.lowest_passing_grade)*100)}</span>.
% elif cert_status['status'] == 'restricted' and enrollment.mode == 'verified':
<p class="message-copy">
${_("Your verified {cert_name_long} is being held pending confirmation that the issuance of your {cert_name_short} is in compliance with strict U.S. embargoes on Iran, Cuba, Syria and Sudan. If you think our system has mistakenly identified you as being connected with one of those countries, please let us know by contacting {email}. If you would like a refund on your {cert_name_long}, please contact our billing address {billing_email}").format(email='<a class="contact-link" href="mailto:{email}">{email}</a>.'.format(email=settings.CONTACT_EMAIL), billing_email='<a class="contact-link" href="mailto:{email}">{email}</a>'.format(email=settings.PAYMENT_SUPPORT_EMAIL), cert_name_short=cert_name_short, cert_name_long=cert_name_long)}
</p>
% elif cert_status['status'] == 'restricted':
<p class="message-copy">
${_("Your {cert_name_long} is being held pending confirmation that the issuance of your {cert_name_short} is in compliance with strict U.S. embargoes on Iran, Cuba, Syria and Sudan. If you think our system has mistakenly identified you as being connected with one of those countries, please let us know by contacting {email}.").format(email='<a class="contact-link" href="mailto:{email}">{email}</a>.'.format(email=settings.CONTACT_EMAIL), cert_name_short=cert_name_short, cert_name_long=cert_name_long)}
</p>
% endif
</p>
<p class="message-copy">${_("Your final grade:")}
<span class="grade-value">${"{0:.0f}%".format(float(cert_status['grade'])*100)}</span>.
% if cert_status['status'] == 'notpassing' and enrollment.mode != 'audit':
${_("Grade required for a {cert_name_short}:").format(cert_name_short=cert_name_short)} <span class="grade-value">
${"{0:.0f}%".format(float(course.lowest_passing_grade)*100)}</span>.
% elif cert_status['status'] == 'restricted' and enrollment.mode == 'verified':
<p class="message-copy">
${_("Your verified {cert_name_long} is being held pending confirmation that the issuance of your {cert_name_short} is in compliance with strict U.S. embargoes on Iran, Cuba, Syria and Sudan. If you think our system has mistakenly identified you as being connected with one of those countries, please let us know by contacting {email}. If you would like a refund on your {cert_name_long}, please contact our billing address {billing_email}").format(email='<a class="contact-link" href="mailto:{email}">{email}</a>.'.format(email=settings.CONTACT_EMAIL), billing_email='<a class="contact-link" href="mailto:{email}">{email}</a>'.format(email=settings.PAYMENT_SUPPORT_EMAIL), cert_name_short=cert_name_short, cert_name_long=cert_name_long)}
</p>
% elif cert_status['status'] == 'restricted':
<p class="message-copy">
${_("Your {cert_name_long} is being held pending confirmation that the issuance of your {cert_name_short} is in compliance with strict U.S. embargoes on Iran, Cuba, Syria and Sudan. If you think our system has mistakenly identified you as being connected with one of those countries, please let us know by contacting {email}.").format(email='<a class="contact-link" href="mailto:{email}">{email}</a>.'.format(email=settings.CONTACT_EMAIL), cert_name_short=cert_name_short, cert_name_long=cert_name_long)}
</p>
% endif
</p>
% endif
% if cert_status['show_disabled_download_button'] or cert_status['show_download_url'] or cert_status['show_survey_button']:
<ul class="actions">
% if cert_status['show_disabled_download_button']:
<li class="action"><span class="disabled">
${_("Your {cert_name_short} is Generating").format(cert_name_short=cert_name_short)}</span></li>
% elif cert_status['show_download_url'] and (enrollment.mode == 'honor' or enrollment.mode == 'audit'):
<li class="action action-certificate">
<a class="btn" href="${cert_status['download_url']}"
title="${_('This link will open/download a PDF document')}">
${_("Download {cert_name_short} (PDF)").format(cert_name_short=cert_name_short,)}</a></li>
% if cert_status['linked_in_url']:
<li class="action action-share">
<a class="btn" target="_blank" href="${cert_status['linked_in_url']}"
title="${_('Add Certificate to LinkedIn Profile')}">
${_("Share on LinkedIn")}</a></li>
% endif
<div class="wrapper-message-primary">
<ul class="actions actions-primary">
% if cert_status['show_disabled_download_button']:
<li class="action"><span class="disabled">
${_("Your {cert_name_short} is Generating").format(cert_name_short=cert_name_short)}</span></li>
% elif cert_status['show_download_url'] and (enrollment.mode == 'honor' or enrollment.mode == 'audit'):
<li class="action action-certificate">
<a class="btn" href="${cert_status['download_url']}"
title="${_('This link will open/download a PDF document')}">
${_("Download {cert_name_short} (PDF)").format(cert_name_short=cert_name_short,)}</a></li>
% elif cert_status['show_download_url'] and enrollment.mode == 'verified' and cert_status['mode'] == 'honor':
<li class="action">
<a class="btn" href="${cert_status['download_url']}"
title="${_('This link will open/download a PDF document')}">
${_("Download Your {cert_name_short} (PDF)").format(cert_name_short=cert_name_short)}</a></li>
% elif cert_status['show_download_url'] and enrollment.mode == 'verified':
<li class="action">
<a class="btn" href="${cert_status['download_url']}"
title="${_('This link will open/download a PDF document of your verified {cert_name_long}.').format(cert_name_long=cert_name_long)}">
${_("Download Your ID Verified {cert_name_short} (PDF)").format(cert_name_short=cert_name_short)}</a></li>
% endif
% elif cert_status['show_download_url'] and enrollment.mode == 'verified' and cert_status['mode'] == 'honor':
<li class="action">
<p>${_('Since we did not have a valid set of verification photos from you when your {cert_name_long} was generated, we could not grant you a verified {cert_name_short}. An honor code {cert_name_short} has been granted instead.').format(cert_name_short=cert_name_short, cert_name_long=cert_name_long)}</p>
<a class="btn" href="${cert_status['download_url']}"
title="${_('This link will open/download a PDF document')}">
${_("Download Your {cert_name_short} (PDF)").format(cert_name_short=cert_name_short)}</a></li>
% elif cert_status['show_download_url'] and enrollment.mode == 'verified':
<li class="action">
<a class="btn" href="${cert_status['download_url']}"
title="${_('This link will open/download a PDF document of your verified {cert_name_long}.').format(cert_name_long=cert_name_long)}">
${_("Download Your ID Verified {cert_name_short} (PDF)").format(cert_name_short=cert_name_short)}</a></li>
% endif
% if cert_status['show_survey_button']:
<li class="action"><a class="cta" href="${cert_status['survey_url']}">
${_("Complete our course feedback survey")}</a></li>
% endif
</ul>
</div>
% if cert_status['show_survey_button']:
<li class="action"><a class="cta" href="${cert_status['survey_url']}">
${_("Complete our course feedback survey")}</a></li>
% endif
% if cert_status['show_download_url'] and cert_status['linked_in_url']:
<ul class="actions actions-secondary">
<li class="action action-share">
<a class="action action-linkedin-profile" target="_blank" href="${cert_status['linked_in_url']}"
title="${_('Add Certificate to LinkedIn Profile')}"
data-course-id="${unicode(course.id)}"
data-certificate-mode="${cert_status['mode']}"
>
<img class="action-linkedin-profile-img"
src="${static.url('images/linkedin_add_to_profile.png')}"
alt="${_('Share on LinkedIn')}">
</a>
</li>
</ul>
% endif
% if cert_status['show_download_url'] and enrollment.mode == 'verified' and cert_status['mode'] == 'honor':
<div class="certificate-explanation">
${_('Since we did not have a valid set of verification photos from you when your {cert_name_long} was generated, we could not grant you a verified {cert_name_short}. An honor code {cert_name_short} has been granted instead.').format(cert_name_short=cert_name_short, cert_name_long=cert_name_long)}
</div>
% endif
% endif
</div>
......@@ -136,7 +136,7 @@ from student.helpers import (
% endif
% if verification_status.get('status') in [VERIFY_STATUS_NEED_TO_VERIFY, VERIFY_STATUS_SUBMITTED, VERIFY_STATUS_APPROVED, VERIFY_STATUS_NEED_TO_REVERIFY] and not is_course_blocked:
<div class="message message-status is-shown">
<div class="message message-status wrapper-message-primary is-shown">
% if verification_status['status'] == VERIFY_STATUS_NEED_TO_VERIFY:
<div class="verification-reminder">
% if verification_status['days_until_deadline'] is not None:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment