Merge pull request #8448 from edx/ziafazal/SOL-886
certificates event tracking SOL-886
This commit is contained in:
46
common/test/acceptance/fixtures/certificates.py
Normal file
46
common/test/acceptance/fixtures/certificates.py
Normal file
@@ -0,0 +1,46 @@
|
||||
"""
|
||||
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
|
||||
52
common/test/acceptance/pages/lms/certificate_page.py
Normal file
52
common/test/acceptance/pages/lms/certificate_page.py
Normal file
@@ -0,0 +1,52 @@
|
||||
# -*- 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')
|
||||
@@ -0,0 +1,86 @@
|
||||
"""
|
||||
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)
|
||||
76
common/test/db_fixtures/certificates_web_view.json
Normal file
76
common/test/db_fixtures/certificates_web_view.json
Normal file
@@ -0,0 +1,76 @@
|
||||
[
|
||||
{
|
||||
"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
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from eventtracking import tracker
|
||||
|
||||
from xmodule.modulestore.django import modulestore
|
||||
|
||||
from certificates.models import (
|
||||
CertificateStatuses as cert_status,
|
||||
CertificateStatuses,
|
||||
certificate_status_for_student,
|
||||
CertificateGenerationCourseSetting,
|
||||
CertificateGenerationConfiguration,
|
||||
@@ -24,13 +26,14 @@ from certificates.queue import XQueueCertInterface
|
||||
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.
|
||||
|
||||
A new record will be created to track 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:
|
||||
student (User)
|
||||
@@ -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
|
||||
it will be loaded.
|
||||
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()
|
||||
if insecure:
|
||||
xqueue.use_https = False
|
||||
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,
|
||||
@@ -95,11 +109,12 @@ def certificate_downloadable_status(student, course_key):
|
||||
|
||||
response_data = {
|
||||
'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
|
||||
}
|
||||
|
||||
if current_status['status'] == cert_status.downloadable:
|
||||
if current_status['status'] == CertificateStatuses.downloadable:
|
||||
response_data['is_downloadable'] = True
|
||||
response_data['download_url'] = current_status['download_url']
|
||||
|
||||
@@ -259,3 +274,26 @@ def get_active_web_certificate(course, is_preview_mode=None):
|
||||
if config.get('is_active') or is_preview_mode:
|
||||
return config
|
||||
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):
|
||||
unavailable = 'unavailable'
|
||||
|
||||
|
||||
class CertificateSocialNetworks(object):
|
||||
"""
|
||||
Enum for certificate social networks
|
||||
"""
|
||||
linkedin = 'LinkedIn'
|
||||
facebook = 'Facebook'
|
||||
twitter = 'Twitter'
|
||||
|
||||
|
||||
class CertificateWhitelist(models.Model):
|
||||
"""
|
||||
Tracks students who are whitelisted, all users
|
||||
@@ -139,10 +148,11 @@ class GeneratedCertificate(models.Model):
|
||||
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
|
||||
course milestone entry if user has passed the course
|
||||
or certificate status is 'generating'.
|
||||
course milestone entry if user has passed the course.
|
||||
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)
|
||||
|
||||
|
||||
|
||||
@@ -187,7 +187,8 @@ class XQueueCertInterface(object):
|
||||
will be skipped.
|
||||
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',
|
||||
'deleted' or 'generating' state.
|
||||
@@ -201,7 +202,7 @@ class XQueueCertInterface(object):
|
||||
If a student does not have a passing grade the status
|
||||
will change to status.notpassing
|
||||
|
||||
Returns the student's status
|
||||
Returns the student's status and newly created certificate instance
|
||||
"""
|
||||
|
||||
valid_statuses = [
|
||||
@@ -215,6 +216,7 @@ class XQueueCertInterface(object):
|
||||
|
||||
cert_status = certificate_status_for_student(student, course_id)['status']
|
||||
new_status = cert_status
|
||||
cert = None
|
||||
|
||||
if cert_status not in valid_statuses:
|
||||
LOGGER.warning(
|
||||
@@ -389,7 +391,7 @@ class XQueueCertInterface(object):
|
||||
new_status
|
||||
)
|
||||
|
||||
return new_status
|
||||
return new_status, cert
|
||||
|
||||
def add_example_cert(self, example_cert):
|
||||
"""Add a task to create an example certificate.
|
||||
|
||||
@@ -15,6 +15,7 @@ from student.models import CourseEnrollment
|
||||
from student.tests.factories import UserFactory
|
||||
from course_modes.tests.factories import CourseModeFactory
|
||||
from config_models.models import cache
|
||||
from util.testing import EventTestMixin
|
||||
|
||||
from certificates import api as certs_api
|
||||
from certificates.models import (
|
||||
@@ -112,15 +113,19 @@ class CertificateDownloadableStatusTests(ModuleStoreTestCase):
|
||||
|
||||
@attr('shard_1')
|
||||
@override_settings(CERT_QUEUE='certificates')
|
||||
class GenerateUserCertificatesTest(ModuleStoreTestCase):
|
||||
class GenerateUserCertificatesTest(EventTestMixin, ModuleStoreTestCase):
|
||||
"""Tests for generating certificates for students. """
|
||||
|
||||
ERROR_REASON = "Kaboom!"
|
||||
|
||||
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.course = CourseFactory.create(
|
||||
org='edx',
|
||||
@@ -139,6 +144,15 @@ class GenerateUserCertificatesTest(ModuleStoreTestCase):
|
||||
# Verify that the certificate has status 'generating'
|
||||
cert = GeneratedCertificate.objects.get(user=self.student, course_id=self.course.id)
|
||||
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):
|
||||
with self._mock_passing_grade():
|
||||
|
||||
@@ -27,7 +27,8 @@ from certificates.models import (
|
||||
GeneratedCertificate,
|
||||
BadgeAssertion,
|
||||
CertificateStatuses,
|
||||
CertificateHtmlViewConfiguration
|
||||
CertificateHtmlViewConfiguration,
|
||||
CertificateSocialNetworks,
|
||||
)
|
||||
|
||||
from certificates.tests.factories import (
|
||||
@@ -593,11 +594,36 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase):
|
||||
def test_render_html_view_invalid_certificate_configuration(self):
|
||||
test_url = get_certificate_url(
|
||||
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)
|
||||
self.assertIn("Invalid Certificate", response.content)
|
||||
|
||||
@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):
|
||||
test_url = get_certificate_url(user_id=self.user.id, course_id=self.course_id) + '?evidence_visit=1'
|
||||
|
||||
@@ -17,15 +17,21 @@ from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.decorators.http import require_POST
|
||||
|
||||
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 (
|
||||
certificate_status_for_student,
|
||||
CertificateStatuses,
|
||||
GeneratedCertificate,
|
||||
ExampleCertificate,
|
||||
CertificateHtmlViewConfiguration,
|
||||
BadgeAssertion)
|
||||
from certificates.queue import XQueueCertInterface
|
||||
CertificateSocialNetworks,
|
||||
BadgeAssertion
|
||||
)
|
||||
from edxmako.shortcuts import render_to_response
|
||||
from util.views import ensure_valid_course_key
|
||||
from xmodule.modulestore.django import modulestore
|
||||
@@ -588,6 +594,14 @@ def render_html_view(request, user_id, course_id):
|
||||
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)
|
||||
|
||||
|
||||
@@ -1337,7 +1337,7 @@ def generate_user_cert(request, course_id):
|
||||
# mark the certificate with "error" status, so it can be re-run
|
||||
# with a management command. From the user's perspective,
|
||||
# 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)
|
||||
return HttpResponse()
|
||||
|
||||
|
||||
@@ -1318,6 +1318,11 @@ ccx_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/ccx/**/*.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 = {
|
||||
'style-vendor': {
|
||||
@@ -1538,6 +1543,10 @@ PIPELINE_JS = {
|
||||
'discovery': {
|
||||
'source_filenames': discovery_js,
|
||||
'output_filename': 'js/discovery.js'
|
||||
},
|
||||
'certificates_wv': {
|
||||
'source_filenames': certificates_web_view_js,
|
||||
'output_filename': 'js/certificates/web_view.js'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<%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">
|
||||
<section class="banner banner-user">
|
||||
@@ -34,4 +58,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user