Commit c3b78ea9 by Matt Drayer

Merge pull request #8448 from edx/ziafazal/SOL-886

certificates event tracking SOL-886
parents c28003b5 6afaa3cc
"""
Tools for creating certificates config fixture data.
"""
import json
from . import STUDIO_BASE_URL
from .base import StudioApiFixture
class CertificateConfigFixtureError(Exception):
"""
Error occurred while installing certificate config fixture.
"""
pass
class CertificateConfigFixture(StudioApiFixture):
"""
Fixture to create certificates configuration for a course
"""
certificates = []
def __init__(self, course_id, certificates_data):
self.course_id = course_id
self.certificates = certificates_data
super(CertificateConfigFixture, self).__init__()
def install(self):
"""
Push the certificates config data to certificate endpoint.
"""
response = self.session.post(
'{}/certificates/{}'.format(STUDIO_BASE_URL, self.course_id),
data=json.dumps(self.certificates),
headers=self.headers
)
if not response.ok:
raise CertificateConfigFixtureError(
"Could not create certificate {0}. Status was {1}".format(
json.dumps(self.certificates), response.status_code
)
)
return self
# -*- coding: utf-8 -*-
"""
Module for Certificates pages.
"""
from bok_choy.page_object import PageObject
from . import BASE_URL
class CertificatePage(PageObject):
"""
Certificate web view page.
"""
url_path = "certificates"
def __init__(self, browser, user_id, course_id):
"""Initialize the page.
Arguments:
browser (Browser): The browser instance.
user_id: id of the user whom certificate is awarded
course_id: course key of the course where certificate is awarded
"""
super(CertificatePage, self).__init__(browser)
self.user_id = user_id
self.course_id = course_id
def is_browser_on_page(self):
""" Checks if certificate web view page is being viewed """
return self.q(css='section.about-accomplishments').present
@property
def url(self):
"""
Construct a URL to the page
"""
return BASE_URL + "/" + self.url_path + "/user/" + self.user_id + "/course/" + self.course_id
@property
def accomplishment_banner(self):
"""
returns accomplishment banner.
"""
return self.q(css='section.banner-user')
@property
def add_to_linkedin_profile_button(self):
"""
returns add to LinkedIn profile button
"""
return self.q(css='a.action-linkedin-profile')
"""
Acceptance tests for the certificate web view feature.
"""
from ..helpers import UniqueCourseTest, EventsTestMixin
from nose.plugins.attrib import attr
from ...fixtures.course import CourseFixture
from ...fixtures.certificates import CertificateConfigFixture
from ...pages.lms.auto_auth import AutoAuthPage
from ...pages.lms.certificate_page import CertificatePage
@attr('shard_5')
class CertificateWebViewTest(EventsTestMixin, UniqueCourseTest):
"""
Tests for verifying certificate web view features
"""
def setUp(self):
super(CertificateWebViewTest, self).setUp()
# set same course number as we have in fixture json
self.course_info['number'] = "335535897951379478207964576572017930000"
test_certificate_config = {
'id': 1,
'name': 'Certificate name',
'description': 'Certificate description',
'course_title': 'Course title override',
'signatories': [],
'version': 1,
'is_active': True
}
course_settings = {'certificates': test_certificate_config}
self.course_fixture = CourseFixture(
self.course_info["org"],
self.course_info["number"],
self.course_info["run"],
self.course_info["display_name"],
settings=course_settings
)
self.course_fixture.install()
self.user_id = "99" # we have createad a user with this id in fixture
self.cert_fixture = CertificateConfigFixture(self.course_id, test_certificate_config)
# Load certificate web view page for use by the tests
self.certificate_page = CertificatePage(self.browser, self.user_id, self.course_id)
def log_in_as_unique_user(self):
"""
Log in as a valid lms user.
"""
AutoAuthPage(
self.browser,
username="testcert",
email="cert@example.com",
password="testuser",
course_id=self.course_id
).visit()
def test_page_has_accomplishments_banner(self):
"""
Scenario: User accomplishment banner should be present if logged in user is the one who is awarded
the certificate
Given there is a course with certificate configuration
And I have passed the course and certificate is generated
When I view the certificate web view page
Then I should see the accomplishment banner
And When I click on `Add to Profile` button `edx.certificate.shared` event should be emitted
"""
self.cert_fixture.install()
self.log_in_as_unique_user()
self.certificate_page.visit()
self.assertTrue(self.certificate_page.accomplishment_banner.visible)
self.assertTrue(self.certificate_page.add_to_linkedin_profile_button.visible)
self.certificate_page.add_to_linkedin_profile_button.click()
actual_events = self.wait_for_events(
event_filter={'event_type': 'edx.certificate.shared'},
number_of_matches=1
)
expected_events = [
{
'event': {
'user_id': self.user_id,
'course_id': self.course_id
}
}
]
self.assert_events_match(expected_events, actual_events)
[
{
"pk": 99,
"model": "auth.user",
"fields": {
"date_joined": "2015-06-12 11:02:13",
"username": "testcert",
"first_name": "john",
"last_name": "doe",
"email":"cert@example.com",
"password": "testuser",
"is_staff": false,
"is_active": true
}
},
{
"pk": 99,
"model": "student.userprofile",
"fields": {
"user": 99,
"name": "test cert",
"courseware": "course.xml",
"allow_certificate": true
}
},
{
"pk": 99,
"model": "student.registration",
"fields": {
"user": 99,
"activation_key": "52bfac10384d49219385dcd4cc17177p"
}
},
{
"pk": 2,
"model": "certificates.certificatehtmlviewconfiguration",
"fields": {
"change_date": "2050-05-15 11:02:13",
"changed_by": 99,
"enabled": true,
"configuration": "{\"default\": {\"accomplishment_class_append\": \"accomplishment-certificate\",\"platform_name\": \"edX\",\"company_privacy_url\": \"http://www.edx.org/edx-privacy-policy\",\"company_about_url\": \"http://www.edx.org/about-us\",\"company_tos_url\": \"http://www.edx.org/edx-terms-service\",\"company_verified_certificate_url\": \"http://www.edx.org/verified-certificate\",\"document_stylesheet_url_application\": \"/static/certificates/sass/main-ltr.css\",\"logo_src\": \"/static/certificates/images/logo-edx.svg\",\"logo_url\": \"http://www.edx.org\"},\"honor\": {\"certificate_type\": \"Honor Code\",\"document_body_class_append\": \"is-honorcode\"},\"verified\": {\"certificate_type\": \"Verified\",\"document_body_class_append\": \"is-idverified\"},\"xseries\": {\"certificate_type\": \"XSeries\",\"document_body_class_append\": \"is-xseries\"}}"
}
},
{
"pk": 1,
"model": "certificates.generatedcertificate",
"fields": {
"user": 99,
"download_url": "http://www.edx.org/certificates/downloand",
"grade": "0.8",
"course_id": "course-v1:test_org+335535897951379478207964576572017930000+test_run",
"key": "",
"distinction": true,
"status": "downloadable",
"verify_uuid": "52bfac10394d49219385dcd4cc17177e",
"download_uuid": "52bfac10394d49219385dcd4cc17177r",
"name": "testcert",
"created_date": "2015-06-12 11:02:13",
"modified_date": "2015-06-12 11:02:13",
"error_reason": "",
"mode": "honor"
}
},
{
"pk": 1,
"model": "student.linkedinaddtoprofileconfiguration",
"fields": {
"change_date": "2050-06-15 11:02:13",
"changed_by": 99,
"enabled": true,
"dashboard_tracking_code": "edx-course-v1&TESTCOURSE",
"company_identifier": "7nTFLiuDkkQkdELSpruCwD4F6jzqtTFsx3PfJUIT2qHqXRLG1",
"trk_partner_name": "edx"
}
}
]
...@@ -9,10 +9,12 @@ import logging ...@@ -9,10 +9,12 @@ import logging
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from eventtracking import tracker
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
from certificates.models import ( from certificates.models import (
CertificateStatuses as cert_status, CertificateStatuses,
certificate_status_for_student, certificate_status_for_student,
CertificateGenerationCourseSetting, CertificateGenerationCourseSetting,
CertificateGenerationConfiguration, CertificateGenerationConfiguration,
...@@ -24,13 +26,14 @@ from certificates.queue import XQueueCertInterface ...@@ -24,13 +26,14 @@ from certificates.queue import XQueueCertInterface
log = logging.getLogger("edx.certificate") log = logging.getLogger("edx.certificate")
def generate_user_certificates(student, course_key, course=None, insecure=False): def generate_user_certificates(student, course_key, course=None, insecure=False, generation_mode='batch'):
""" """
It will add the add-cert request into the xqueue. It will add the add-cert request into the xqueue.
A new record will be created to track the certificate A new record will be created to track the certificate
generation task. If an error occurs while adding the certificate generation task. If an error occurs while adding the certificate
to the queue, the task will have status 'error'. to the queue, the task will have status 'error'. It also emits
`edx.certificate.created` event for analytics.
Args: Args:
student (User) student (User)
...@@ -40,12 +43,23 @@ def generate_user_certificates(student, course_key, course=None, insecure=False) ...@@ -40,12 +43,23 @@ def generate_user_certificates(student, course_key, course=None, insecure=False)
course (Course): Optionally provide the course object; if not provided course (Course): Optionally provide the course object; if not provided
it will be loaded. it will be loaded.
insecure - (Boolean) insecure - (Boolean)
generation_mode - who has requested certificate generation. Its value should `batch`
in case of django command and `self` if student initiated the request.
""" """
xqueue = XQueueCertInterface() xqueue = XQueueCertInterface()
if insecure: if insecure:
xqueue.use_https = False xqueue.use_https = False
generate_pdf = not has_html_certificates_enabled(course_key, course) generate_pdf = not has_html_certificates_enabled(course_key, course)
return xqueue.add_cert(student, course_key, course=course, generate_pdf=generate_pdf) status, cert = xqueue.add_cert(student, course_key, course=course, generate_pdf=generate_pdf)
if status in [CertificateStatuses.generating, CertificateStatuses.downloadable]:
emit_certificate_event('created', student, course_key, course, {
'user_id': student.id,
'course_id': unicode(course_key),
'certificate_id': cert.verify_uuid,
'enrollment_mode': cert.mode,
'generation_mode': generation_mode
})
return status
def regenerate_user_certificates(student, course_key, course=None, def regenerate_user_certificates(student, course_key, course=None,
...@@ -95,11 +109,12 @@ def certificate_downloadable_status(student, course_key): ...@@ -95,11 +109,12 @@ def certificate_downloadable_status(student, course_key):
response_data = { response_data = {
'is_downloadable': False, 'is_downloadable': False,
'is_generating': True if current_status['status'] in [cert_status.generating, cert_status.error] else False, 'is_generating': True if current_status['status'] in [CertificateStatuses.generating,
CertificateStatuses.error] else False,
'download_url': None 'download_url': None
} }
if current_status['status'] == cert_status.downloadable: if current_status['status'] == CertificateStatuses.downloadable:
response_data['is_downloadable'] = True response_data['is_downloadable'] = True
response_data['download_url'] = current_status['download_url'] response_data['download_url'] = current_status['download_url']
...@@ -259,3 +274,26 @@ def get_active_web_certificate(course, is_preview_mode=None): ...@@ -259,3 +274,26 @@ def get_active_web_certificate(course, is_preview_mode=None):
if config.get('is_active') or is_preview_mode: if config.get('is_active') or is_preview_mode:
return config return config
return None return None
def emit_certificate_event(event_name, user, course_id, course=None, event_data=None):
"""
Emits certificate event.
"""
event_name = '.'.join(['edx', 'certificate', event_name])
if course is None:
course = modulestore().get_course(course_id, depth=0)
context = {
'org_id': course.org,
'course_id': unicode(course_id)
}
data = {
'user_id': user.id,
'course_id': unicode(course_id),
'certificate_url': get_certificate_url(user.id, course_id)
}
event_data = event_data or {}
event_data.update(data)
with tracker.get_tracker().context(event_name, context):
tracker.emit(event_name, event_data)
...@@ -81,6 +81,15 @@ class CertificateStatuses(object): ...@@ -81,6 +81,15 @@ class CertificateStatuses(object):
unavailable = 'unavailable' unavailable = 'unavailable'
class CertificateSocialNetworks(object):
"""
Enum for certificate social networks
"""
linkedin = 'LinkedIn'
facebook = 'Facebook'
twitter = 'Twitter'
class CertificateWhitelist(models.Model): class CertificateWhitelist(models.Model):
""" """
Tracks students who are whitelisted, all users Tracks students who are whitelisted, all users
...@@ -139,10 +148,11 @@ class GeneratedCertificate(models.Model): ...@@ -139,10 +148,11 @@ class GeneratedCertificate(models.Model):
def handle_post_cert_generated(sender, instance, **kwargs): # pylint: disable=no-self-argument, unused-argument def handle_post_cert_generated(sender, instance, **kwargs): # pylint: disable=no-self-argument, unused-argument
""" """
Handles post_save signal of GeneratedCertificate, and mark user collected Handles post_save signal of GeneratedCertificate, and mark user collected
course milestone entry if user has passed the course course milestone entry if user has passed the course.
or certificate status is 'generating'. User is assumed to have passed the course if certificate status is either 'generating' or 'downloadable'.
""" """
if settings.FEATURES.get('ENABLE_PREREQUISITE_COURSES') and instance.status == CertificateStatuses.generating: allowed_cert_states = [CertificateStatuses.generating, CertificateStatuses.downloadable]
if settings.FEATURES.get('ENABLE_PREREQUISITE_COURSES') and instance.status in allowed_cert_states:
fulfill_course_milestone(instance.course_id, instance.user) fulfill_course_milestone(instance.course_id, instance.user)
......
...@@ -187,7 +187,8 @@ class XQueueCertInterface(object): ...@@ -187,7 +187,8 @@ class XQueueCertInterface(object):
will be skipped. will be skipped.
generate_pdf - Boolean should a message be sent in queue to generate certificate PDF generate_pdf - Boolean should a message be sent in queue to generate certificate PDF
Will change the certificate status to 'generating'. Will change the certificate status to 'generating' or
`downloadable` in case of web view certificates.
Certificate must be in the 'unavailable', 'error', Certificate must be in the 'unavailable', 'error',
'deleted' or 'generating' state. 'deleted' or 'generating' state.
...@@ -201,7 +202,7 @@ class XQueueCertInterface(object): ...@@ -201,7 +202,7 @@ class XQueueCertInterface(object):
If a student does not have a passing grade the status If a student does not have a passing grade the status
will change to status.notpassing will change to status.notpassing
Returns the student's status Returns the student's status and newly created certificate instance
""" """
valid_statuses = [ valid_statuses = [
...@@ -215,6 +216,7 @@ class XQueueCertInterface(object): ...@@ -215,6 +216,7 @@ class XQueueCertInterface(object):
cert_status = certificate_status_for_student(student, course_id)['status'] cert_status = certificate_status_for_student(student, course_id)['status']
new_status = cert_status new_status = cert_status
cert = None
if cert_status not in valid_statuses: if cert_status not in valid_statuses:
LOGGER.warning( LOGGER.warning(
...@@ -389,7 +391,7 @@ class XQueueCertInterface(object): ...@@ -389,7 +391,7 @@ class XQueueCertInterface(object):
new_status new_status
) )
return new_status return new_status, cert
def add_example_cert(self, example_cert): def add_example_cert(self, example_cert):
"""Add a task to create an example certificate. """Add a task to create an example certificate.
......
...@@ -15,6 +15,7 @@ from student.models import CourseEnrollment ...@@ -15,6 +15,7 @@ from student.models import CourseEnrollment
from student.tests.factories import UserFactory from student.tests.factories import UserFactory
from course_modes.tests.factories import CourseModeFactory from course_modes.tests.factories import CourseModeFactory
from config_models.models import cache from config_models.models import cache
from util.testing import EventTestMixin
from certificates import api as certs_api from certificates import api as certs_api
from certificates.models import ( from certificates.models import (
...@@ -112,15 +113,19 @@ class CertificateDownloadableStatusTests(ModuleStoreTestCase): ...@@ -112,15 +113,19 @@ class CertificateDownloadableStatusTests(ModuleStoreTestCase):
@attr('shard_1') @attr('shard_1')
@override_settings(CERT_QUEUE='certificates') @override_settings(CERT_QUEUE='certificates')
class GenerateUserCertificatesTest(ModuleStoreTestCase): class GenerateUserCertificatesTest(EventTestMixin, ModuleStoreTestCase):
"""Tests for generating certificates for students. """ """Tests for generating certificates for students. """
ERROR_REASON = "Kaboom!" ERROR_REASON = "Kaboom!"
def setUp(self): def setUp(self):
super(GenerateUserCertificatesTest, self).setUp() super(GenerateUserCertificatesTest, self).setUp('certificates.api.tracker')
self.student = UserFactory() self.student = UserFactory.create(
email='joe_user@edx.org',
username='joeuser',
password='foo'
)
self.student_no_cert = UserFactory() self.student_no_cert = UserFactory()
self.course = CourseFactory.create( self.course = CourseFactory.create(
org='edx', org='edx',
...@@ -139,6 +144,15 @@ class GenerateUserCertificatesTest(ModuleStoreTestCase): ...@@ -139,6 +144,15 @@ class GenerateUserCertificatesTest(ModuleStoreTestCase):
# Verify that the certificate has status 'generating' # Verify that the certificate has status 'generating'
cert = GeneratedCertificate.objects.get(user=self.student, course_id=self.course.id) cert = GeneratedCertificate.objects.get(user=self.student, course_id=self.course.id)
self.assertEqual(cert.status, CertificateStatuses.generating) self.assertEqual(cert.status, CertificateStatuses.generating)
self.assert_event_emitted(
'edx.certificate.created',
user_id=self.student.id,
course_id=unicode(self.course.id),
certificate_url=certs_api.get_certificate_url(self.student.id, self.course.id),
certificate_id=cert.verify_uuid,
enrollment_mode=cert.mode,
generation_mode='batch'
)
def test_xqueue_submit_task_error(self): def test_xqueue_submit_task_error(self):
with self._mock_passing_grade(): with self._mock_passing_grade():
......
...@@ -27,7 +27,8 @@ from certificates.models import ( ...@@ -27,7 +27,8 @@ from certificates.models import (
GeneratedCertificate, GeneratedCertificate,
BadgeAssertion, BadgeAssertion,
CertificateStatuses, CertificateStatuses,
CertificateHtmlViewConfiguration CertificateHtmlViewConfiguration,
CertificateSocialNetworks,
) )
from certificates.tests.factories import ( from certificates.tests.factories import (
...@@ -593,12 +594,37 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): ...@@ -593,12 +594,37 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase):
def test_render_html_view_invalid_certificate_configuration(self): def test_render_html_view_invalid_certificate_configuration(self):
test_url = get_certificate_url( test_url = get_certificate_url(
user_id=self.user.id, user_id=self.user.id,
course_id=unicode(self.course.id) # pylint: disable=no-member course_id=unicode(self.course.id)
) )
response = self.client.get(test_url) response = self.client.get(test_url)
self.assertIn("Invalid Certificate", response.content) self.assertIn("Invalid Certificate", response.content)
@override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED) @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
def test_certificate_evidence_event_emitted(self):
self.client.logout()
self._add_course_certificates(count=1, signatory_count=2)
self.recreate_tracker()
test_url = get_certificate_url(
user_id=self.user.id,
course_id=unicode(self.course.id)
)
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
actual_event = self.get_event()
self.assertEqual(actual_event['name'], 'edx.certificate.evidence_visited')
assert_event_matches(
{
'user_id': self.user.id,
'certificate_id': unicode(self.cert.verify_uuid),
'enrollment_mode': self.cert.mode,
'certificate_url': test_url,
'course_id': unicode(self.course.id),
'social_network': CertificateSocialNetworks.linkedin
},
actual_event['data']
)
@override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
def test_evidence_event_sent(self): def test_evidence_event_sent(self):
test_url = get_certificate_url(user_id=self.user.id, course_id=self.course_id) + '?evidence_visit=1' test_url = get_certificate_url(user_id=self.user.id, course_id=self.course_id) + '?evidence_visit=1'
self.recreate_tracker() self.recreate_tracker()
......
...@@ -17,15 +17,21 @@ from django.views.decorators.csrf import csrf_exempt ...@@ -17,15 +17,21 @@ from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST from django.views.decorators.http import require_POST
from capa.xqueue_interface import XQUEUE_METRIC_NAME from capa.xqueue_interface import XQUEUE_METRIC_NAME
from certificates.api import get_active_web_certificate, get_certificate_url, generate_user_certificates from certificates.api import (
get_active_web_certificate,
get_certificate_url,
generate_user_certificates,
emit_certificate_event
)
from certificates.models import ( from certificates.models import (
certificate_status_for_student, certificate_status_for_student,
CertificateStatuses, CertificateStatuses,
GeneratedCertificate, GeneratedCertificate,
ExampleCertificate, ExampleCertificate,
CertificateHtmlViewConfiguration, CertificateHtmlViewConfiguration,
BadgeAssertion) CertificateSocialNetworks,
from certificates.queue import XQueueCertInterface BadgeAssertion
)
from edxmako.shortcuts import render_to_response from edxmako.shortcuts import render_to_response
from util.views import ensure_valid_course_key from util.views import ensure_valid_course_key
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
...@@ -588,6 +594,14 @@ def render_html_view(request, user_id, course_id): ...@@ -588,6 +594,14 @@ def render_html_view(request, user_id, course_id):
if microsite_config_key: if microsite_config_key:
context.update(configuration.get(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 # Append/Override the existing view context values with any course-specific static values from Advanced Settings
context.update(course.cert_html_view_overrides) context.update(course.cert_html_view_overrides)
......
...@@ -1337,7 +1337,7 @@ def generate_user_cert(request, course_id): ...@@ -1337,7 +1337,7 @@ def generate_user_cert(request, course_id):
# mark the certificate with "error" status, so it can be re-run # mark the certificate with "error" status, so it can be re-run
# with a management command. From the user's perspective, # with a management command. From the user's perspective,
# it will appear that the certificate task was submitted successfully. # it will appear that the certificate task was submitted successfully.
certs_api.generate_user_certificates(student, course.id) certs_api.generate_user_certificates(student, course.id, course=course, generation_mode='self')
_track_successful_certificate_generation(student.id, course.id) _track_successful_certificate_generation(student.id, course.id)
return HttpResponse() return HttpResponse()
......
...@@ -1318,6 +1318,11 @@ ccx_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/ccx/**/*.js')) ...@@ -1318,6 +1318,11 @@ ccx_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/ccx/**/*.js'))
discovery_js = ['js/discovery/main.js'] discovery_js = ['js/discovery/main.js']
certificates_web_view_js = [
'js/vendor/jquery.min.js',
'js/vendor/jquery.cookie.js',
'js/src/logger.js',
]
PIPELINE_CSS = { PIPELINE_CSS = {
'style-vendor': { 'style-vendor': {
...@@ -1538,6 +1543,10 @@ PIPELINE_JS = { ...@@ -1538,6 +1543,10 @@ PIPELINE_JS = {
'discovery': { 'discovery': {
'source_filenames': discovery_js, 'source_filenames': discovery_js,
'output_filename': 'js/discovery.js' 'output_filename': 'js/discovery.js'
},
'certificates_wv': {
'source_filenames': certificates_web_view_js,
'output_filename': 'js/certificates/web_view.js'
} }
} }
......
<%! from django.utils.translation import ugettext as _ %> <%! from django.utils.translation import ugettext as _ %>
<%namespace name='static' file='../static_content.html'/> <%namespace name='static' file='../static_content.html'/>
<%block name="js_extra">
<%static:js group='certificates_wv'/>
<script type="text/javascript">
$(document).ready(function() {
$.ajaxSetup({
headers: {
'X-CSRFToken': $.cookie('csrftoken')
},
dataType: 'json'
});
$(".action-linkedin-profile").click(function() {
var data = {
user_id: '${accomplishment_user_id}',
course_id: $(this).data('course-id'),
enrollment_mode: $(this).data('certificate-mode'),
certificate_id: '${certificate_id_number}',
certificate_url: window.location.href,
social_network: 'LinkedIn'
};
Logger.log('edx.certificate.shared', data);
});
});
</script>
</%block>
<div class="wrapper-banner wrapper-banner-user"> <div class="wrapper-banner wrapper-banner-user">
<section class="banner banner-user"> <section class="banner banner-user">
......
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