MICROBA-921 Move emit_certificate_event() to utils (#26133)

This commit is contained in:
Christie Rice
2021-01-26 14:41:34 -05:00
committed by GitHub
parent e3cfaab487
commit b1e5695acf
7 changed files with 176 additions and 137 deletions

View File

@@ -9,13 +9,11 @@ rather than importing Django models directly.
import logging
import six
from django.conf import settings
from django.db.models import Q
from django.urls import reverse
from eventtracking import tracker
from opaque_keys.edx.django.models import CourseKeyField
from opaque_keys.edx.keys import CourseKey
from organizations.api import get_course_organization_id
from xmodule.modulestore.django import modulestore
from lms.djangoapps.branding import api as branding_api
from lms.djangoapps.certificates.models import (
@@ -30,10 +28,12 @@ from lms.djangoapps.certificates.models import (
certificate_status_for_student
)
from lms.djangoapps.certificates.queue import XQueueCertInterface
from lms.djangoapps.certificates.utils import emit_certificate_event as _emit_certificate_event
from lms.djangoapps.certificates.utils import get_certificate_url as _get_certificate_url
from lms.djangoapps.certificates.utils import has_html_certificates_enabled as _has_html_certificates_enabled
from lms.djangoapps.instructor.access import list_with_level
from openedx.core.djangoapps.certificates.api import certificates_viewable_for_course
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from xmodule.modulestore.django import modulestore
log = logging.getLogger("edx.certificate")
MODES = GeneratedCertificate.MODES
@@ -234,7 +234,7 @@ def generate_user_certificates(student, course_key, course=None, insecure=False,
return
if CertificateStatuses.is_passing_status(cert.status):
emit_certificate_event('created', student, course_key, course, {
_emit_certificate_event('created', student, course_key, course, {
'user_id': student.id,
'course_id': six.text_type(course_key),
'certificate_id': cert.verify_uuid,
@@ -458,7 +458,7 @@ def example_certificates_status(course_key):
Example Usage:
>>> from lms.djangoapps.certificates import api as certs_api
>>> certs_api.example_certificate_status(course_key)
>>> certs_api.example_certificates_status(course_key)
[
{
'description': 'honor',
@@ -476,63 +476,12 @@ def example_certificates_status(course_key):
return ExampleCertificateSet.latest_status(course_key)
def _safe_course_key(course_key):
if not isinstance(course_key, CourseKey):
return CourseKey.from_string(course_key)
return course_key
def _course_from_key(course_key):
return CourseOverview.get_from_id(_safe_course_key(course_key))
def _certificate_html_url(uuid):
"""
Returns uuid based certificate URL.
"""
return reverse(
'certificates:render_cert_by_uuid', kwargs={'certificate_uuid': uuid}
) if uuid else ''
def _certificate_download_url(user_id, course_id, user_certificate=None):
if not user_certificate:
try:
user_certificate = GeneratedCertificate.eligible_certificates.get(
user=user_id,
course_id=_safe_course_key(course_id)
)
except GeneratedCertificate.DoesNotExist:
log.critical(
u'Unable to lookup certificate\n'
u'user id: %s\n'
u'course: %s', six.text_type(user_id), six.text_type(course_id)
)
if user_certificate:
return user_certificate.download_url
return ''
def has_html_certificates_enabled(course):
if not settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False):
return False
return course.cert_html_view_enabled
return _has_html_certificates_enabled(course)
def get_certificate_url(user_id=None, course_id=None, uuid=None, user_certificate=None):
url = ''
course = _course_from_key(course_id)
if not course:
return url
if has_html_certificates_enabled(course):
url = _certificate_html_url(uuid)
else:
url = _certificate_download_url(user_id, course_id, user_certificate=user_certificate)
return url
return _get_certificate_url(user_id, course_id, uuid, user_certificate)
def get_active_web_certificate(course, is_preview_mode=None):
@@ -634,30 +583,6 @@ def _get_two_letter_language_code(language_code):
return language_code[:2]
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': six.text_type(course_id)
}
data = {
'user_id': user.id,
'course_id': six.text_type(course_id),
'certificate_url': get_certificate_url(user.id, course_id, uuid=event_data['certificate_id'])
}
event_data = event_data or {}
event_data.update(data)
with tracker.get_tracker().context(event_name, context):
tracker.emit(event_name, event_data)
def get_asset_url_by_slug(asset_slug):
"""
Returns certificate template asset url for given asset_slug.

View File

@@ -535,7 +535,7 @@ class GenerateUserCertificatesTest(EventTestMixin, WebCertificateTestMixin, Modu
ENABLED_SIGNALS = ['course_published']
def setUp(self): # pylint: disable=arguments-differ
super(GenerateUserCertificatesTest, self).setUp('lms.djangoapps.certificates.api.tracker')
super().setUp('lms.djangoapps.certificates.utils.tracker')
self.student = UserFactory.create(
email='joe_user@edx.org',

View File

@@ -15,13 +15,13 @@ from django.urls import reverse
from opaque_keys.edx.locator import CourseLocator
from six.moves import range
from lms.djangoapps.certificates.api import get_certificate_url
from lms.djangoapps.certificates.models import (
CertificateHtmlViewConfiguration,
ExampleCertificate,
ExampleCertificateSet,
GeneratedCertificate
)
from lms.djangoapps.certificates.utils import get_certificate_url
from openedx.core.djangoapps.site_configuration.tests.test_util import with_site_configuration
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from common.djangoapps.student.tests.factories import UserFactory

View File

@@ -4,7 +4,6 @@
import datetime
import json
from collections import OrderedDict
from urllib.parse import urlencode
from uuid import uuid4
@@ -26,7 +25,6 @@ from lms.djangoapps.badges.tests.factories import (
BadgeClassFactory,
CourseCompleteImageConfigurationFactory
)
from lms.djangoapps.certificates.api import get_certificate_url
from lms.djangoapps.certificates.models import (
CertificateGenerationCourseSetting,
CertificateHtmlViewConfiguration,
@@ -36,6 +34,7 @@ from lms.djangoapps.certificates.models import (
CertificateTemplateAsset,
GeneratedCertificate
)
from lms.djangoapps.certificates.utils import get_certificate_url
from lms.djangoapps.certificates.tests.factories import (
CertificateHtmlViewConfigurationFactory,
GeneratedCertificateFactory,
@@ -1005,7 +1004,7 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase)
response_json = json.loads(response.content.decode('utf-8'))
self.assertEqual(CertificateStatuses.generating, response_json['add_status'])
#TEMPLATES WITHOUT LANGUAGE TESTS
# TEMPLATES WITHOUT LANGUAGE TESTS
@override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
@override_settings(LANGUAGE_CODE='fr')
@patch('lms.djangoapps.certificates.views.webview.get_course_run_details')
@@ -1126,8 +1125,8 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase)
self.assertContains(response, u'mode: {}'.format(mode))
self.assertContains(response, 'course name: test_template_1_course')
## Templates With Language tests
#1
# Templates With Language tests
# 1
@override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
@override_settings(LANGUAGE_CODE='fr')
@patch('lms.djangoapps.certificates.views.webview.get_course_run_details')
@@ -1164,16 +1163,16 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase)
course_id=six.text_type(self.course.id),
uuid=self.cert.verify_uuid
)
#create a org_mode_and_coursekey template language=null
# Create an org_mode_and_coursekey template language=null
self._create_custom_named_template(
'test_null_lang_template', org_id=1, mode='honor', course_key=six.text_type(self.course.id), language=None,
)
#verify return template lang = null
# Verify return template lang = null
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_null_lang_template')
#create a org_mode_and_coursekey template language=wrong_language
# Create an org_mode_and_coursekey template language=wrong_language
self._create_custom_named_template(
'test_wrong_lang_template',
org_id=1,
@@ -1181,12 +1180,12 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase)
course_key=six.text_type(self.course.id),
language=wrong_language,
)
#verify returns null lang template
# Verify returns null lang template
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_null_lang_template')
#create an org_mode_and_coursekey template language=''
# Create an org_mode_and_coursekey template language=''
self._create_custom_named_template(
'test_all_languages_template',
org_id=1,
@@ -1194,12 +1193,12 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase)
course_key=six.text_type(self.course.id),
language='',
)
#verify returns null lang template
# Verify returns null lang template
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_all_languages_template')
#create a org_mode_and_coursekey template language=lang
# Create a org_mode_and_coursekey template language=lang
self._create_custom_named_template(
'test_right_lang_template',
org_id=1,
@@ -1212,7 +1211,7 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_right_lang_template')
#2
# 2
@override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
@patch('lms.djangoapps.certificates.views.webview.get_course_run_details')
@patch('lms.djangoapps.certificates.api.get_course_organization_id')
@@ -1244,35 +1243,35 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase)
course_id=six.text_type(self.course.id),
uuid=self.cert.verify_uuid
)
#create a org and mode template language=null
# Create a org and mode template language=null
self._create_custom_named_template('test_null_lang_template', org_id=1, mode='honor', language=None)
#verify return template lang = null
# Verify return template lang = null
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_null_lang_template')
#create a org and mode template language=wrong_language
# Create a org and mode template language=wrong_language
self._create_custom_named_template('test_wrong_lang_template', org_id=1, mode='honor', language=wrong_language)
#verify returns null lang template
# Verify returns null lang template
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_null_lang_template')
#create an org and mode template language=''
# Create an org and mode template language=''
self._create_custom_named_template('test_all_languages_template', org_id=1, mode='honor', language='')
#verify returns All Languages template
# Verify returns All Languages template
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_all_languages_template')
#create a org and mode template language=lang
# Create a org and mode template language=lang
self._create_custom_named_template('test_right_lang_template', org_id=1, mode='honor', language=right_language)
# verify return right_language template
# Verify return right_language template
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_right_lang_template')
#3
# 3
@override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
@patch('lms.djangoapps.certificates.views.webview.get_course_run_details')
@patch('lms.djangoapps.certificates.api.get_course_organization_id')
@@ -1302,35 +1301,35 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase)
course_id=six.text_type(self.course.id),
uuid=self.cert.verify_uuid
)
#create a org template language=null
# Create a org template language=null
self._create_custom_named_template('test_null_lang_template', org_id=1, language=None)
#verify return template lang = null
# Verify return template lang = null
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_null_lang_template')
#create a org template language=wrong_language
# Create a org template language=wrong_language
self._create_custom_named_template('test_wrong_lang_template', org_id=1, language=wrong_language)
#verify returns null lang template
# Verify returns null lang template
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_null_lang_template')
#create an org template language=''
# Create an org template language=''
self._create_custom_named_template('test_all_languages_template', org_id=1, language='')
#verify returns All Languages template
# Verify returns All Languages template
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_all_languages_template')
#create a org template language=lang
# Create a org template language=lang
self._create_custom_named_template('test_right_lang_template', org_id=1, language=right_language)
# verify return right_language template
# Verify return right_language template
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_right_lang_template')
#4
# 4
@override_settings(FEATURES=FEATURES_WITH_CUSTOM_CERTS_ENABLED)
@patch('lms.djangoapps.certificates.views.webview.get_course_run_details')
@patch('lms.djangoapps.certificates.api.get_course_organization_id')
@@ -1361,30 +1360,30 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase)
course_id=six.text_type(self.course.id),
uuid=self.cert.verify_uuid
)
#create a mode template language=null
# Create a mode template language=null
self._create_custom_named_template('test_null_lang_template', mode='honor', language=None)
#verify return template with lang = null
# Verify return template with lang = null
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_null_lang_template')
#create a mode template language=wrong_language
# Create a mode template language=wrong_language
self._create_custom_named_template('test_wrong_lang_template', mode='honor', language=wrong_language)
#verify returns null lang template
# Verify returns null lang template
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_null_lang_template')
#create a mode template language=''
# Create a mode template language=''
self._create_custom_named_template('test_all_languages_template', mode='honor', language='')
#verify returns All Languages template
# Verify returns All Languages template
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_all_languages_template')
#create a mode template language=lang
# Create a mode template language=lang
self._create_custom_named_template('test_right_lang_template', mode='honor', language=right_language)
# verify return right_language template
# Verify return right_language template
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_right_lang_template')
@@ -1423,28 +1422,28 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase)
course_id=six.text_type(self.course.id),
uuid=self.cert.verify_uuid
)
#create a mode template language=null
# Create a mode template language=null
self._create_custom_named_template('test_null_lang_template', org_id=1, mode='honor', language=None)
#verify return template with lang = null
# Verify return template with lang = null
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_null_lang_template')
#create a mode template language=wrong_language
# Create a mode template language=wrong_language
self._create_custom_named_template('test_wrong_lang_template', org_id=1, mode='honor', language=wrong_language)
#verify returns null lang template
# Verify returns null lang template
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_null_lang_template')
#create a mode template language=''
# Create a mode template language=''
self._create_custom_named_template('test_all_languages_template', org_id=1, mode='honor', language='')
#verify returns All Languages template
# Verify returns All Languages template
response = self.client.get(test_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'course name: test_all_languages_template')
#create a mode template language=lang
# Create a mode template language=lang
self._create_custom_named_template('test_right_lang_template', org_id=1, mode='honor', language=right_language)
# verify return right_language template
response = self.client.get(test_url)

View File

@@ -0,0 +1,117 @@
"""
Certificates utilities
"""
import logging
import six
from django.conf import settings
from django.urls import reverse
from eventtracking import tracker
from opaque_keys.edx.keys import CourseKey
from xmodule.modulestore.django import modulestore
from lms.djangoapps.certificates.models import (
GeneratedCertificate
)
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
log = logging.getLogger(__name__)
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': six.text_type(course_id)
}
data = {
'user_id': user.id,
'course_id': six.text_type(course_id),
'certificate_url': get_certificate_url(user.id, course_id, uuid=event_data['certificate_id'])
}
event_data = event_data or {}
event_data.update(data)
with tracker.get_tracker().context(event_name, context):
tracker.emit(event_name, event_data)
def get_certificate_url(user_id=None, course_id=None, uuid=None, user_certificate=None):
"""
Returns the certificate URL
"""
url = ''
course = _course_from_key(course_id)
if not course:
return url
if has_html_certificates_enabled(course):
url = _certificate_html_url(uuid)
else:
url = _certificate_download_url(user_id, course_id, user_certificate=user_certificate)
return url
def has_html_certificates_enabled(course):
"""
Returns True if HTML certificates are enabled
"""
if not settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False):
return False
return course.cert_html_view_enabled
def _certificate_html_url(uuid):
"""
Returns uuid based certificate URL.
"""
return reverse(
'certificates:render_cert_by_uuid', kwargs={'certificate_uuid': uuid}
) if uuid else ''
def _certificate_download_url(user_id, course_id, user_certificate=None):
"""
Returns the certificate download URL
"""
if not user_certificate:
try:
user_certificate = GeneratedCertificate.eligible_certificates.get(
user=user_id,
course_id=_safe_course_key(course_id)
)
except GeneratedCertificate.DoesNotExist:
log.critical(
u'Unable to lookup certificate\n'
u'user id: %s\n'
u'course: %s', six.text_type(user_id), six.text_type(course_id)
)
if user_certificate:
return user_certificate.download_url
return ''
def _course_from_key(course_key):
"""
Returns the course overview
"""
return CourseOverview.get_from_id(_safe_course_key(course_key))
def _safe_course_key(course_key):
"""
Returns the course key
"""
if not isinstance(course_key, CourseKey):
return CourseKey.from_string(course_key)
return course_key

View File

@@ -27,12 +27,10 @@ from lms.djangoapps.badges.utils import badges_enabled
from common.djangoapps.edxmako.shortcuts import render_to_response
from common.djangoapps.edxmako.template import Template
from lms.djangoapps.certificates.api import (
emit_certificate_event,
get_active_web_certificate,
get_certificate_footer_context,
get_certificate_header_context,
get_certificate_template,
get_certificate_url
get_certificate_template
)
from lms.djangoapps.certificates.models import (
CertificateGenerationCourseSetting,
@@ -42,6 +40,7 @@ from lms.djangoapps.certificates.models import (
GeneratedCertificate
)
from lms.djangoapps.certificates.permissions import PREVIEW_CERTIFICATES
from lms.djangoapps.certificates.utils import emit_certificate_event, get_certificate_url
from lms.djangoapps.courseware.courses import get_course_by_id
from openedx.core.djangoapps.catalog.utils import get_course_run_details
from openedx.core.djangoapps.certificates.api import certificates_viewable_for_course, display_date_for_certificate
@@ -430,7 +429,7 @@ def _update_organization_context(context, course):
partner_short_name = course.display_organization if course.display_organization else course.org
organizations = organizations_api.get_course_organizations(course_key=course.id)
if organizations:
#TODO Need to add support for multiple organizations, Currently we are interested in the first one.
# TODO Need to add support for multiple organizations, Currently we are interested in the first one.
organization = organizations[0]
partner_long_name = organization.get('name', partner_long_name)
partner_short_name = organization.get('short_name', partner_short_name)

View File

@@ -57,7 +57,6 @@ from xmodule.modulestore.tests.django_utils import (
)
from xmodule.modulestore.tests.factories import CourseFactory as ModuleStoreCourseFactory
CERTIFICATES_API_MODULE = 'lms.djangoapps.certificates.api'
ECOMMERCE_URL_ROOT = 'https://ecommerce.example.com'
UTILS_MODULE = 'openedx.core.djangoapps.programs.utils'
LOGGER_NAME = 'openedx.core.djangoapps.programs.utils'
@@ -932,7 +931,7 @@ class TestProgramDataExtender(ModuleStoreTestCase):
@ddt.data(True, False)
@mock.patch(UTILS_MODULE + '.certificate_api.certificate_downloadable_status')
@mock.patch(CERTIFICATES_API_MODULE + '.has_html_certificates_enabled')
@mock.patch('lms.djangoapps.certificates.utils.has_html_certificates_enabled')
def test_certificate_url_retrieval(self, is_uuid_available, mock_html_certs_enabled, mock_get_cert_data):
"""
Verify that the student's run mode certificate is included,