Merge pull request #12575 from edx/renzo/program-detail-data
Include raw program data on the detail page
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
Unit tests covering the program listing and detail pages.
|
||||
"""
|
||||
import datetime
|
||||
import json
|
||||
import unittest
|
||||
from urlparse import urljoin
|
||||
|
||||
@@ -16,10 +17,11 @@ 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.models import ProgramsApiConfig
|
||||
from openedx.core.djangoapps.programs.tests import factories
|
||||
from openedx.core.djangoapps.programs.tests.mixins import (
|
||||
ProgramsApiConfigMixin,
|
||||
ProgramsDataMixin)
|
||||
from openedx.core.djangoapps.programs.models import ProgramsApiConfig
|
||||
from student.models import CourseEnrollment
|
||||
from student.tests.factories import UserFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
@@ -226,25 +228,56 @@ class TestProgramListing(
|
||||
self.assertNotContains(response, certificate['credential_url'])
|
||||
|
||||
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
@httpretty.activate
|
||||
@override_settings(MKTG_URLS={'ROOT': 'http://edx.org'})
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
class TestProgramDetails(ProgramsApiConfigMixin, TestCase):
|
||||
"""
|
||||
Unit tests for the program details page
|
||||
"""
|
||||
program_id = 123
|
||||
password = 'test'
|
||||
|
||||
def setUp(self):
|
||||
super(TestProgramDetails, self).setUp()
|
||||
|
||||
self.user = UserFactory()
|
||||
self.details_page = reverse('program_details_view', args=['123'])
|
||||
self.details_page = reverse('program_details_view', args=[self.program_id])
|
||||
|
||||
self.client.login(username=self.user.username, password='test')
|
||||
self.user = UserFactory()
|
||||
self.client.login(username=self.user.username, password=self.password)
|
||||
|
||||
ClientFactory(name=ProgramsApiConfig.OAUTH2_CLIENT_NAME, client_type=CONFIDENTIAL)
|
||||
|
||||
self.data = factories.Program(
|
||||
organizations=[factories.Organization()],
|
||||
course_codes=[
|
||||
factories.CourseCode(run_modes=[factories.RunMode()]),
|
||||
]
|
||||
)
|
||||
|
||||
def _mock_programs_api(self):
|
||||
"""Helper for mocking out Programs API URLs."""
|
||||
self.assertTrue(httpretty.is_enabled(), msg='httpretty must be enabled to mock Programs API calls.')
|
||||
|
||||
url = '{api_root}/programs/{id}/'.format(
|
||||
api_root=ProgramsApiConfig.current().internal_api_url.strip('/'),
|
||||
id=self.program_id
|
||||
)
|
||||
body = json.dumps(self.data)
|
||||
|
||||
httpretty.register_uri(httpretty.GET, url, body=body, content_type='application/json')
|
||||
|
||||
def _assert_program_data_present(self, response):
|
||||
"""Verify that program data is present."""
|
||||
self.assertContains(response, 'programData')
|
||||
self.assertContains(response, self.data['name'])
|
||||
|
||||
def test_login_required(self):
|
||||
"""
|
||||
Verify that login is required to access the page.
|
||||
"""
|
||||
self.create_programs_config()
|
||||
self._mock_programs_api()
|
||||
|
||||
self.client.logout()
|
||||
|
||||
@@ -254,10 +287,10 @@ class TestProgramDetails(ProgramsApiConfigMixin, TestCase):
|
||||
'{}?next={}'.format(reverse('signin_user'), self.details_page)
|
||||
)
|
||||
|
||||
self.client.login(username=self.user.username, password='test')
|
||||
self.client.login(username=self.user.username, password=self.password)
|
||||
|
||||
response = self.client.get(self.details_page)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
self._assert_program_data_present(response)
|
||||
|
||||
def test_404_if_disabled(self):
|
||||
"""
|
||||
@@ -271,12 +304,13 @@ class TestProgramDetails(ProgramsApiConfigMixin, TestCase):
|
||||
def test_page_routing(self):
|
||||
"""Verify that the page can be hit with or without a program name in the URL."""
|
||||
self.create_programs_config()
|
||||
self._mock_programs_api()
|
||||
|
||||
response = self.client.get(self.details_page)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
self._assert_program_data_present(response)
|
||||
|
||||
response = self.client.get(self.details_page + 'program_name/')
|
||||
self.assertEquals(response.status_code, 200)
|
||||
self._assert_program_data_present(response)
|
||||
|
||||
response = self.client.get(self.details_page + 'program_name/invalid/')
|
||||
self.assertEquals(response.status_code, 404)
|
||||
|
||||
@@ -9,7 +9,7 @@ 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 openedx.core.djangoapps.programs.utils import ProgramProgressMeter, get_programs, get_display_category
|
||||
from student.views import get_course_enrollments
|
||||
|
||||
|
||||
@@ -50,13 +50,16 @@ def view_programs(request):
|
||||
|
||||
@login_required
|
||||
@require_GET
|
||||
def program_details(request, program_id): # pylint: disable=unused-argument
|
||||
def program_details(request, program_id):
|
||||
"""View details about a specific program."""
|
||||
show_program_details = ProgramsApiConfig.current().show_program_details
|
||||
if not show_program_details:
|
||||
raise Http404
|
||||
|
||||
program_data = get_programs(request.user, program_id=program_id)
|
||||
|
||||
context = {
|
||||
'program_data': program_data,
|
||||
'nav_hidden': True,
|
||||
'disable_courseware_js': True,
|
||||
'uses_pattern_library': True
|
||||
|
||||
@@ -13,7 +13,9 @@ from openedx.core.djangolib.js_utils import (
|
||||
|
||||
<%block name="js_extra">
|
||||
<%static:require_module module_name="js/learner_dashboard/program_details_factory" class_name="ProgramDetailsFactory">
|
||||
ProgramDetailsFactory({});
|
||||
ProgramDetailsFactory({
|
||||
programData: ${program_data | n, dump_js_escaped_json}
|
||||
});
|
||||
</%static:require_module>
|
||||
</%block>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from openedx.core.lib.edx_api_utils import get_edx_api_data
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_programs(user):
|
||||
def get_programs(user, program_id=None):
|
||||
"""Given a user, get programs from the Programs service.
|
||||
Returned value is cached depending on user permissions. Staff users making requests
|
||||
against Programs will receive unpublished programs, while regular users will only receive
|
||||
@@ -19,6 +19,9 @@ def get_programs(user):
|
||||
Arguments:
|
||||
user (User): The user to authenticate as when requesting programs.
|
||||
|
||||
Keyword Arguments:
|
||||
program_id (int): Identifies a specific program for which to retrieve data.
|
||||
|
||||
Returns:
|
||||
list of dict, representing programs returned by the Programs service.
|
||||
"""
|
||||
@@ -27,7 +30,7 @@ def get_programs(user):
|
||||
# Bypass caching for staff users, who may be creating Programs and want
|
||||
# to see them displayed immediately.
|
||||
cache_key = programs_config.CACHE_KEY if programs_config.is_cache_enabled and not user.is_staff else None
|
||||
return get_edx_api_data(programs_config, user, 'programs', cache_key=cache_key)
|
||||
return get_edx_api_data(programs_config, user, 'programs', resource_id=program_id, cache_key=cache_key)
|
||||
|
||||
|
||||
def flatten_programs(programs, course_ids):
|
||||
|
||||
Reference in New Issue
Block a user