Commit b89fc917 by Clinton Blackburn Committed by GitHub

Merge pull request #12786 from edx/clintonb/catalog-admin-csv

Added CSV catalog downloads
parents 6705677b eab057c8
...@@ -726,6 +726,8 @@ ECOMMERCE_API_URL = ENV_TOKENS.get('ECOMMERCE_API_URL', ECOMMERCE_API_URL) ...@@ -726,6 +726,8 @@ ECOMMERCE_API_URL = ENV_TOKENS.get('ECOMMERCE_API_URL', ECOMMERCE_API_URL)
ECOMMERCE_API_SIGNING_KEY = AUTH_TOKENS.get('ECOMMERCE_API_SIGNING_KEY', ECOMMERCE_API_SIGNING_KEY) ECOMMERCE_API_SIGNING_KEY = AUTH_TOKENS.get('ECOMMERCE_API_SIGNING_KEY', ECOMMERCE_API_SIGNING_KEY)
ECOMMERCE_API_TIMEOUT = ENV_TOKENS.get('ECOMMERCE_API_TIMEOUT', ECOMMERCE_API_TIMEOUT) ECOMMERCE_API_TIMEOUT = ENV_TOKENS.get('ECOMMERCE_API_TIMEOUT', ECOMMERCE_API_TIMEOUT)
COURSE_CATALOG_API_URL = ENV_TOKENS.get('COURSE_CATALOG_API_URL', COURSE_CATALOG_API_URL)
##### Custom Courses for EdX ##### ##### Custom Courses for EdX #####
if FEATURES.get('CUSTOM_COURSES_EDX'): if FEATURES.get('CUSTOM_COURSES_EDX'):
INSTALLED_APPS += ('lms.djangoapps.ccx', 'openedx.core.djangoapps.ccxcon') INSTALLED_APPS += ('lms.djangoapps.ccx', 'openedx.core.djangoapps.ccxcon')
......
...@@ -2731,6 +2731,8 @@ ECOMMERCE_API_SIGNING_KEY = None ...@@ -2731,6 +2731,8 @@ ECOMMERCE_API_SIGNING_KEY = None
ECOMMERCE_API_TIMEOUT = 5 ECOMMERCE_API_TIMEOUT = 5
ECOMMERCE_SERVICE_WORKER_USERNAME = 'ecommerce_worker' ECOMMERCE_SERVICE_WORKER_USERNAME = 'ecommerce_worker'
COURSE_CATALOG_API_URL = None
# Reverification checkpoint name pattern # Reverification checkpoint name pattern
CHECKPOINT_PATTERN = r'(?P<checkpoint_name>[^/]+)' CHECKPOINT_PATTERN = r'(?P<checkpoint_name>[^/]+)'
......
...@@ -585,3 +585,5 @@ TransformerRegistry.USE_PLUGIN_MANAGER = False ...@@ -585,3 +585,5 @@ TransformerRegistry.USE_PLUGIN_MANAGER = False
# Set the default Oauth2 Provider Model so that migrations can run in # Set the default Oauth2 Provider Model so that migrations can run in
# verbose mode # verbose mode
OAUTH2_PROVIDER_APPLICATION_MODEL = 'oauth2_provider.Application' OAUTH2_PROVIDER_APPLICATION_MODEL = 'oauth2_provider.Application'
COURSE_CATALOG_API_URL = 'https://catalog.example.com/api/v1'
## mako
<%page expression_filter="h"/>
<%inherit file="../../main.html"/>
<%!
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext as _
%>
<%block name="pagetitle">${catalog.name}</%block>
<%block name="content">
<div id="api-access-wrapper">
<h1 id="api-header">${catalog.name}</h1>
<p class="api-copy-body">${catalog.query}</p>
<p class="api-copy-body"><a href="${edit_link}">${_("Edit or delete this catalog.")}</a></p>
<p class="api-copy-body"><a href="${preview_link}">${_("See a preview of this catalog's contents.")}</a></p>
</div>
</%block>
...@@ -23,6 +23,12 @@ from django.utils.translation import ugettext as _ ...@@ -23,6 +23,12 @@ from django.utils.translation import ugettext as _
<div id="api-access-wrapper"> <div id="api-access-wrapper">
<h1 id="api-header">${catalog.name}</h1> <h1 id="api-header">${catalog.name}</h1>
<p>
<a href="${'{root}/{id}/csv/'.format(root=catalog_api_catalog_endpoint, id=catalog.id)}" target="_blank">
${_("Download CSV")}
</a>
</p>
<div class="catalog-body"> <div class="catalog-body">
<div class="api-form-container"> <div class="api-form-container">
<form class="api-form" id="catalog-update" action="${reverse('api_admin:catalog-edit', args=(catalog.id,))}" method="post"> <form class="api-form" id="catalog-update" action="${reverse('api_admin:catalog-edit', args=(catalog.id,))}" method="post">
......
...@@ -25,7 +25,10 @@ CatalogPreviewFactory({ ...@@ -25,7 +25,10 @@ CatalogPreviewFactory({
<ul> <ul>
% for catalog in catalogs: % for catalog in catalogs:
<li> <li>
<a href="${reverse('api_admin:catalog-edit', args=(catalog.id,))}">${catalog.name}</a> <a href="${reverse('api_admin:catalog-edit', args=(catalog.id,))}">${catalog.name}</a>&nbsp;
(<a
href="${'{root}/{id}/csv/'.format(root=catalog_api_catalog_endpoint, id=catalog.id)}"
target="_blank">${_("Download CSV")}</a>)
</li> </li>
% endfor % endfor
</ul> </ul>
......
#pylint: disable=missing-docstring """ Tests for the api_admin app's views. """
import unittest
import json import json
from urlparse import urljoin import unittest
import ddt import ddt
import httpretty
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.test import TestCase from django.test import TestCase
from django.test.utils import override_settings from django.test.utils import override_settings
from edx_oauth2_provider.tests.factories import ClientFactory
import httpretty
from oauth2_provider.models import get_application_model from oauth2_provider.models import get_application_model
from openedx.core.djangoapps.api_admin.models import ApiAccessRequest, ApiAccessConfig from openedx.core.djangoapps.api_admin.models import ApiAccessRequest, ApiAccessConfig
...@@ -19,14 +18,10 @@ from openedx.core.djangoapps.api_admin.tests.factories import ( ...@@ -19,14 +18,10 @@ from openedx.core.djangoapps.api_admin.tests.factories import (
from openedx.core.djangoapps.api_admin.tests.utils import VALID_DATA from openedx.core.djangoapps.api_admin.tests.utils import VALID_DATA
from student.tests.factories import UserFactory from student.tests.factories import UserFactory
Application = get_application_model() # pylint: disable=invalid-name Application = get_application_model() # pylint: disable=invalid-name
MOCK_CATALOG_API_URL_ROOT = 'https://api.example.com/'
class ApiAdminTest(TestCase): class ApiAdminTest(TestCase):
def setUp(self): def setUp(self):
super(ApiAdminTest, self).setUp() super(ApiAdminTest, self).setUp()
ApiAccessConfig(enabled=True).save() ApiAccessConfig(enabled=True).save()
...@@ -34,7 +29,6 @@ class ApiAdminTest(TestCase): ...@@ -34,7 +29,6 @@ class ApiAdminTest(TestCase):
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
class ApiRequestViewTest(ApiAdminTest): class ApiRequestViewTest(ApiAdminTest):
def setUp(self): def setUp(self):
super(ApiRequestViewTest, self).setUp() super(ApiRequestViewTest, self).setUp()
self.url = reverse('api_admin:api-request') self.url = reverse('api_admin:api-request')
...@@ -103,7 +97,6 @@ class ApiRequestViewTest(ApiAdminTest): ...@@ -103,7 +97,6 @@ class ApiRequestViewTest(ApiAdminTest):
@override_settings(PLATFORM_NAME='edX') @override_settings(PLATFORM_NAME='edX')
@ddt.ddt @ddt.ddt
class ApiRequestStatusViewTest(ApiAdminTest): class ApiRequestStatusViewTest(ApiAdminTest):
def setUp(self): def setUp(self):
super(ApiRequestStatusViewTest, self).setUp() super(ApiRequestStatusViewTest, self).setUp()
password = 'abc123' password = 'abc123'
...@@ -207,7 +200,6 @@ class ApiRequestStatusViewTest(ApiAdminTest): ...@@ -207,7 +200,6 @@ class ApiRequestStatusViewTest(ApiAdminTest):
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
class ApiTosViewTest(ApiAdminTest): class ApiTosViewTest(ApiAdminTest):
def test_get_api_tos(self): def test_get_api_tos(self):
"""Verify that the terms of service can be read.""" """Verify that the terms of service can be read."""
url = reverse('api_admin:api-tos') url = reverse('api_admin:api-tos')
...@@ -217,20 +209,23 @@ class ApiTosViewTest(ApiAdminTest): ...@@ -217,20 +209,23 @@ class ApiTosViewTest(ApiAdminTest):
class CatalogTest(ApiAdminTest): class CatalogTest(ApiAdminTest):
def setUp(self): def setUp(self):
super(CatalogTest, self).setUp() super(CatalogTest, self).setUp()
password = 'abc123' password = 'abc123'
self.user = UserFactory(password=password, is_staff=True) self.user = UserFactory(password=password, is_staff=True)
self.client.login(username=self.user.username, password=password) self.client.login(username=self.user.username, password=password)
ClientFactory(user=self.user, name='course-discovery', url=MOCK_CATALOG_API_URL_ROOT)
def mock_catalog_api(self, url, data, method=httpretty.GET, status_code=200): def mock_catalog_endpoint(self, data, catalog_id=None, method=httpretty.GET, status_code=200):
""" Mock the Course Catalog API's catalog endpoint. """
self.assertTrue(httpretty.is_enabled(), msg='httpretty must be enabled to mock Catalog API calls.') self.assertTrue(httpretty.is_enabled(), msg='httpretty must be enabled to mock Catalog API calls.')
httpretty.reset()
url = '{root}/catalogs/'.format(root=settings.COURSE_CATALOG_API_URL.rstrip('/'))
if catalog_id:
url += '{id}/'.format(id=catalog_id)
httpretty.register_uri( httpretty.register_uri(
method, method,
urljoin(MOCK_CATALOG_API_URL_ROOT, url), url,
body=json.dumps(data), body=json.dumps(data),
content_type='application/json', content_type='application/json',
status=status_code status=status_code
...@@ -239,7 +234,6 @@ class CatalogTest(ApiAdminTest): ...@@ -239,7 +234,6 @@ class CatalogTest(ApiAdminTest):
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
class CatalogSearchViewTest(CatalogTest): class CatalogSearchViewTest(CatalogTest):
def setUp(self): def setUp(self):
super(CatalogSearchViewTest, self).setUp() super(CatalogSearchViewTest, self).setUp()
self.url = reverse('api_admin:catalog-search') self.url = reverse('api_admin:catalog-search')
...@@ -251,7 +245,7 @@ class CatalogSearchViewTest(CatalogTest): ...@@ -251,7 +245,7 @@ class CatalogSearchViewTest(CatalogTest):
@httpretty.activate @httpretty.activate
def test_post(self): def test_post(self):
catalog_user = UserFactory() catalog_user = UserFactory()
self.mock_catalog_api('api/v1/catalogs/', {'results': []}) self.mock_catalog_endpoint({'results': []})
response = self.client.post(self.url, {'username': catalog_user.username}) response = self.client.post(self.url, {'username': catalog_user.username})
self.assertRedirects(response, reverse('api_admin:catalog-list', kwargs={'username': catalog_user.username})) self.assertRedirects(response, reverse('api_admin:catalog-list', kwargs={'username': catalog_user.username}))
...@@ -262,7 +256,6 @@ class CatalogSearchViewTest(CatalogTest): ...@@ -262,7 +256,6 @@ class CatalogSearchViewTest(CatalogTest):
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
class CatalogListViewTest(CatalogTest): class CatalogListViewTest(CatalogTest):
def setUp(self): def setUp(self):
super(CatalogListViewTest, self).setUp() super(CatalogListViewTest, self).setUp()
self.catalog_user = UserFactory() self.catalog_user = UserFactory()
...@@ -271,9 +264,7 @@ class CatalogListViewTest(CatalogTest): ...@@ -271,9 +264,7 @@ class CatalogListViewTest(CatalogTest):
@httpretty.activate @httpretty.activate
def test_get(self): def test_get(self):
catalog = CatalogFactory(viewers=[self.catalog_user.username]) catalog = CatalogFactory(viewers=[self.catalog_user.username])
self.mock_catalog_api('api/v1/catalogs/', { self.mock_catalog_endpoint({'results': [catalog.attributes]})
'results': [catalog.attributes]
})
response = self.client.get(self.url) response = self.client.get(self.url)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertIn(catalog.name, response.content.decode('utf-8')) self.assertIn(catalog.name, response.content.decode('utf-8'))
...@@ -281,7 +272,7 @@ class CatalogListViewTest(CatalogTest): ...@@ -281,7 +272,7 @@ class CatalogListViewTest(CatalogTest):
@httpretty.activate @httpretty.activate
def test_get_no_catalogs(self): def test_get_no_catalogs(self):
"""Verify that the view works when no catalogs are set up.""" """Verify that the view works when no catalogs are set up."""
self.mock_catalog_api('api/v1/catalogs/', {}, status_code=404) self.mock_catalog_endpoint({}, status_code=404)
response = self.client.get(self.url) response = self.client.get(self.url)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
...@@ -293,18 +284,16 @@ class CatalogListViewTest(CatalogTest): ...@@ -293,18 +284,16 @@ class CatalogListViewTest(CatalogTest):
'viewers': [self.catalog_user.username] 'viewers': [self.catalog_user.username]
} }
catalog_id = 123 catalog_id = 123
self.mock_catalog_api('api/v1/catalogs/', dict(catalog_data, id=catalog_id), method=httpretty.POST) self.mock_catalog_endpoint(dict(catalog_data, id=catalog_id), method=httpretty.POST)
response = self.client.post(self.url, catalog_data) response = self.client.post(self.url, catalog_data)
self.assertEqual(httpretty.last_request().method, 'POST') self.assertEqual(httpretty.last_request().method, 'POST')
self.mock_catalog_api('api/v1/catalogs/{}/'.format(catalog_id), CatalogFactory().attributes) self.mock_catalog_endpoint(CatalogFactory().attributes, catalog_id=catalog_id)
self.assertRedirects(response, reverse('api_admin:catalog-edit', kwargs={'catalog_id': catalog_id})) self.assertRedirects(response, reverse('api_admin:catalog-edit', kwargs={'catalog_id': catalog_id}))
@httpretty.activate @httpretty.activate
def test_post_invalid(self): def test_post_invalid(self):
catalog = CatalogFactory(viewers=[self.catalog_user.username]) catalog = CatalogFactory(viewers=[self.catalog_user.username])
self.mock_catalog_api('api/v1/catalogs/', { self.mock_catalog_endpoint({'results': [catalog.attributes]})
'results': [catalog.attributes]
})
response = self.client.post(self.url, { response = self.client.post(self.url, {
'name': '', 'name': '',
'query': '*', 'query': '*',
...@@ -317,7 +306,6 @@ class CatalogListViewTest(CatalogTest): ...@@ -317,7 +306,6 @@ class CatalogListViewTest(CatalogTest):
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
class CatalogEditViewTest(CatalogTest): class CatalogEditViewTest(CatalogTest):
def setUp(self): def setUp(self):
super(CatalogEditViewTest, self).setUp() super(CatalogEditViewTest, self).setUp()
self.catalog_user = UserFactory() self.catalog_user = UserFactory()
...@@ -326,17 +314,17 @@ class CatalogEditViewTest(CatalogTest): ...@@ -326,17 +314,17 @@ class CatalogEditViewTest(CatalogTest):
@httpretty.activate @httpretty.activate
def test_get(self): def test_get(self):
self.mock_catalog_api('api/v1/catalogs/{}/'.format(self.catalog.id), self.catalog.attributes) self.mock_catalog_endpoint(self.catalog.attributes, catalog_id=self.catalog.id)
response = self.client.get(self.url) response = self.client.get(self.url)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertIn(self.catalog.name, response.content.decode('utf-8')) self.assertIn(self.catalog.name, response.content.decode('utf-8'))
@httpretty.activate @httpretty.activate
def test_delete(self): def test_delete(self):
self.mock_catalog_api( self.mock_catalog_endpoint(
'api/v1/catalogs/{}/'.format(self.catalog.id),
self.catalog.attributes, self.catalog.attributes,
method=httpretty.DELETE method=httpretty.DELETE,
catalog_id=self.catalog.id
) )
response = self.client.post(self.url, {'delete-catalog': 'on'}) response = self.client.post(self.url, {'delete-catalog': 'on'})
self.assertRedirects(response, reverse('api_admin:catalog-search')) self.assertRedirects(response, reverse('api_admin:catalog-search'))
...@@ -349,18 +337,15 @@ class CatalogEditViewTest(CatalogTest): ...@@ -349,18 +337,15 @@ class CatalogEditViewTest(CatalogTest):
@httpretty.activate @httpretty.activate
def test_edit(self): def test_edit(self):
self.mock_catalog_api( self.mock_catalog_endpoint(self.catalog.attributes, method=httpretty.PATCH, catalog_id=self.catalog.id)
'api/v1/catalogs/{}/'.format(self.catalog.id),
self.catalog.attributes, method=httpretty.PATCH
)
new_attributes = dict(self.catalog.attributes, **{'delete-catalog': 'off', 'name': 'changed'}) new_attributes = dict(self.catalog.attributes, **{'delete-catalog': 'off', 'name': 'changed'})
response = self.client.post(self.url, new_attributes) response = self.client.post(self.url, new_attributes)
self.mock_catalog_api('api/v1/catalogs/{}/'.format(self.catalog.id), new_attributes) self.mock_catalog_endpoint(new_attributes, catalog_id=self.catalog.id)
self.assertRedirects(response, reverse('api_admin:catalog-edit', kwargs={'catalog_id': self.catalog.id})) self.assertRedirects(response, reverse('api_admin:catalog-edit', kwargs={'catalog_id': self.catalog.id}))
@httpretty.activate @httpretty.activate
def test_edit_invalid(self): def test_edit_invalid(self):
self.mock_catalog_api('api/v1/catalogs/{}/'.format(self.catalog.id), self.catalog.attributes) self.mock_catalog_endpoint(self.catalog.attributes, catalog_id=self.catalog.id)
new_attributes = dict(self.catalog.attributes, **{'delete-catalog': 'off', 'name': ''}) new_attributes = dict(self.catalog.attributes, **{'delete-catalog': 'off', 'name': ''})
response = self.client.post(self.url, new_attributes) response = self.client.post(self.url, new_attributes)
self.assertEqual(response.status_code, 400) self.assertEqual(response.status_code, 400)
...@@ -370,7 +355,6 @@ class CatalogEditViewTest(CatalogTest): ...@@ -370,7 +355,6 @@ class CatalogEditViewTest(CatalogTest):
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
class CatalogPreviewViewTest(CatalogTest): class CatalogPreviewViewTest(CatalogTest):
def setUp(self): def setUp(self):
super(CatalogPreviewViewTest, self).setUp() super(CatalogPreviewViewTest, self).setUp()
self.url = reverse('api_admin:catalog-preview') self.url = reverse('api_admin:catalog-preview')
...@@ -378,7 +362,12 @@ class CatalogPreviewViewTest(CatalogTest): ...@@ -378,7 +362,12 @@ class CatalogPreviewViewTest(CatalogTest):
@httpretty.activate @httpretty.activate
def test_get(self): def test_get(self):
data = {'count': 1, 'results': ['test data'], 'next': None, 'prev': None} data = {'count': 1, 'results': ['test data'], 'next': None, 'prev': None}
self.mock_catalog_api('api/v1/courses/', data) httpretty.register_uri(
httpretty.GET,
'{root}/courses/'.format(root=settings.COURSE_CATALOG_API_URL.rstrip('/')),
body=json.dumps(data),
content_type='application/json'
)
response = self.client.get(self.url, {'q': '*'}) response = self.client.get(self.url, {'q': '*'})
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(json.loads(response.content), data) self.assertEqual(json.loads(response.content), data)
......
""" Course Discovery API Service. """ """ Course Discovery API Service. """
import datetime import datetime
import jwt
from django.conf import settings from django.conf import settings
from edx_rest_api_client.client import EdxRestApiClient from edx_rest_api_client.client import EdxRestApiClient
import jwt
from openedx.core.djangoapps.theming import helpers from openedx.core.djangoapps.theming import helpers
from provider.oauth2.models import Client
from student.models import UserProfile, anonymous_id_for_user from student.models import UserProfile, anonymous_id_for_user
CLIENT_NAME = 'course-discovery'
def get_id_token(user): def get_id_token(user):
""" """
...@@ -44,10 +41,9 @@ def get_id_token(user): ...@@ -44,10 +41,9 @@ def get_id_token(user):
} }
secret_key = helpers.get_value('JWT_AUTH', settings.JWT_AUTH)['JWT_SECRET_KEY'] secret_key = helpers.get_value('JWT_AUTH', settings.JWT_AUTH)['JWT_SECRET_KEY']
return jwt.encode(payload, secret_key) return jwt.encode(payload, secret_key).decode('utf-8')
def course_discovery_api_client(user): def course_discovery_api_client(user):
""" Returns a Course Discovery API client setup with authentication for the specified user. """ """ Returns a Course Discovery API client setup with authentication for the specified user. """
course_discovery_client = Client.objects.get(name=CLIENT_NAME) return EdxRestApiClient(settings.COURSE_CATALOG_API_URL, jwt=get_id_token(user))
return EdxRestApiClient(course_discovery_client.url, jwt=get_id_token(user))
...@@ -6,7 +6,6 @@ from django.contrib.sites.shortcuts import get_current_site ...@@ -6,7 +6,6 @@ from django.contrib.sites.shortcuts import get_current_site
from django.core.urlresolvers import reverse_lazy, reverse from django.core.urlresolvers import reverse_lazy, reverse
from django.http.response import JsonResponse from django.http.response import JsonResponse
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils.translation import ugettext as _
from django.views.generic import View from django.views.generic import View
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.views.generic.edit import CreateView from django.views.generic.edit import CreateView
...@@ -144,75 +143,77 @@ class CatalogListView(View): ...@@ -144,75 +143,77 @@ class CatalogListView(View):
def _get_catalogs(self, client, username): def _get_catalogs(self, client, username):
"""Retrieve catalogs for a user. Returns the empty list if none are found.""" """Retrieve catalogs for a user. Returns the empty list if none are found."""
try: try:
response = client.api.v1.catalogs.get(username=username) response = client.catalogs.get(username=username)
return [Catalog(attributes=catalog) for catalog in response['results']] return [Catalog(attributes=catalog) for catalog in response['results']]
except HttpNotFoundError: except HttpNotFoundError:
return [] return []
def get_context_data(self, client, username, form):
""" Retrieve context data for the template. """
return {
'username': username,
'catalogs': self._get_catalogs(client, username),
'form': form,
'preview_url': reverse('api_admin:catalog-preview'),
'catalog_api_catalog_endpoint': client.catalogs.url().rstrip('/'),
'catalog_api_url': client.courses.url(),
}
def get(self, request, username): def get(self, request, username):
"""Display a list of a user's catalogs.""" """Display a list of a user's catalogs."""
client = course_discovery_api_client(request.user) client = course_discovery_api_client(request.user)
catalogs = self._get_catalogs(client, username) form = CatalogForm(initial={'viewers': [username]})
return render_to_response(self.template, { return render_to_response(self.template, self.get_context_data(client, username, form))
'username': username,
'catalogs': catalogs,
'form': CatalogForm(initial={'viewers': [username]}),
'preview_url': reverse('api_admin:catalog-preview'),
'catalog_api_url': client.api.v1.courses.url(),
})
def post(self, request, username): def post(self, request, username):
"""Create a new catalog for a user.""" """Create a new catalog for a user."""
form = CatalogForm(request.POST) form = CatalogForm(request.POST)
client = course_discovery_api_client(request.user) client = course_discovery_api_client(request.user)
if not form.is_valid(): if not form.is_valid():
catalogs = self._get_catalogs(client, username) return render_to_response(self.template, self.get_context_data(client, username, form), status=400)
return render_to_response(self.template, {
'form': form,
'catalogs': catalogs,
'username': username,
'preview_url': reverse('api_admin:catalog-preview'),
'catalog_api_url': client.api.v1.courses.url(),
}, status=400)
attrs = form.instance.attributes attrs = form.instance.attributes
catalog = client.api.v1.catalogs.post(attrs) catalog = client.catalogs.post(attrs)
return redirect(reverse('api_admin:catalog-edit', kwargs={'catalog_id': catalog['id']})) return redirect(reverse('api_admin:catalog-edit', kwargs={'catalog_id': catalog['id']}))
class CatalogEditView(View): class CatalogEditView(View):
"""View to edit an individual catalog.""" """View to edit an individual catalog."""
template_name = 'api_admin/catalogs/edit.html'
def get_context_data(self, catalog, form, client):
""" Retrieve context data for the template. """
return {
'catalog': catalog,
'form': form,
'preview_url': reverse('api_admin:catalog-preview'),
'catalog_api_url': client.courses.url(),
'catalog_api_catalog_endpoint': client.catalogs.url().rstrip('/'),
}
def get(self, request, catalog_id): def get(self, request, catalog_id):
"""Display a form to edit this catalog.""" """Display a form to edit this catalog."""
client = course_discovery_api_client(request.user) client = course_discovery_api_client(request.user)
response = client.api.v1.catalogs(catalog_id).get() response = client.catalogs(catalog_id).get()
catalog = Catalog(attributes=response) catalog = Catalog(attributes=response)
form = CatalogForm(instance=catalog) form = CatalogForm(instance=catalog)
return render_to_response('api_admin/catalogs/edit.html', { return render_to_response(self.template_name, self.get_context_data(catalog, form, client))
'catalog': catalog,
'form': form,
'preview_url': reverse('api_admin:catalog-preview'),
'catalog_api_url': client.api.v1.courses.url(),
})
def post(self, request, catalog_id): def post(self, request, catalog_id):
"""Update or delete this catalog.""" """Update or delete this catalog."""
client = course_discovery_api_client(request.user) client = course_discovery_api_client(request.user)
if request.POST.get('delete-catalog') == 'on': if request.POST.get('delete-catalog') == 'on':
client.api.v1.catalogs(catalog_id).delete() client.catalogs(catalog_id).delete()
return redirect(reverse('api_admin:catalog-search')) return redirect(reverse('api_admin:catalog-search'))
form = CatalogForm(request.POST) form = CatalogForm(request.POST)
if not form.is_valid(): if not form.is_valid():
response = client.api.v1.catalogs(catalog_id).get() response = client.catalogs(catalog_id).get()
catalog = Catalog(attributes=response) catalog = Catalog(attributes=response)
return render_to_response('api_admin/catalogs/edit.html', { return render_to_response(self.template_name, self.get_context_data(catalog, form, client), status=400)
'catalog': catalog, catalog = client.catalogs(catalog_id).patch(form.instance.attributes)
'form': form,
'preview_url': reverse('api_admin:catalog-preview'),
'catalog_api_url': client.api.v1.courses.url(),
}, status=400)
catalog = client.api.v1.catalogs(catalog_id).patch(form.instance.attributes)
return redirect(reverse('api_admin:catalog-edit', kwargs={'catalog_id': catalog['id']})) return redirect(reverse('api_admin:catalog-edit', kwargs={'catalog_id': catalog['id']}))
...@@ -227,7 +228,7 @@ class CatalogPreviewView(View): ...@@ -227,7 +228,7 @@ class CatalogPreviewView(View):
client = course_discovery_api_client(request.user) client = course_discovery_api_client(request.user)
# Just pass along the request params including limit/offset pagination # Just pass along the request params including limit/offset pagination
if 'q' in request.GET: if 'q' in request.GET:
results = client.api.v1.courses.get(**request.GET) results = client.courses.get(**request.GET)
# Ensure that we don't just return all the courses if no query is given # Ensure that we don't just return all the courses if no query is given
else: else:
results = {'count': 0, 'results': [], 'next': None, 'prev': None} results = {'count': 0, 'results': [], 'next': None, 'prev': None}
......
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