Commit 98b63a79 by Jim Abramson

Merge pull request #10862 from edx/jsa/programs-token-endpoint

Implement an endpoint to get id_tokens for programs.
parents a753d1ef 2fbfcfd2
"""Programs views for use with Studio."""
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
from django.http import Http404
from django.http import Http404, JsonResponse
from django.utils.decorators import method_decorator
from django.views.generic import View
from edxmako.shortcuts import render_to_response
from openedx.core.djangoapps.programs.models import ProgramsApiConfig
from openedx.core.lib.token_utils import get_id_token
class ProgramAuthoringView(View):
......@@ -18,13 +19,6 @@ class ProgramAuthoringView(View):
"""
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
"""Relays requests to matching methods.
Decorated to require login before accessing the authoring app.
"""
return super(ProgramAuthoringView, self).dispatch(*args, **kwargs)
def get(self, request, *args, **kwargs):
"""Populate the template context with values required for the authoring app to run."""
programs_config = ProgramsApiConfig.current()
......@@ -38,3 +32,16 @@ class ProgramAuthoringView(View):
})
else:
raise Http404
class ProgramsIdTokenView(View):
"""Provides id tokens to JavaScript clients for use with the Programs API."""
@method_decorator(login_required)
def get(self, request, *args, **kwargs):
"""Generate and return a token, if the integration is enabled."""
if ProgramsApiConfig.current().is_studio_tab_enabled:
id_token = get_id_token(request.user, 'programs')
return JsonResponse({'id_token': id_token})
else:
raise Http404
"""Tests covering the Programs listing on the Studio home."""
import json
from django.conf import settings
from django.core.urlresolvers import reverse
import httpretty
import mock
from oauth2_provider.tests.factories import ClientFactory
from provider.constants import CONFIDENTIAL
from openedx.core.djangoapps.programs.models import ProgramsApiConfig
from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin, ProgramsDataMixin
from student.tests.factories import UserFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
class TestProgramListing(ProgramsApiConfigMixin, ProgramsDataMixin, ModuleStoreTestCase):
class TestProgramListing(ProgramsApiConfigMixin, ProgramsDataMixin, SharedModuleStoreTestCase):
"""Verify Program listing behavior."""
def setUp(self):
super(TestProgramListing, self).setUp()
......@@ -70,7 +73,7 @@ class TestProgramListing(ProgramsApiConfigMixin, ProgramsDataMixin, ModuleStoreT
self.assertIn(program_name, response.content)
class TestProgramAuthoringView(ProgramsApiConfigMixin, ModuleStoreTestCase):
class TestProgramAuthoringView(ProgramsApiConfigMixin, SharedModuleStoreTestCase):
"""Verify the behavior of the program authoring app's host view."""
def setUp(self):
super(TestProgramAuthoringView, self).setUp()
......@@ -118,3 +121,43 @@ class TestProgramAuthoringView(ProgramsApiConfigMixin, ModuleStoreTestCase):
student = UserFactory(is_staff=False)
self.client.login(username=student.username, password='test')
self._assert_status(404)
class TestProgramsIdTokenView(ProgramsApiConfigMixin, SharedModuleStoreTestCase):
"""Tests for the programs id_token endpoint."""
def setUp(self):
super(TestProgramsIdTokenView, self).setUp()
self.user = UserFactory()
self.client.login(username=self.user.username, password='test')
self.path = reverse('programs_id_token')
def test_config_disabled(self):
"""Ensure the endpoint returns 404 when Programs authoring is disabled."""
self.create_config(enable_studio_tab=False)
response = self.client.get(self.path)
self.assertEqual(response.status_code, 404)
def test_not_logged_in(self):
"""Ensure the endpoint denies access to unauthenticated users."""
self.create_config()
self.client.logout()
response = self.client.get(self.path)
self.assertEqual(response.status_code, 302)
self.assertIn(settings.LOGIN_URL, response['Location'])
@mock.patch('cms.djangoapps.contentstore.views.program.get_id_token', return_value='test-id-token')
def test_config_enabled(self, mock_get_id_token):
"""
Ensure the endpoint responds with a valid JSON payload when authoring
is enabled.
"""
self.create_config()
response = self.client.get(self.path)
self.assertEqual(response.status_code, 200)
payload = json.loads(response.content)
self.assertEqual(payload, {"id_token": "test-id-token"})
# this comparison is a little long-handed because we need to compare user instances directly
user, client_name = mock_get_id_token.call_args[0]
self.assertEqual(user, self.user)
self.assertEqual(client_name, "programs")
......@@ -3,7 +3,7 @@ from django.conf.urls import patterns, include, url
# There is a course creators admin table.
from ratelimitbackend import admin
from cms.djangoapps.contentstore.views.program import ProgramAuthoringView
from cms.djangoapps.contentstore.views.program import ProgramAuthoringView, ProgramsIdTokenView
admin.autodiscover()
......@@ -185,9 +185,10 @@ if settings.FEATURES.get('CERTIFICATES_HTML_VIEW'):
)
urlpatterns += (
# These views use a configuration model to determine whether or not to
# display the Programs authoring app. If disabled, a 404 is returned.
url(r'^programs/id_token/$', ProgramsIdTokenView.as_view(), name='programs_id_token'),
# Drops into the Programs authoring app, which handles its own routing.
# The view uses a configuration model to determine whether or not to
# display the authoring app. If disabled, a 404 is returned.
url(r'^program/', ProgramAuthoringView.as_view(), name='programs'),
)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment