Commit a18e0c6b by Will Daly

Rename LinkedIn configuration field to "company_identifier"

Add "source" parameter to LinkedIn add-to-profile URL.

Add platform name to certification name.

Style changes for linked in sharing on dashboard
parent eb2d8c4e
...@@ -16,13 +16,13 @@ import json ...@@ -16,13 +16,13 @@ import json
import logging import logging
from pytz import UTC from pytz import UTC
import uuid import uuid
from collections import defaultdict from collections import defaultdict, OrderedDict
import dogstats_wrapper as dog_stats_api import dogstats_wrapper as dog_stats_api
from django.db.models import Q from django.db.models import Q
import pytz import pytz
from urllib import urlencode from urllib import urlencode
from django.utils.translation import ugettext_lazy from django.utils.translation import ugettext as _, ugettext_lazy
from django.conf import settings from django.conf import settings
from django.utils import timezone from django.utils import timezone
from django.contrib.auth.models import User from django.contrib.auth.models import User
...@@ -1442,28 +1442,56 @@ class DashboardConfiguration(ConfigurationModel): ...@@ -1442,28 +1442,56 @@ class DashboardConfiguration(ConfigurationModel):
class LinkedInAddToProfileConfiguration(ConfigurationModel): class LinkedInAddToProfileConfiguration(ConfigurationModel):
""" """
LinkedIn Add to Profile Configuration LinkedIn Add to Profile Configuration
This configuration enables the "Add to Profile" LinkedIn
button on the student dashboard. The button appears when
users have a certificate available; when clicked,
users are sent to the LinkedIn site with a pre-filled
form allowing them to add the certificate to their
LinkedIn profile.
""" """
# tracking code field
dashboard_tracking_code = models.TextField( MODE_TO_CERT_NAME = {
blank=True, "honor": ugettext_lazy(u"{platform_name} Honor Code Certificate for {course_name}"),
"verified": ugettext_lazy(u"{platform_name} Verified Certificate for {course_name}"),
"professional": ugettext_lazy(u"{platform_name} Professional Certificate for {course_name}"),
}
company_identifier = models.TextField(
help_text=ugettext_lazy( help_text=ugettext_lazy(
u"A dashboard tracking code field for LinkedIn Add-to-profile Certificates. " u"The company identifier for the LinkedIn Add-to-Profile button "
u"e.g 0_0dPSPyS070e0HsE9HNz_13_d11_" u"e.g 0_0dPSPyS070e0HsE9HNz_13_d11_"
) )
) )
@classmethod def add_to_profile_url(self, course_name, enrollment_mode, cert_url, source="o"):
def linked_in_dashboard_tracking_code_url(cls, params): """Construct the URL for the "add to profile" button.
"""
Get the linked-in Configuration.
"""
config = cls.current()
if config.enabled:
return u'http://www.linkedin.com/profile/add?_ed={tracking_code}&{params}'.format(
tracking_code=config.dashboard_tracking_code,
params=urlencode(params)
)
return None
def __unicode__(self): Arguments:
return self.dashboard_tracking_code course_name (unicode): The display name of the course.
enrollment_mode (str): The enrollment mode of the user (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)
"""
params = OrderedDict([
('_ed', self.company_identifier),
('pfCertificationName', self._cert_name(course_name, enrollment_mode).encode('utf-8')),
('pfCertificationUrl', cert_url),
('source', source)
])
return u'http://www.linkedin.com/profile/add?{params}'.format(
params=urlencode(params)
)
def _cert_name(self, course_name, enrollment_mode):
"""Name of the certification, for display on LinkedIn. """
return self.MODE_TO_CERT_NAME.get(
enrollment_mode,
_(u"{platform_name} Certificate for {course_name}")
).format(
platform_name=settings.PLATFORM_NAME,
course_name=course_name
)
...@@ -9,6 +9,7 @@ from datetime import datetime, timedelta ...@@ -9,6 +9,7 @@ from datetime import datetime, timedelta
import logging import logging
import pytz import pytz
import unittest import unittest
import ddt
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User, AnonymousUser from django.contrib.auth.models import User, AnonymousUser
...@@ -44,9 +45,17 @@ from config_models.models import cache ...@@ -44,9 +45,17 @@ from config_models.models import cache
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ddt.ddt
class CourseEndingTest(TestCase): class CourseEndingTest(TestCase):
"""Test things related to course endings: certificates, surveys, etc""" """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): def test_process_survey_link(self):
username = "fred" username = "fred"
user = Mock(username=username) user = Mock(username=username)
...@@ -194,8 +203,11 @@ class CourseEndingTest(TestCase): ...@@ -194,8 +203,11 @@ class CourseEndingTest(TestCase):
user = Mock(username="fred") user = Mock(username="fred")
survey_url = "http://a_survey.com" survey_url = "http://a_survey.com"
course = Mock(end_of_course_survey_url=survey_url, certificates_display_behavior='end') course = Mock(
course.display_name = u'edx/abc/courseregisters®' end_of_course_survey_url=survey_url,
certificates_display_behavior='end',
display_name=u'edx/abc/courseregisters®'
)
download_url = 'http://s3.edx/cert' download_url = 'http://s3.edx/cert'
cert_status = { cert_status = {
...@@ -204,25 +216,28 @@ class CourseEndingTest(TestCase): ...@@ -204,25 +216,28 @@ class CourseEndingTest(TestCase):
'mode': 'honor' 'mode': 'honor'
} }
LinkedInAddToProfileConfiguration( LinkedInAddToProfileConfiguration(
dashboard_tracking_code='0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9', company_identifier='0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9',
enabled=True).save() enabled=True
).save()
status_dict = _cert_info(user, course, cert_status, 'honor') status_dict = _cert_info(user, course, cert_status, 'honor')
self.assertIn( expected_url = (
'http://www.linkedin.com/profile/add?_ed=0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9', 'http://www.linkedin.com/profile/add'
status_dict['linked_in_url'] '?_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.assertIn('pfCertificationName', status_dict['linked_in_url']) self.assertEqual(expected_url, status_dict['linked_in_url'])
self.assertIn('pfCertificationUrl', status_dict['linked_in_url'])
self.assertIn('courseregisters', status_dict['linked_in_url'])
self.assertIn('Honor+Code+Certificate', status_dict['linked_in_url'])
def test_linked_in_url_not_exists_without_config(self): def test_linked_in_url_not_exists_without_config(self):
# Test case with Linked-In URL empty with if linked-in-config is none.
cache.clear()
user = Mock(username="fred") user = Mock(username="fred")
survey_url = "http://a_survey.com" survey_url = "http://a_survey.com"
course = Mock(end_of_course_survey_url=survey_url, certificates_display_behavior='end') course = Mock(
display_name="Demo Course",
end_of_course_survey_url=survey_url,
certificates_display_behavior='end'
)
download_url = 'http://s3.edx/cert' download_url = 'http://s3.edx/cert'
cert_status = { cert_status = {
...@@ -246,16 +261,54 @@ class CourseEndingTest(TestCase): ...@@ -246,16 +261,54 @@ class CourseEndingTest(TestCase):
} }
) )
# adding config. linked-in-url will be return # 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( LinkedInAddToProfileConfiguration(
dashboard_tracking_code='0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9', company_identifier='0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9',
enabled=True).save() enabled=True
).save()
status_dict = _cert_info(user, course, cert_status, 'honor') status_dict = _cert_info(user, course, cert_status, 'honor')
self.assertIn( expected_url = (
'http://www.linkedin.com/profile/add?_ed=0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9', 'http://www.linkedin.com/profile/add'
status_dict['linked_in_url'] '?_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): class DashboardTest(ModuleStoreTestCase):
...@@ -511,8 +564,10 @@ class DashboardTest(ModuleStoreTestCase): ...@@ -511,8 +564,10 @@ class DashboardTest(ModuleStoreTestCase):
""" """
self.client.login(username="jack", password="test") self.client.login(username="jack", password="test")
tracking_code = '0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9' LinkedInAddToProfileConfiguration(
LinkedInAddToProfileConfiguration(dashboard_tracking_code=tracking_code, enabled=True).save() company_identifier='0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9',
enabled=True
).save()
CourseModeFactory.create( CourseModeFactory.create(
course_id=self.course.id, course_id=self.course.id,
...@@ -542,14 +597,14 @@ class DashboardTest(ModuleStoreTestCase): ...@@ -542,14 +597,14 @@ class DashboardTest(ModuleStoreTestCase):
self.assertEquals(response.status_code, 200) self.assertEquals(response.status_code, 200)
self.assertIn('Add Certificate to LinkedIn', response.content) self.assertIn('Add Certificate to LinkedIn', response.content)
response_url = ( expected_url = (
'http://www.linkedin.com/profile/add?_ed=' 'http://www.linkedin.com/profile/add'
'{tracking_code}&pfCertificationUrl={download}&pfCertificationName=' '?_ed=0_mC_o2MizqdtZEmkVXjH4eYwMj4DnkCWrZP_D9&'
'Honor+Code+Certificate+for+{name}' 'pfCertificationName=edX+Honor+Code+Certificate+for+Omega&'
).format( 'pfCertificationUrl=www.edx.org&'
tracking_code=tracking_code, download=download_url, name='Omega' 'source=o'
) )
self.assertContains(response, response_url) self.assertContains(response, expected_url)
class EnrollInCourseTest(TestCase): class EnrollInCourseTest(TestCase):
......
...@@ -354,30 +354,16 @@ def _cert_info(user, course, cert_status, course_mode): ...@@ -354,30 +354,16 @@ def _cert_info(user, course, cert_status, course_mode):
else: else:
status_dict['download_url'] = cert_status['download_url'] status_dict['download_url'] = cert_status['download_url']
# getting linkedin URL and then pass the params which appears # If enabled, show the LinkedIn "add to profile" button
# on user profile. if linkedin config is empty don't show the button. # Clicking this button sends the user to LinkedIn where they
# can add the certificate information to their profile.
modes_dict = { linkedin_config = LinkedInAddToProfileConfiguration.current()
"honor": "Honor Code Certificate", if linkedin_config.enabled:
"verified": "Verified Certificate", status_dict['linked_in_url'] = linkedin_config.add_to_profile_url(
"professional": "Professional Certificate", course.display_name,
} cert_status.get('mode'),
cert_status['download_url']
certification_name = u'{type} for {course_name}'.format( )
type=modes_dict.get(course_mode, "Certificate"), course_name=course.display_name
).encode('utf-8')
params_dict = {
'pfCertificationName': certification_name,
'pfCertificationUrl': cert_status['download_url'],
}
# following method will construct and return url if current enabled config exists otherwise return None
# In case of None linked-in-button will not appear on dashboard.
status_dict['linked_in_url'] = LinkedInAddToProfileConfiguration.linked_in_dashboard_tracking_code_url(
params_dict
)
if status in ('generating', 'ready', 'notpassing', 'restricted'): if status in ('generating', 'ready', 'notpassing', 'restricted'):
if 'grade' not in cert_status: if 'grade' not in cert_status:
......
...@@ -901,11 +901,51 @@ ...@@ -901,11 +901,51 @@
} }
&.course-status-certavailable { &.course-status-certavailable {
background-color: $gray-l5;
border: 0;
.action-certificate { .message-copy {
width: flex-grid(6, 12);
position: relative;
float: left;
}
.btn { .actions {
width: flex-grid(6, 12);
position: relative;
@include float(right);
.action {
@include margin(0, 0, ($baseline/2), ($baseline*.75));
float: none;
text-align: center;
&:last-child {
margin-bottom: 0;
}
.btn {
float: none;
}
}
.action-certificate .btn {
@extend %btn-inherited-primary; @extend %btn-inherited-primary;
@include box-sizing(border-box);
float: none;
border-radius: 3px;
display: block;
@include padding(7px, ($baseline*.75), 7px, ($baseline*.75));
text-align: center;
a:link, a:visited {
color: #fff;
}
}
.action-share .btn {
display: inline;
letter-spacing: 0;
} }
} }
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
cert_name_short = course.cert_name_short cert_name_short = course.cert_name_short
if cert_name_short == "": if cert_name_short == "":
cert_name_short = settings.CERT_NAME_SHORT cert_name_short = settings.CERT_NAME_SHORT
cert_name_long = course.cert_name_long cert_name_long = course.cert_name_long
if cert_name_long == "": if cert_name_long == "":
cert_name_long = settings.CERT_NAME_LONG cert_name_long = settings.CERT_NAME_LONG
...@@ -53,13 +53,13 @@ else: ...@@ -53,13 +53,13 @@ else:
<li class="action action-certificate"> <li class="action action-certificate">
<a class="btn" href="${cert_status['download_url']}" <a class="btn" href="${cert_status['download_url']}"
title="${_('This link will open/download a PDF document')}"> title="${_('This link will open/download a PDF document')}">
${_("Download Your {cert_name_short} (PDF)").format(cert_name_short=cert_name_short,)}</a></li> ${_("Download {cert_name_short} (PDF)").format(cert_name_short=cert_name_short,)}</a></li>
% if cert_status['linked_in_url']: % if cert_status['linked_in_url']:
<li class="action action-certificate"> <li class="action action-share">
<a class="btn" target="_blank" href="${cert_status['linked_in_url']}" <a class="btn" target="_blank" href="${cert_status['linked_in_url']}"
title="${_('Add to LinkedIn Profile')}"> title="${_('Add Certificate to LinkedIn Profile')}">
${_("Add Certificate to LinkedIn.")}</a></li> ${_("Share on LinkedIn")}</a></li>
% endif % endif
% elif cert_status['show_download_url'] and enrollment.mode == 'verified' and cert_status['mode'] == 'honor': % elif cert_status['show_download_url'] and enrollment.mode == 'verified' and cert_status['mode'] == 'honor':
......
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