diff --git a/cms/djangoapps/contentstore/views/library.py b/cms/djangoapps/contentstore/views/library.py index 0b9a38543a07b3b8b24a14ae1582ad6c5d2b5a79..7b912fcc7d35c1b97e76fc5dea80eab5a286e2f8 100644 --- a/cms/djangoapps/contentstore/views/library.py +++ b/cms/djangoapps/contentstore/views/library.py @@ -17,6 +17,8 @@ from django.views.decorators.http import require_http_methods from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import LibraryLocator, LibraryUsageLocator +from organizations.api import ensure_organization +from organizations.exceptions import InvalidOrganizationException from six import text_type from cms.djangoapps.course_creators.views import get_course_creator_status @@ -183,6 +185,7 @@ def _create_library(request): try: display_name = request.json['display_name'] org = request.json['org'] + ensure_organization(org) library = request.json.get('number', None) if library is None: library = request.json['library'] @@ -215,6 +218,13 @@ def _create_library(request): 'change your library code so that it is unique within your organization.' ) }) + except InvalidOrganizationException: + log.exception("Unable to create library - %s is not a valid org short_name.", org) + return JsonResponseBadRequest({ + 'ErrMsg': _( + "'{organization_key}' is not a valid organization identifier." + ).format(organization_key=org) + }) lib_key_str = text_type(new_lib.location.library_key) return JsonResponse({ diff --git a/cms/djangoapps/contentstore/views/tests/test_library.py b/cms/djangoapps/contentstore/views/tests/test_library.py index 96d3f68012fa09b5e79f8d83fe435f3158980b4b..3f3dfd576838099c67871bda7fde671576a7b40c 100644 --- a/cms/djangoapps/contentstore/views/tests/test_library.py +++ b/cms/djangoapps/contentstore/views/tests/test_library.py @@ -8,10 +8,13 @@ More important high-level tests are in contentstore/tests/test_libraries.py import ddt import mock from django.conf import settings +from django.test.utils import override_settings from django.urls import reverse from mock import patch +from organizations.api import get_organization_by_short_name +from organizations.exceptions import InvalidOrganizationException from opaque_keys.edx.locator import CourseKey, LibraryLocator -from six import binary_type, text_type +from six import text_type from six.moves import range from cms.djangoapps.contentstore.tests.utils import AjaxEnabledTestClient, CourseTestCase, parse_json @@ -125,7 +128,7 @@ class UnitTestLibraries(CourseTestCase): """ # Create some more libraries libraries = [LibraryFactory.create() for _ in range(3)] - lib_dict = dict([(lib.location.library_key, lib) for lib in libraries]) + lib_dict = {lib.location.library_key: lib for lib in libraries} response = self.client.get_json(LIBRARY_REST_URL) self.assertEqual(response.status_code, 200) @@ -227,6 +230,41 @@ class UnitTestLibraries(CourseTestCase): self.assertIn('already a library defined', parse_json(response)['ErrMsg']) self.assertEqual(response.status_code, 400) + @override_settings(ORGANIZATIONS_AUTOCREATE=True) + def test_library_with_unknown_organization_autocreation(self): + """ + Test that when automatic organization creation is enabled, + creating a content library with an unknown organization auto-creates + said organization. + """ + with self.assertRaises(InvalidOrganizationException): + get_organization_by_short_name("org_xyz") + response = self.client.ajax_post(LIBRARY_REST_URL, { + 'org': "org_xyz", + 'library': "org_test_lib", + 'display_name': "This library's organization doesn't exist... yet.", + }) + assert response.status_code == 200 + assert get_organization_by_short_name("org_xyz") + + @override_settings(ORGANIZATIONS_AUTOCREATE=False) + def test_library_with_unknown_organization_validation_error(self): + """ + Test that when automatic organization creation is disabled, + creating a content library with an unknown organization raises an error. + """ + with self.assertRaises(InvalidOrganizationException): + get_organization_by_short_name("org_xyz") + response = self.client.ajax_post(LIBRARY_REST_URL, { + 'org': "org_xyz", + 'library': "org_test_lib", + 'display_name': "This library's organization doesn't exist!", + }) + assert response.status_code == 400 + assert "'org_xyz' is not a valid organization identifier" in parse_json(response)['ErrMsg'] + with self.assertRaises(InvalidOrganizationException): + get_organization_by_short_name("org_xyz") + ###################################################### # Tests for /library/:lib_key/ - get a specific library as JSON or HTML editing view @@ -308,7 +346,11 @@ class UnitTestLibraries(CourseTestCase): lib.save() problem_type_templates = next( - (component['templates'] for component in get_component_templates(lib, library=True) if component['type'] == 'problem'), + ( + component['templates'] + for component in get_component_templates(lib, library=True) + if component['type'] == 'problem' + ), [] ) # Each problem template has a category which shows whether problem is a 'problem'