Merge pull request #12468 from edx/ahsan/ECOM-4398-Course-Dashboard-Visual-Update
Course Dashboard Visual Update
This commit is contained in:
@@ -122,8 +122,6 @@ from eventtracking import tracker
|
||||
# Note that this lives in LMS, so this dependency should be refactored.
|
||||
from notification_prefs.views import enable_notifications
|
||||
|
||||
# Note that this lives in openedx, so this dependency should be refactored.
|
||||
from openedx.core.djangoapps.credentials.utils import get_user_program_credentials
|
||||
from openedx.core.djangoapps.credit.email_utils import get_credit_provider_display_names, make_providers_strings
|
||||
from openedx.core.djangoapps.user_api.preferences import api as preferences_api
|
||||
from openedx.core.djangoapps.programs.utils import get_programs_for_dashboard, get_display_category
|
||||
@@ -615,7 +613,6 @@ def dashboard(request):
|
||||
# This is passed along in the template context to allow rendering of
|
||||
# program-related information on the dashboard.
|
||||
course_programs = _get_course_programs(user, [enrollment.course_id for enrollment in course_enrollments])
|
||||
xseries_credentials = _get_xseries_credentials(user)
|
||||
|
||||
# Construct a dictionary of course mode information
|
||||
# used to render the course list. We re-use the course modes dict
|
||||
@@ -741,7 +738,6 @@ def dashboard(request):
|
||||
'nav_hidden': True,
|
||||
'course_programs': course_programs,
|
||||
'disable_courseware_js': True,
|
||||
'xseries_credentials': xseries_credentials,
|
||||
'show_program_listing': ProgramsApiConfig.current().show_program_listing,
|
||||
}
|
||||
|
||||
@@ -2483,34 +2479,3 @@ def _get_course_programs(user, user_enrolled_courses): # pylint: disable=invali
|
||||
log.warning('Program structure is invalid, skipping display: %r', program)
|
||||
|
||||
return programs_data
|
||||
|
||||
|
||||
def _get_xseries_credentials(user):
|
||||
"""Return program credentials data required for display on
|
||||
the learner dashboard.
|
||||
|
||||
Given a user, find all programs for which certificates have been earned
|
||||
and return list of dictionaries of required program data.
|
||||
|
||||
Arguments:
|
||||
user (User): user object for getting programs credentials.
|
||||
|
||||
Returns:
|
||||
list of dict, containing data corresponding to the programs for which
|
||||
the user has been awarded a credential.
|
||||
"""
|
||||
programs_credentials = get_user_program_credentials(user)
|
||||
credentials_data = []
|
||||
for program in programs_credentials:
|
||||
if program.get('category') == 'xseries':
|
||||
try:
|
||||
program_data = {
|
||||
'display_name': program['name'],
|
||||
'subtitle': program['subtitle'],
|
||||
'credential_url': program['credential_url'],
|
||||
}
|
||||
credentials_data.append(program_data)
|
||||
except KeyError:
|
||||
log.warning('Program structure is invalid: %r', program)
|
||||
|
||||
return credentials_data
|
||||
|
||||
@@ -14,6 +14,7 @@ from opaque_keys.edx import locator
|
||||
from provider.constants import CONFIDENTIAL
|
||||
|
||||
from openedx.core.djangoapps.credentials.models import CredentialsApiConfig
|
||||
from openedx.core.djangoapps.credentials.tests import factories as credentials_factories
|
||||
from openedx.core.djangoapps.credentials.tests.mixins import CredentialsDataMixin, CredentialsApiConfigMixin
|
||||
from openedx.core.djangoapps.programs.tests.mixins import (
|
||||
ProgramsApiConfigMixin,
|
||||
@@ -155,18 +156,36 @@ class TestProgramListing(
|
||||
'{}?next={}'.format(reverse('signin_user'), self.url)
|
||||
)
|
||||
|
||||
# TODO: Use a factory to generate this data.
|
||||
def _expected_progam_credentials_data(self):
|
||||
"""
|
||||
Dry method for getting expected program credentials response data.
|
||||
"""
|
||||
return [
|
||||
credentials_factories.UserCredential(
|
||||
id=1,
|
||||
username='test',
|
||||
credential=credentials_factories.ProgramCredential()
|
||||
),
|
||||
credentials_factories.UserCredential(
|
||||
id=2,
|
||||
username='test',
|
||||
credential=credentials_factories.ProgramCredential()
|
||||
)
|
||||
]
|
||||
|
||||
def _expected_credentials_data(self):
|
||||
""" Dry method for getting expected credentials."""
|
||||
|
||||
program_credentials_data = self._expected_progam_credentials_data()
|
||||
return [
|
||||
{
|
||||
"display_name": "Test Program A",
|
||||
"credential_url": "http://credentials.edx.org/credentials/dummy-uuid-1/"
|
||||
'display_name': self.PROGRAMS_API_RESPONSE['results'][0]['name'],
|
||||
'subtitle': self.PROGRAMS_API_RESPONSE['results'][0]['subtitle'],
|
||||
'credential_url':program_credentials_data[0]['certificate_url']
|
||||
},
|
||||
{
|
||||
"display_name": "Test Program B",
|
||||
"credential_url": "http://credentials.edx.org/credentials/dummy-uuid-2/"
|
||||
'display_name': self.PROGRAMS_API_RESPONSE['results'][1]['name'],
|
||||
'subtitle':self.PROGRAMS_API_RESPONSE['results'][1]['subtitle'],
|
||||
'credential_url':program_credentials_data[1]['certificate_url']
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@@ -7,9 +7,10 @@ from django.views.decorators.http import require_GET
|
||||
from django.http import Http404
|
||||
|
||||
from edxmako.shortcuts import render_to_response
|
||||
from openedx.core.djangoapps.credentials.utils import get_programs_credentials
|
||||
from openedx.core.djangoapps.programs.models import ProgramsApiConfig
|
||||
from openedx.core.djangoapps.programs.utils import ProgramProgressMeter, get_display_category
|
||||
from student.views import get_course_enrollments, _get_xseries_credentials
|
||||
from student.views import get_course_enrollments
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -39,7 +40,7 @@ def view_programs(request):
|
||||
'xseries_url': marketing_root if ProgramsApiConfig.current().show_xseries_ad else None,
|
||||
'nav_hidden': True,
|
||||
'show_program_listing': show_program_listing,
|
||||
'credentials': _get_xseries_credentials(request.user),
|
||||
'credentials': get_programs_credentials(request.user, category='xseries'),
|
||||
'disable_courseware_js': True,
|
||||
'uses_pattern_library': True
|
||||
}
|
||||
|
||||
@@ -19,9 +19,6 @@
|
||||
@include float(right);
|
||||
@include margin-left(flex-gutter());
|
||||
width: flex-grid(3);
|
||||
margin-top: ($baseline*2);
|
||||
border-top: 3px solid $blue;
|
||||
padding: $baseline 0;
|
||||
|
||||
.course-advertise {
|
||||
@include clearfix();
|
||||
@@ -36,7 +33,7 @@
|
||||
}
|
||||
.ad-link {
|
||||
@include text-align(center);
|
||||
.btn-find-courses {
|
||||
.btn-neutral {
|
||||
padding-bottom: 12px;
|
||||
padding-top: 12px;
|
||||
}
|
||||
@@ -57,6 +54,9 @@
|
||||
span {
|
||||
@include margin-left($baseline*0.25);
|
||||
}
|
||||
.icon {
|
||||
@include margin-right($baseline*0.25);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,8 +94,6 @@
|
||||
@include margin-left(flex-gutter());
|
||||
width: flex-grid(3);
|
||||
margin-top: ($baseline*2);
|
||||
border-top: 3px solid $blue;
|
||||
padding: $baseline 0;
|
||||
|
||||
.user-info {
|
||||
@include clearfix();
|
||||
|
||||
@@ -175,19 +175,6 @@ from openedx.core.djangolib.markup import Text, HTML
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
% if xseries_credentials:
|
||||
<div class="wrapper-xseries-certificates">
|
||||
<p class="title">${_("XSeries Program Certificates")}</p>
|
||||
<p class="copy">${_("You have received a certificate for the following XSeries programs:")}</p>
|
||||
<ul>
|
||||
% for xseries_credential in xseries_credentials:
|
||||
<li>
|
||||
<a class="copy" href="${xseries_credential['credential_url']}">${xseries_credential['display_name']}</a>
|
||||
</li>
|
||||
% endfor
|
||||
</ul>
|
||||
</div>
|
||||
% endif
|
||||
</section>
|
||||
</main>
|
||||
|
||||
|
||||
41
openedx/core/djangoapps/credentials/tests/factories.py
Normal file
41
openedx/core/djangoapps/credentials/tests/factories.py
Normal file
@@ -0,0 +1,41 @@
|
||||
"""Factories for generating fake credentials-related data."""
|
||||
import factory
|
||||
from factory.fuzzy import FuzzyText
|
||||
|
||||
|
||||
class UserCredential(factory.Factory):
|
||||
"""Factory for stubbing user credentials resources from the User Credentials
|
||||
API (v1).
|
||||
"""
|
||||
class Meta(object):
|
||||
model = dict
|
||||
|
||||
id = factory.Sequence(lambda n: n) # pylint: disable=invalid-name
|
||||
username = FuzzyText(prefix='user_')
|
||||
status = 'awarded'
|
||||
uuid = FuzzyText(prefix='uuid_')
|
||||
certificate_url = 'http=//credentials.edx.org/credentials/dummy-uuid'
|
||||
credential = {}
|
||||
|
||||
|
||||
class ProgramCredential(factory.Factory):
|
||||
"""Factory for stubbing program credentials resources from the Program
|
||||
Credentials API (v1).
|
||||
"""
|
||||
class Meta(object):
|
||||
model = dict
|
||||
|
||||
credential_id = factory.Sequence(lambda n: n)
|
||||
program_id = factory.Sequence(lambda n: n)
|
||||
|
||||
|
||||
class CourseCredential(factory.Factory):
|
||||
"""Factory for stubbing course credentials resources from the Course
|
||||
Credentials API (v1).
|
||||
"""
|
||||
class Meta(object):
|
||||
model = dict
|
||||
|
||||
course_id = 'edx/test01/2015'
|
||||
credential_id = factory.Sequence(lambda n: n)
|
||||
certificate_type = 'verified'
|
||||
@@ -4,6 +4,7 @@ import json
|
||||
import httpretty
|
||||
|
||||
from openedx.core.djangoapps.credentials.models import CredentialsApiConfig
|
||||
from openedx.core.djangoapps.credentials.tests import factories
|
||||
|
||||
|
||||
class CredentialsApiConfigMixin(object):
|
||||
@@ -33,103 +34,63 @@ class CredentialsDataMixin(object):
|
||||
CREDENTIALS_API_RESPONSE = {
|
||||
"next": None,
|
||||
"results": [
|
||||
{
|
||||
"id": 1,
|
||||
"username": "test",
|
||||
"credential": {
|
||||
"credential_id": 1,
|
||||
"program_id": 1
|
||||
},
|
||||
"status": "awarded",
|
||||
"uuid": "dummy-uuid-1",
|
||||
"certificate_url": "http://credentials.edx.org/credentials/dummy-uuid-1/"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"username": "test",
|
||||
"credential": {
|
||||
"credential_id": 2,
|
||||
"program_id": 2
|
||||
},
|
||||
"status": "awarded",
|
||||
"uuid": "dummy-uuid-2",
|
||||
"certificate_url": "http://credentials.edx.org/credentials/dummy-uuid-2/"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"username": "test",
|
||||
"credential": {
|
||||
"credential_id": 3,
|
||||
"program_id": 3
|
||||
},
|
||||
"status": "revoked",
|
||||
"uuid": "dummy-uuid-3",
|
||||
"certificate_url": "http://credentials.edx.org/credentials/dummy-uuid-3/"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"username": "test",
|
||||
"credential": {
|
||||
"course_id": "edx/test01/2015",
|
||||
"credential_id": 4,
|
||||
"certificate_type": "honor"
|
||||
},
|
||||
"status": "awarded",
|
||||
"uuid": "dummy-uuid-4",
|
||||
"certificate_url": "http://credentials.edx.org/credentials/dummy-uuid-4/"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"username": "test",
|
||||
"credential": {
|
||||
"course_id": "edx/test02/2015",
|
||||
"credential_id": 5,
|
||||
"certificate_type": "verified"
|
||||
},
|
||||
"status": "awarded",
|
||||
"uuid": "dummy-uuid-5",
|
||||
"certificate_url": "http://credentials.edx.org/credentials/dummy-uuid-5/"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"username": "test",
|
||||
"credential": {
|
||||
"course_id": "edx/test03/2015",
|
||||
"credential_id": 6,
|
||||
"certificate_type": "honor"
|
||||
},
|
||||
"status": "revoked",
|
||||
"uuid": "dummy-uuid-6",
|
||||
"certificate_url": "http://credentials.edx.org/credentials/dummy-uuid-6/"
|
||||
}
|
||||
factories.UserCredential(
|
||||
id=1,
|
||||
username='test',
|
||||
credential=factories.ProgramCredential(
|
||||
program_id=1
|
||||
)
|
||||
),
|
||||
factories.UserCredential(
|
||||
id=2,
|
||||
username='test',
|
||||
credential=factories.ProgramCredential(
|
||||
program_id=2
|
||||
)
|
||||
),
|
||||
factories.UserCredential(
|
||||
id=3,
|
||||
status='revoked',
|
||||
username='test',
|
||||
credential=factories.ProgramCredential()
|
||||
),
|
||||
factories.UserCredential(
|
||||
id=4,
|
||||
username='test',
|
||||
credential=factories.CourseCredential(
|
||||
certificate_type='honor'
|
||||
)
|
||||
),
|
||||
factories.UserCredential(
|
||||
id=5,
|
||||
username='test',
|
||||
credential=factories.CourseCredential(
|
||||
course_id='edx/test02/2015'
|
||||
)
|
||||
),
|
||||
factories.UserCredential(
|
||||
id=6,
|
||||
username='test',
|
||||
credential=factories.CourseCredential(
|
||||
course_id='edx/test02/2015'
|
||||
)
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
CREDENTIALS_NEXT_API_RESPONSE = {
|
||||
"next": None,
|
||||
"results": [
|
||||
{
|
||||
"id": 7,
|
||||
"username": "test",
|
||||
"credential": {
|
||||
"credential_id": 7,
|
||||
"program_id": 7
|
||||
},
|
||||
"status": "awarded",
|
||||
"uuid": "dummy-uuid-7",
|
||||
"certificate_url": "http://credentials.edx.org/credentials/dummy-uuid-7"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"username": "test",
|
||||
"credential": {
|
||||
"credential_id": 8,
|
||||
"program_id": 8
|
||||
},
|
||||
"status": "awarded",
|
||||
"uuid": "dummy-uuid-8",
|
||||
"certificate_url": "http://credentials.edx.org/credentials/dummy-uuid-8/"
|
||||
}
|
||||
factories.UserCredential(
|
||||
id=7,
|
||||
username='test',
|
||||
credential=factories.ProgramCredential()
|
||||
),
|
||||
factories.UserCredential(
|
||||
id=8,
|
||||
username='test',
|
||||
credential=factories.ProgramCredential()
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -3,17 +3,19 @@ import unittest
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from django.test import TestCase
|
||||
from nose.plugins.attrib import attr
|
||||
import httpretty
|
||||
from edx_oauth2_provider.tests.factories import ClientFactory
|
||||
from provider.constants import CONFIDENTIAL
|
||||
|
||||
from openedx.core.djangoapps.credentials.tests.mixins import CredentialsApiConfigMixin, CredentialsDataMixin
|
||||
from openedx.core.djangoapps.credentials.models import CredentialsApiConfig
|
||||
from openedx.core.djangoapps.credentials.tests.mixins import CredentialsApiConfigMixin, CredentialsDataMixin
|
||||
from openedx.core.djangoapps.credentials.utils import (
|
||||
get_user_credentials, get_user_program_credentials
|
||||
get_user_credentials,
|
||||
get_user_program_credentials,
|
||||
get_programs_credentials
|
||||
)
|
||||
from openedx.core.djangoapps.credentials.tests import factories
|
||||
from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin, ProgramsDataMixin
|
||||
from openedx.core.djangoapps.programs.models import ProgramsApiConfig
|
||||
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
|
||||
@@ -39,6 +41,39 @@ class TestCredentialsRetrieval(ProgramsApiConfigMixin, CredentialsApiConfigMixin
|
||||
|
||||
cache.clear()
|
||||
|
||||
def _expected_progam_credentials_data(self):
|
||||
"""
|
||||
Dry method for getting expected program credentials response data.
|
||||
"""
|
||||
return [
|
||||
factories.UserCredential(
|
||||
id=1,
|
||||
username='test',
|
||||
credential=factories.ProgramCredential()
|
||||
),
|
||||
factories.UserCredential(
|
||||
id=2,
|
||||
username='test',
|
||||
credential=factories.ProgramCredential()
|
||||
)
|
||||
]
|
||||
|
||||
def expected_credentials_display_data(self):
|
||||
""" Returns expected credentials data to be represented. """
|
||||
program_credentials_data = self._expected_progam_credentials_data()
|
||||
return [
|
||||
{
|
||||
'display_name': self.PROGRAMS_API_RESPONSE['results'][0]['name'],
|
||||
'subtitle': self.PROGRAMS_API_RESPONSE['results'][0]['subtitle'],
|
||||
'credential_url':program_credentials_data[0]['certificate_url']
|
||||
},
|
||||
{
|
||||
'display_name': self.PROGRAMS_API_RESPONSE['results'][1]['name'],
|
||||
'subtitle':self.PROGRAMS_API_RESPONSE['results'][1]['subtitle'],
|
||||
'credential_url':program_credentials_data[1]['certificate_url']
|
||||
}
|
||||
]
|
||||
|
||||
@httpretty.activate
|
||||
def test_get_user_credentials(self):
|
||||
"""Verify user credentials data can be retrieve."""
|
||||
@@ -98,9 +133,10 @@ class TestCredentialsRetrieval(ProgramsApiConfigMixin, CredentialsApiConfigMixin
|
||||
self.mock_credentials_api(self.user, reset_url=False)
|
||||
|
||||
actual = get_user_program_credentials(self.user)
|
||||
program_credentials_data = self._expected_progam_credentials_data()
|
||||
expected = self.PROGRAMS_API_RESPONSE['results'][:2]
|
||||
expected[0]['credential_url'] = self.PROGRAMS_CREDENTIALS_DATA[0]['certificate_url']
|
||||
expected[1]['credential_url'] = self.PROGRAMS_CREDENTIALS_DATA[1]['certificate_url']
|
||||
expected[0]['credential_url'] = program_credentials_data[0]['certificate_url']
|
||||
expected[1]['credential_url'] = program_credentials_data[1]['certificate_url']
|
||||
|
||||
# checking response from API is as expected
|
||||
self.assertEqual(len(actual), 2)
|
||||
@@ -125,3 +161,57 @@ class TestCredentialsRetrieval(ProgramsApiConfigMixin, CredentialsApiConfigMixin
|
||||
self.mock_credentials_api(self.user, data=credential_data)
|
||||
actual = get_user_program_credentials(self.user)
|
||||
self.assertEqual(actual, [])
|
||||
|
||||
@httpretty.activate
|
||||
def test_get_programs_credentials(self):
|
||||
""" Verify that the program credentials data required for display can
|
||||
be retrieved.
|
||||
"""
|
||||
# create credentials and program configuration
|
||||
self.create_credentials_config()
|
||||
self.create_programs_config()
|
||||
|
||||
# Mocking the API responses from programs and credentials
|
||||
self.mock_programs_api()
|
||||
self.mock_credentials_api(self.user, reset_url=False)
|
||||
actual = get_programs_credentials(self.user, category='xseries')
|
||||
expected = self.expected_credentials_display_data()
|
||||
|
||||
# Checking result is as expected
|
||||
self.assertEqual(len(actual), 2)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@httpretty.activate
|
||||
def test_get_programs_credentials_category(self):
|
||||
""" Verify behaviour when program category is provided."""
|
||||
# create credentials and program configuration
|
||||
self.create_credentials_config()
|
||||
self.create_programs_config()
|
||||
|
||||
# Mocking the API responses from programs and credentials
|
||||
self.mock_programs_api()
|
||||
self.mock_credentials_api(self.user, reset_url=False)
|
||||
actual = get_programs_credentials(self.user, category='dummy_category')
|
||||
expected = self.expected_credentials_display_data()
|
||||
|
||||
self.assertEqual(len(actual), 0)
|
||||
|
||||
actual = get_programs_credentials(self.user, category='xseries')
|
||||
|
||||
self.assertEqual(len(actual), 2)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@httpretty.activate
|
||||
def test_get_programs_credentials_no_category(self):
|
||||
""" Verify behaviour when no program category is provided. """
|
||||
self.create_credentials_config()
|
||||
self.create_programs_config()
|
||||
|
||||
# Mocking the API responses from programs and credentials
|
||||
self.mock_programs_api()
|
||||
self.mock_credentials_api(self.user, reset_url=False)
|
||||
actual = get_programs_credentials(self.user)
|
||||
expected = self.expected_credentials_display_data()
|
||||
|
||||
self.assertEqual(len(actual), 2)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@@ -64,3 +64,35 @@ def get_user_program_credentials(user):
|
||||
programs_credentials_data = get_programs_for_credentials(user, programs_credentials)
|
||||
|
||||
return programs_credentials_data
|
||||
|
||||
|
||||
def get_programs_credentials(user, category=None):
|
||||
"""Return program credentials data required for display.
|
||||
|
||||
Given a user, find all programs for which certificates have been earned
|
||||
and return list of dictionaries of required program data.
|
||||
|
||||
Arguments:
|
||||
user (User): user object for getting programs credentials.
|
||||
category(str) : program category for getting credentials.
|
||||
|
||||
Returns:
|
||||
list of dict, containing data corresponding to the programs for which
|
||||
the user has been awarded a credential.
|
||||
"""
|
||||
programs_credentials = get_user_program_credentials(user)
|
||||
credentials_data = []
|
||||
for program in programs_credentials:
|
||||
is_included = (category is None) or (program.get('category') == category)
|
||||
if is_included:
|
||||
try:
|
||||
program_data = {
|
||||
'display_name': program['name'],
|
||||
'subtitle': program['subtitle'],
|
||||
'credential_url': program['credential_url'],
|
||||
}
|
||||
credentials_data.append(program_data)
|
||||
except KeyError:
|
||||
log.warning('Program structure is invalid: %r', program)
|
||||
|
||||
return credentials_data
|
||||
|
||||
@@ -100,31 +100,6 @@ class ProgramsDataMixin(object):
|
||||
]
|
||||
}
|
||||
|
||||
PROGRAMS_CREDENTIALS_DATA = [
|
||||
{
|
||||
"id": 1,
|
||||
"username": "test",
|
||||
"credential": {
|
||||
"credential_id": 1,
|
||||
"program_id": 1
|
||||
},
|
||||
"status": "awarded",
|
||||
"uuid": "dummy-uuid-1",
|
||||
"certificate_url": "http://credentials.edx.org/credentials/dummy-uuid-1/"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"username": "test",
|
||||
"credential": {
|
||||
"credential_id": 2,
|
||||
"program_id": 2
|
||||
},
|
||||
"status": "awarded",
|
||||
"uuid": "dummy-uuid-2",
|
||||
"certificate_url": "http://credentials.edx.org/credentials/dummy-uuid-2/"
|
||||
}
|
||||
]
|
||||
|
||||
def mock_programs_api(self, data=None, status_code=200):
|
||||
"""Utility for mocking out Programs API URLs."""
|
||||
self.assertTrue(httpretty.is_enabled(), msg='httpretty must be enabled to mock Programs API calls.')
|
||||
|
||||
@@ -12,7 +12,8 @@ from edx_oauth2_provider.tests.factories import ClientFactory
|
||||
from provider.constants import CONFIDENTIAL
|
||||
|
||||
from lms.djangoapps.certificates.api import MODES
|
||||
from openedx.core.djangoapps.credentials.tests.mixins import CredentialsApiConfigMixin
|
||||
from openedx.core.djangoapps.credentials.tests import factories as credentials_factories
|
||||
from openedx.core.djangoapps.credentials.tests.mixins import CredentialsApiConfigMixin, CredentialsDataMixin
|
||||
from openedx.core.djangoapps.programs import utils
|
||||
from openedx.core.djangoapps.programs.models import ProgramsApiConfig
|
||||
from openedx.core.djangoapps.programs.tests import factories
|
||||
@@ -26,7 +27,7 @@ UTILS_MODULE = 'openedx.core.djangoapps.programs.utils'
|
||||
|
||||
@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
@attr('shard_2')
|
||||
class TestProgramRetrieval(ProgramsApiConfigMixin, ProgramsDataMixin,
|
||||
class TestProgramRetrieval(ProgramsApiConfigMixin, ProgramsDataMixin, CredentialsDataMixin,
|
||||
CredentialsApiConfigMixin, CacheIsolationTestCase):
|
||||
"""Tests covering the retrieval of programs from the Programs service."""
|
||||
|
||||
@@ -40,6 +41,27 @@ class TestProgramRetrieval(ProgramsApiConfigMixin, ProgramsDataMixin,
|
||||
|
||||
cache.clear()
|
||||
|
||||
def _expected_progam_credentials_data(self):
|
||||
"""
|
||||
Dry method for getting expected program credentials response data.
|
||||
"""
|
||||
return [
|
||||
credentials_factories.UserCredential(
|
||||
id=1,
|
||||
username='test',
|
||||
credential=credentials_factories.ProgramCredential(
|
||||
program_id=1
|
||||
)
|
||||
),
|
||||
credentials_factories.UserCredential(
|
||||
id=2,
|
||||
username='test',
|
||||
credential=credentials_factories.ProgramCredential(
|
||||
program_id=2
|
||||
)
|
||||
)
|
||||
]
|
||||
|
||||
@httpretty.activate
|
||||
def test_get_programs(self):
|
||||
"""Verify programs data can be retrieved."""
|
||||
@@ -152,11 +174,12 @@ class TestProgramRetrieval(ProgramsApiConfigMixin, ProgramsDataMixin,
|
||||
"""Verify programs data can be retrieved and parsed correctly for certificates."""
|
||||
self.create_programs_config()
|
||||
self.mock_programs_api()
|
||||
program_credentials_data = self._expected_progam_credentials_data()
|
||||
|
||||
actual = utils.get_programs_for_credentials(self.user, self.PROGRAMS_CREDENTIALS_DATA)
|
||||
actual = utils.get_programs_for_credentials(self.user, program_credentials_data)
|
||||
expected = self.PROGRAMS_API_RESPONSE['results'][:2]
|
||||
expected[0]['credential_url'] = self.PROGRAMS_CREDENTIALS_DATA[0]['certificate_url']
|
||||
expected[1]['credential_url'] = self.PROGRAMS_CREDENTIALS_DATA[1]['certificate_url']
|
||||
expected[0]['credential_url'] = program_credentials_data[0]['certificate_url']
|
||||
expected[1]['credential_url'] = program_credentials_data[1]['certificate_url']
|
||||
|
||||
self.assertEqual(len(actual), 2)
|
||||
self.assertEqual(actual, expected)
|
||||
@@ -167,8 +190,9 @@ class TestProgramRetrieval(ProgramsApiConfigMixin, ProgramsDataMixin,
|
||||
self.create_programs_config()
|
||||
self.create_credentials_config()
|
||||
self.mock_programs_api(data={'results': []})
|
||||
program_credentials_data = self._expected_progam_credentials_data()
|
||||
|
||||
actual = utils.get_programs_for_credentials(self.user, self.PROGRAMS_CREDENTIALS_DATA)
|
||||
actual = utils.get_programs_for_credentials(self.user, program_credentials_data)
|
||||
self.assertEqual(actual, [])
|
||||
|
||||
@httpretty.activate
|
||||
|
||||
@@ -163,7 +163,7 @@ from openedx.core.djangolib.markup import Text, HTML
|
||||
${_("Browse recently launched courses and see what's new in your favorite subjects.")}
|
||||
</div>
|
||||
<div class="ad-link">
|
||||
<a class="btn-find-courses" href="${marketing_link('COURSES')}">
|
||||
<a class="btn-neutral" href="${marketing_link('COURSES')}">
|
||||
<span class="icon fa fa-search" aria-hidden="true"></span>
|
||||
${_("Explore New Courses")}
|
||||
</a>
|
||||
@@ -193,19 +193,6 @@ from openedx.core.djangolib.markup import Text, HTML
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
% if xseries_credentials:
|
||||
<div class="wrapper-xseries-certificates">
|
||||
<p class="title">${_("XSeries Program Certificates")}</p>
|
||||
<p class="copy">${_("You have received a certificate for the following XSeries programs:")}</p>
|
||||
<ul>
|
||||
% for xseries_credential in xseries_credentials:
|
||||
<li>
|
||||
<a class="copy" href="${xseries_credential['credential_url']}">${xseries_credential['display_name']}</a>
|
||||
</li>
|
||||
% endfor
|
||||
</ul>
|
||||
</div>
|
||||
% endif
|
||||
</section>
|
||||
|
||||
<section id="email-settings-modal" class="modal" aria-hidden="true">
|
||||
|
||||
Reference in New Issue
Block a user