Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
edx-platform
Commits
8c6c4676
Commit
8c6c4676
authored
Sep 06, 2017
by
McKenzie Welter
Committed by
Dillon Dumesnil
Oct 31, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added util method to retrieve individual course_run data from Catalog
parent
efe3be83
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
116 additions
and
14 deletions
+116
-14
lms/djangoapps/certificates/api.py
+2
-2
lms/djangoapps/certificates/models.py
+1
-0
lms/djangoapps/certificates/tests/test_webview_views.py
+19
-7
lms/djangoapps/certificates/views/webview.py
+10
-3
openedx/core/djangoapps/catalog/tests/factories.py
+2
-0
openedx/core/djangoapps/catalog/tests/test_utils.py
+29
-0
openedx/core/djangoapps/catalog/utils.py
+36
-0
openedx/core/lib/edx_api_utils.py
+17
-2
No files found.
lms/djangoapps/certificates/api.py
View file @
8c6c4676
...
...
@@ -484,9 +484,9 @@ def get_active_web_certificate(course, is_preview_mode=None):
return
None
def
get_certificate_template
(
course_key
,
mode
):
def
get_certificate_template
(
course_key
,
mode
,
language
):
# pylint: disable=unused-argument
"""
Retrieves the custom certificate template based on course_key
and mod
e.
Retrieves the custom certificate template based on course_key
, mode, and languag
e.
"""
org_id
,
template
=
None
,
None
# fetch organization of the course
...
...
lms/djangoapps/certificates/models.py
View file @
8c6c4676
...
...
@@ -910,6 +910,7 @@ class CertificateGenerationCourseSetting(TimeStampedModel):
defaults
=
default
)
@classmethod
def
is_language_specific_templates_enabled_for_course
(
cls
,
course_key
):
"""Check whether language-specific certificates are enabled for a course.
...
...
lms/djangoapps/certificates/tests/test_webview_views.py
View file @
8c6c4676
...
...
@@ -13,7 +13,7 @@ from django.core.urlresolvers import reverse
from
django.test.client
import
Client
,
RequestFactory
from
django.test.utils
import
override_settings
from
util.date_utils
import
strftime_localized
from
mock
import
patch
from
mock
import
Mock
,
patch
from
nose.plugins.attrib
import
attr
from
certificates.api
import
get_certificate_url
...
...
@@ -884,11 +884,13 @@ class CertificatesViewsTests(CommonCertificatesTestCase):
@override_settings
(
FEATURES
=
FEATURES_WITH_CUSTOM_CERTS_ENABLED
)
@override_settings
(
LANGUAGE_CODE
=
'fr'
)
def
test_certificate_custom_template_with_org_mode_course
(
self
):
@patch
(
'certificates.views.webview.get_course_run_details'
)
def
test_certificate_custom_template_with_org_mode_course
(
self
,
mock_get_course_run_details
):
"""
Tests custom template search and rendering.
This test should check template matching when org={org}, course={course}, mode={mode}.
"""
mock_get_course_run_details
.
return_value
=
{
'language'
:
'en'
}
self
.
_add_course_certificates
(
count
=
1
,
signatory_count
=
2
)
self
.
_create_custom_template
(
org_id
=
1
,
mode
=
'honor'
,
course_key
=
unicode
(
self
.
course
.
id
))
self
.
_create_custom_template
(
org_id
=
2
,
mode
=
'honor'
)
...
...
@@ -913,12 +915,14 @@ class CertificatesViewsTests(CommonCertificatesTestCase):
self
.
assertContains
(
response
,
'course name: course_title_0'
)
@override_settings
(
FEATURES
=
FEATURES_WITH_CUSTOM_CERTS_ENABLED
)
def
test_certificate_custom_template_with_org
(
self
):
@patch
(
'certificates.views.webview.get_course_run_details'
)
def
test_certificate_custom_template_with_org
(
self
,
mock_get_course_run_details
):
"""
Tests custom template search if we have a single template for organization and mode
with course set to Null.
This test should check template matching when org={org}, course=Null, mode={mode}.
"""
mock_get_course_run_details
.
return_value
=
{
'language'
:
'en'
}
course
=
CourseFactory
.
create
(
org
=
'cstX'
,
number
=
'cst_22'
,
display_name
=
'custom template course'
)
...
...
@@ -940,11 +944,13 @@ class CertificatesViewsTests(CommonCertificatesTestCase):
self
.
assertContains
(
response
,
'course name: course_title_0'
)
@override_settings
(
FEATURES
=
FEATURES_WITH_CUSTOM_CERTS_ENABLED
)
def
test_certificate_custom_template_with_organization
(
self
):
@patch
(
'certificates.views.webview.get_course_run_details'
)
def
test_certificate_custom_template_with_organization
(
self
,
mock_get_course_run_details
):
"""
Tests custom template search when we have a single template for a organization.
This test should check template matching when org={org}, course=Null, mode=null.
"""
mock_get_course_run_details
.
return_value
=
{
'language'
:
'en'
}
self
.
_add_course_certificates
(
count
=
1
,
signatory_count
=
2
)
self
.
_create_custom_template
(
org_id
=
1
,
mode
=
'honor'
)
self
.
_create_custom_template
(
org_id
=
1
,
mode
=
'honor'
,
course_key
=
self
.
course
.
id
)
...
...
@@ -962,11 +968,13 @@ class CertificatesViewsTests(CommonCertificatesTestCase):
self
.
assertEqual
(
response
.
status_code
,
200
)
@override_settings
(
FEATURES
=
FEATURES_WITH_CUSTOM_CERTS_ENABLED
)
def
test_certificate_custom_template_with_course_mode
(
self
):
@patch
(
'certificates.views.webview.get_course_run_details'
)
def
test_certificate_custom_template_with_course_mode
(
self
,
mock_get_course_run_details
):
"""
Tests custom template search if we have a single template for a course mode.
This test should check template matching when org=null, course=Null, mode={mode}.
"""
mock_get_course_run_details
.
return_value
=
{
'language'
:
'en'
}
mode
=
'honor'
self
.
_add_course_certificates
(
count
=
1
,
signatory_count
=
2
)
self
.
_create_custom_template
(
mode
=
mode
)
...
...
@@ -982,10 +990,12 @@ class CertificatesViewsTests(CommonCertificatesTestCase):
self
.
assertContains
(
response
,
'mode: {}'
.
format
(
mode
))
@ddt.data
(
True
,
False
)
def
test_certificate_custom_template_with_unicode_data
(
self
,
custom_certs_enabled
):
@patch
(
'certificates.views.webview.get_course_run_details'
)
def
test_certificate_custom_template_with_unicode_data
(
self
,
custom_certs_enabled
,
mock_get_course_run_details
):
"""
Tests custom template renders properly with unicode data.
"""
mock_get_course_run_details
.
return_value
=
{
'language'
:
'en'
}
mode
=
'honor'
self
.
_add_course_certificates
(
count
=
1
,
signatory_count
=
2
)
self
.
_create_custom_template
(
mode
=
mode
)
...
...
@@ -1014,10 +1024,12 @@ class CertificatesViewsTests(CommonCertificatesTestCase):
self
.
assertContains
(
response
,
'https://twitter.com/intent/tweet'
)
@override_settings
(
FEATURES
=
FEATURES_WITH_CUSTOM_CERTS_ENABLED
)
def
test_certificate_asset_by_slug
(
self
):
@patch
(
'certificates.views.webview.get_course_run_details'
)
def
test_certificate_asset_by_slug
(
self
,
mock_get_course_run_details
):
"""
Tests certificate template asset display by slug using static.certificate_asset_url method.
"""
mock_get_course_run_details
.
return_value
=
{
'language'
:
'en'
}
self
.
_add_course_certificates
(
count
=
1
,
signatory_count
=
2
)
self
.
_create_custom_template
(
mode
=
'honor'
)
test_url
=
get_certificate_url
(
...
...
lms/djangoapps/certificates/views/webview.py
View file @
8c6c4676
...
...
@@ -30,6 +30,7 @@ from certificates.api import (
has_html_certificates_enabled
)
from
certificates.models
import
(
CertificateGenerationCourseSetting
,
CertificateHtmlViewConfiguration
,
CertificateSocialNetworks
,
CertificateStatuses
,
...
...
@@ -39,6 +40,7 @@ from courseware.access import has_access
from
courseware.courses
import
get_course_by_id
from
edxmako.shortcuts
import
render_to_response
from
edxmako.template
import
Template
from
openedx.core.djangoapps.catalog.utils
import
get_course_run_details
from
openedx.core.djangoapps.site_configuration
import
helpers
as
configuration_helpers
from
openedx.core.lib.courses
import
course_image_url
from
openedx.core.djangoapps.certificates.api
import
display_date_for_certificate
...
...
@@ -224,7 +226,7 @@ def _update_context_with_basic_info(context, course_id, platform_name, configura
)
def
_update_course_context
(
request
,
context
,
course
,
platform_name
):
def
_update_course_context
(
request
,
context
,
course
,
course_key
,
platform_name
):
"""
Updates context dictionary with course info.
"""
...
...
@@ -248,6 +250,11 @@ def _update_course_context(request, context, course, platform_name):
'{partner_short_name}.'
)
.
format
(
partner_short_name
=
context
[
'organization_short_name'
],
platform_name
=
platform_name
)
# If language specific templates are enabled for the course, add course_run specific information to the context
if
CertificateGenerationCourseSetting
.
is_language_specific_templates_enabled_for_course
(
course_key
):
fields
=
[
'start'
,
'end'
,
'max_effort'
,
'language'
]
course_run_data
=
get_course_run_details
(
course_key
,
fields
)
context
.
update
(
course_run_data
)
def
_update_social_context
(
request
,
context
,
course
,
user
,
user_certificate
,
platform_name
):
...
...
@@ -413,7 +420,7 @@ def _render_certificate_template(request, context, course, user_certificate):
Picks appropriate certificate templates and renders it.
"""
if
settings
.
FEATURES
.
get
(
'CUSTOM_CERTIFICATE_TEMPLATES_ENABLED'
,
False
):
custom_template
=
get_certificate_template
(
course
.
id
,
user_certificate
.
mode
)
custom_template
=
get_certificate_template
(
course
.
id
,
user_certificate
.
mode
,
context
.
get
(
'language'
)
)
if
custom_template
:
template
=
Template
(
custom_template
,
...
...
@@ -571,7 +578,7 @@ def render_html_view(request, user_id, course_id):
_update_organization_context
(
context
,
course
)
# Append course info
_update_course_context
(
request
,
context
,
course
,
platform_name
)
_update_course_context
(
request
,
context
,
course
,
course_key
,
platform_name
)
# Append user info
_update_context_with_user_info
(
context
,
user
,
user_certificate
)
...
...
openedx/core/djangoapps/catalog/tests/factories.py
View file @
8c6c4676
...
...
@@ -118,6 +118,8 @@ class CourseRunFactory(DictFactoryBase):
title
=
factory
.
Faker
(
'catch_phrase'
)
type
=
'verified'
uuid
=
factory
.
Faker
(
'uuid4'
)
language
=
'en'
max_effort
=
5
class
CourseFactory
(
DictFactoryBase
):
...
...
openedx/core/djangoapps/catalog/tests/test_utils.py
View file @
8c6c4676
...
...
@@ -15,6 +15,7 @@ from openedx.core.djangoapps.catalog.tests.factories import CourseRunFactory, Pr
from
openedx.core.djangoapps.catalog.tests.mixins
import
CatalogIntegrationMixin
from
openedx.core.djangoapps.catalog.utils
import
(
get_course_runs
,
get_course_run_details
,
get_program_types
,
get_programs
,
get_programs_with_type
...
...
@@ -304,3 +305,31 @@ class TestGetCourseRuns(CatalogIntegrationMixin, TestCase):
self
.
assertTrue
(
mock_get_edx_api_data
.
called
)
self
.
assert_contract
(
mock_get_edx_api_data
.
call_args
)
self
.
assertEqual
(
data
,
catalog_course_runs
)
@skip_unless_lms
@mock.patch
(
UTILS_MODULE
+
'.get_edx_api_data'
)
class
TestGetCourseRunDetails
(
CatalogIntegrationMixin
,
TestCase
):
"""
Tests covering retrieval of information about a specific course run from the catalog service.
"""
def
setUp
(
self
):
super
(
TestGetCourseRunDetails
,
self
)
.
setUp
()
self
.
catalog_integration
=
self
.
create_catalog_integration
(
cache_ttl
=
1
)
self
.
user
=
UserFactory
(
username
=
self
.
catalog_integration
.
service_username
)
def
test_get_course_run_details
(
self
,
mock_get_edx_api_data
):
"""
Test retrieval of details about a specific course run
"""
course_run
=
CourseRunFactory
()
course_run_details
=
{
'language'
:
course_run
[
'language'
],
'start'
:
course_run
[
'start'
],
'end'
:
course_run
[
'end'
],
'max_effort'
:
course_run
[
'max_effort'
]
}
mock_get_edx_api_data
.
return_value
=
course_run_details
data
=
get_course_run_details
(
course_run
[
'key'
],
[
'language'
,
'start'
,
'end'
,
'max_effort'
])
self
.
assertTrue
(
mock_get_edx_api_data
.
called
)
self
.
assertEqual
(
data
,
course_run_details
)
openedx/core/djangoapps/catalog/utils.py
View file @
8c6c4676
...
...
@@ -185,3 +185,39 @@ def get_course_runs():
course_runs
=
get_edx_api_data
(
catalog_integration
,
'course_runs'
,
api
=
api
,
querystring
=
querystring
)
return
course_runs
def
get_course_run_details
(
course_run_key
,
fields
):
"""
Retrieve information about the course run with the given id
Arguments:
course_run_key: key for the course_run about which we are retrieving information
Returns:
dict with language, start date, end date, and max_effort details about specified course run
"""
catalog_integration
=
CatalogIntegration
.
current
()
course_run_details
=
dict
()
if
catalog_integration
.
enabled
:
try
:
user
=
catalog_integration
.
get_service_user
()
except
ObjectDoesNotExist
:
msg
=
'Catalog service user {} does not exist. Data for course_run {} will not be retrieved'
.
format
(
catalog_integration
.
service_username
,
course_run_key
)
logger
.
error
(
msg
)
return
course_run_details
api
=
create_catalog_api_client
(
user
)
cache_key
=
'{base}.course_runs'
.
format
(
base
=
catalog_integration
.
CACHE_KEY
)
course_run_details
=
get_edx_api_data
(
catalog_integration
,
'course_runs'
,
api
,
resource_id
=
course_run_key
,
cache_key
=
cache_key
,
many
=
False
,
traverse_pagination
=
False
,
fields
=
fields
)
else
:
msg
=
'Unable to retrieve details about course_run {} because Catalog Integration is not enabled'
.
format
(
course_run_key
)
logger
.
error
(
msg
)
return
course_run_details
openedx/core/lib/edx_api_utils.py
View file @
8c6c4676
...
...
@@ -15,8 +15,20 @@ from openedx.core.lib.token_utils import JwtBuilder
log
=
logging
.
getLogger
(
__name__
)
def
get_fields
(
fields
,
response
):
"""Extracts desired fields from the API response"""
results
=
{}
for
field
in
fields
:
try
:
results
[
field
]
=
response
[
field
]
# TODO: Determine what exception would be raised here if response does not have the specified field
except
:
msg
=
'{resource} does not have the attribute {field}'
.
format
(
resource
,
field
)
log
.
exception
(
msg
)
def
get_edx_api_data
(
api_config
,
resource
,
api
,
resource_id
=
None
,
querystring
=
None
,
cache_key
=
None
,
many
=
True
,
traverse_pagination
=
True
):
traverse_pagination
=
True
,
fields
=
None
):
"""GET data from an edX REST API.
DRY utility for handling caching and pagination.
...
...
@@ -59,7 +71,10 @@ def get_edx_api_data(api_config, resource, api, resource_id=None, querystring=No
response
=
endpoint
(
resource_id
)
.
get
(
**
querystring
)
if
resource_id
is
not
None
:
results
=
response
if
fields
:
results
=
get_fields
(
fields
,
response
)
else
:
results
=
response
elif
traverse_pagination
:
results
=
_traverse_pagination
(
response
,
endpoint
,
querystring
,
no_data
)
else
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment