Programs list conditionally added to the context of index and courses page.

This commit is contained in:
Afzal Wali
2016-11-23 16:14:19 +05:00
parent bde0f7b2a7
commit e44e18592f
9 changed files with 242 additions and 16 deletions

View File

@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('catalog', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='catalogintegration',
name='service_username',
field=models.CharField(default=b'lms_catalog_service_user', help_text='Username created for Course Catalog Integration, e.g. lms_catalog_service_user.', max_length=100),
),
]

View File

@@ -25,6 +25,16 @@ class CatalogIntegration(ConfigurationModel):
)
)
service_username = models.CharField(
max_length=100,
default="lms_catalog_service_user",
null=False,
blank=False,
help_text=_(
'Username created for Course Catalog Integration, e.g. lms_catalog_service_user.'
)
)
@property
def is_cache_enabled(self):
"""Whether responses from the catalog API will be cached."""

View File

@@ -70,3 +70,14 @@ class Program(factory.Factory):
banner_image = {
size: BannerImage() for size in ['large', 'medium', 'small', 'x-small']
}
class ProgramType(factory.Factory):
"""
Factory for stubbing ProgramType resources from the catalog API.
"""
class Meta(object):
model = dict
name = FuzzyText()
logo_image = FuzzyText(prefix='https://example.com/program/logo')

View File

@@ -2,6 +2,7 @@
Tests covering utilities for integrating with the catalog service.
"""
import uuid
import copy
from django.core.cache import cache
from django.test import TestCase
@@ -12,9 +13,8 @@ from opaque_keys.edx.keys import CourseKey
from openedx.core.djangoapps.catalog import utils
from openedx.core.djangoapps.catalog.models import CatalogIntegration
from openedx.core.djangoapps.catalog.tests import factories, mixins
from student.tests.factories import UserFactory, AnonymousUserFactory
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from student.tests.factories import UserFactory
UTILS_MODULE = 'openedx.core.djangoapps.catalog.utils'
@@ -76,6 +76,73 @@ class TestGetPrograms(mixins.CatalogIntegrationMixin, TestCase):
self.assert_contract(mock_get_catalog_data.call_args)
self.assertEqual(data, programs)
def test_get_programs_anonymous_user(self, _mock_cache, mock_get_catalog_data):
programs = [factories.Program() for __ in range(3)]
mock_get_catalog_data.return_value = programs
anonymous_user = AnonymousUserFactory()
# The user is an Anonymous user but the Catalog Service User has not been created yet.
data = utils.get_programs(anonymous_user)
# This should not return programs.
self.assertEqual(data, [])
UserFactory(username='lms_catalog_service_user')
# After creating the service user above,
data = utils.get_programs(anonymous_user)
# the programs should be returned successfully.
self.assertEqual(data, programs)
def test_get_program_types(self, _mock_cache, mock_get_catalog_data):
program_types = [factories.ProgramType() for __ in range(3)]
mock_get_catalog_data.return_value = program_types
# Creating Anonymous user but the Catalog Service User has not been created yet.
anonymous_user = AnonymousUserFactory()
data = utils.get_program_types(anonymous_user)
# This should not return programs.
self.assertEqual(data, [])
# Creating Catalog Service User user
UserFactory(username='lms_catalog_service_user')
data = utils.get_program_types(anonymous_user)
# the programs should be returned successfully.
self.assertEqual(data, program_types)
# Catalog integration is disabled now.
self.catalog_integration = self.create_catalog_integration(enabled=False)
data = utils.get_program_types(anonymous_user)
# This should not return programs.
self.assertEqual(data, [])
def test_get_programs_data(self, _mock_cache, mock_get_catalog_data): # pylint: disable=unused-argument
programs = []
program_types = []
programs_data = []
for index in range(3):
# Creating the Programs and their corresponding program types.
type_name = "type_name_{postfix}".format(postfix=index)
program = factories.Program(type=type_name)
program_type = factories.ProgramType(name=type_name)
# Maintaining the programs, program types and program data(program+logo_image) lists.
programs.append(program)
program_types.append(program_type)
programs_data.append(copy.deepcopy(program))
# Adding the logo image in program data.
programs_data[-1]['logo_image'] = program_type["logo_image"]
with mock.patch("openedx.core.djangoapps.catalog.utils.get_programs") as patched_get_programs:
with mock.patch("openedx.core.djangoapps.catalog.utils.get_program_types") as patched_get_program_types:
# Mocked the "get_programs" and "get_program_types"
patched_get_programs.return_value = programs
patched_get_program_types.return_value = program_types
programs_data = utils.get_programs_data()
self.assertEqual(programs_data, programs)
def test_get_one_program(self, _mock_cache, mock_get_catalog_data):
program = factories.Program()
mock_get_catalog_data.return_value = program

View File

@@ -4,6 +4,7 @@ import logging
from django.conf import settings
from django.core.cache import cache
from django.contrib.auth.models import User
from edx_rest_api_client.client import EdxRestApiClient
from opaque_keys.edx.keys import CourseKey
@@ -24,7 +25,20 @@ def create_catalog_api_client(user, catalog_integration):
return EdxRestApiClient(catalog_integration.internal_api_url, jwt=jwt)
def get_programs(user, uuid=None, type=None): # pylint: disable=redefined-builtin
def _get_service_user(user, service_username):
"""
Retrieve and return the Catalog Integration Service User Object
if the passed user is None or anonymous
"""
if not user or user.is_anonymous():
try:
user = User.objects.get(username=service_username)
except User.DoesNotExist:
user = None
return user
def get_programs(user=None, uuid=None, type=None): # pylint: disable=redefined-builtin
"""Retrieve marketable programs from the catalog service.
Keyword Arguments:
@@ -36,8 +50,11 @@ def get_programs(user, uuid=None, type=None): # pylint: disable=redefined-built
dict, if a specific program is requested.
"""
catalog_integration = CatalogIntegration.current()
if catalog_integration.enabled:
user = _get_service_user(user, catalog_integration.service_username)
if not user:
return []
api = create_catalog_api_client(user, catalog_integration)
cache_key = '{base}.programs{type}'.format(
@@ -66,6 +83,46 @@ def get_programs(user, uuid=None, type=None): # pylint: disable=redefined-built
return []
def get_program_types(user=None): # pylint: disable=redefined-builtin
"""Retrieve all program types from the catalog service.
Returns:
list of dict, representing program types.
"""
catalog_integration = CatalogIntegration.current()
if catalog_integration.enabled:
user = _get_service_user(user, catalog_integration.service_username)
if not user:
return []
api = create_catalog_api_client(user, catalog_integration)
cache_key = '{base}.program_types'.format(base=catalog_integration.CACHE_KEY)
return get_edx_api_data(
catalog_integration,
user,
'program_types',
cache_key=cache_key if catalog_integration.is_cache_enabled else None,
api=api
)
else:
return []
def get_programs_data(user=None):
"""Return the list of Programs after adding the ProgramType Logo Image"""
programs_list = get_programs(user)
program_types = get_program_types(user)
program_types_lookup_dict = {program_type["name"]: program_type for program_type in program_types}
for program in programs_list:
program["logo_image"] = program_types_lookup_dict[program["type"]]["logo_image"]
return programs_list
def munge_catalog_program(catalog_program):
"""Make a program from the catalog service look like it came from the programs service.