Course Dashboard Visual Update

ECOM-4398
This commit is contained in:
Ahsan Ulhaq
2016-05-16 14:26:55 +05:00
parent 83155840aa
commit a8f2de8375
12 changed files with 283 additions and 203 deletions

View 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'

View File

@@ -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()
)
]
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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.')

View File

@@ -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