diff --git a/cms/djangoapps/contentstore/views/import_export.py b/cms/djangoapps/contentstore/views/import_export.py
index ab0e1574515a..7402b15cadf2 100644
--- a/cms/djangoapps/contentstore/views/import_export.py
+++ b/cms/djangoapps/contentstore/views/import_export.py
@@ -33,7 +33,6 @@
from user_tasks.conf import settings as user_tasks_settings
from user_tasks.models import UserTaskArtifact, UserTaskStatus
-from common.djangoapps.edxmako.shortcuts import render_to_response
from common.djangoapps.util.json_request import JsonResponse
from common.djangoapps.util.monitoring import monitor_import_failure
from common.djangoapps.util.views import ensure_valid_course_key
@@ -43,7 +42,7 @@
from ..storage import course_import_export_storage
from ..tasks import CourseExportTask, CourseImportTask, export_olx, import_olx
-from ..utils import IMPORTABLE_FILE_TYPES, get_export_url, get_import_url, reverse_course_url, reverse_library_url
+from ..utils import IMPORTABLE_FILE_TYPES, get_export_url, get_import_url, reverse_course_url
__all__ = [
'import_handler', 'import_status_handler',
@@ -74,15 +73,10 @@ def import_handler(request, course_key_string):
json: import a course via the .tar.gz or .zip file specified in request.FILES
"""
courselike_key = CourseKey.from_string(course_key_string)
- library = isinstance(courselike_key, LibraryLocator)
- if library:
- successful_url = reverse_library_url('library_handler', courselike_key)
- context_name = 'context_library'
- courselike_block = modulestore().get_library(courselike_key)
- else:
- successful_url = reverse_course_url('course_handler', courselike_key)
- context_name = 'context_course'
- courselike_block = modulestore().get_course(courselike_key)
+ # Legacy (v1) libraries are no longer supported for import. Reject early
+ # to avoid an invalid redirect to the MFE with a library key.
+ if isinstance(courselike_key, LibraryLocator):
+ raise Http404
if not user_has_course_permission(
user=request.user,
authz_permission=COURSES_IMPORT_COURSE.identifier,
@@ -98,17 +92,7 @@ def import_handler(request, course_key_string):
return _write_chunk(request, courselike_key)
elif request.method == 'GET': # assume html
- if not library:
- return redirect(get_import_url(courselike_key))
- status_url = reverse_course_url(
- "import_status_handler", courselike_key, kwargs={'filename': "fillerName"}
- )
- return render_to_response('import.html', {
- context_name: courselike_block,
- 'successful_import_redirect_url': successful_url,
- 'import_status_url': status_url,
- 'library': isinstance(courselike_key, LibraryLocator)
- })
+ return redirect(get_import_url(courselike_key))
else:
return HttpResponseNotFound()
@@ -331,24 +315,8 @@ def export_handler(request, course_key_string):
legacy_permission=LegacyAuthoringPermission.WRITE
):
raise PermissionDenied()
- library = isinstance(course_key, LibraryLocator)
- if library:
- courselike_block = modulestore().get_library(course_key)
- context = {
- 'context_library': courselike_block,
- 'courselike_home_url': reverse_library_url("library_handler", course_key),
- 'library': True
- }
- else:
- courselike_block = modulestore().get_course(course_key)
- if courselike_block is None:
- raise Http404
- context = {
- 'context_course': courselike_block,
- 'courselike_home_url': reverse_course_url("course_handler", course_key),
- 'library': False
- }
- context['status_url'] = reverse_course_url('export_status_handler', course_key)
+ if modulestore().get_course(course_key) is None:
+ raise Http404
# an _accept URL parameter will be preferred over HTTP_ACCEPT in the header.
requested_format = request.GET.get('_accept', request.META.get('HTTP_ACCEPT', 'text/html'))
@@ -357,9 +325,7 @@ def export_handler(request, course_key_string):
export_olx.delay(request.user.id, course_key_string, request.LANGUAGE_CODE)
return JsonResponse({'ExportStatus': 1})
elif 'text/html' in requested_format:
- if not library:
- return redirect(get_export_url(course_key))
- return render_to_response('export.html', context)
+ return redirect(get_export_url(course_key))
else:
# Only HTML request format is supported (no JSON).
return HttpResponse(status=406)
diff --git a/cms/djangoapps/contentstore/views/library.py b/cms/djangoapps/contentstore/views/library.py
index 70ae0bce2c2a..ecce6b1378ff 100644
--- a/cms/djangoapps/contentstore/views/library.py
+++ b/cms/djangoapps/contentstore/views/library.py
@@ -24,16 +24,12 @@
from cms.djangoapps.course_creators.views import get_course_creator_status
from common.djangoapps.edxmako.shortcuts import render_to_response
from common.djangoapps.student.auth import (
- STUDIO_EDIT_ROLES,
- STUDIO_VIEW_USERS,
- get_user_permissions,
has_studio_read_access,
has_studio_write_access,
)
from common.djangoapps.student.roles import (
CourseInstructorRole,
CourseStaffRole,
- LibraryUserRole,
OrgStaffRole,
UserBasedRole,
)
@@ -45,9 +41,8 @@
from ..toggles import libraries_v1_enabled
from ..utils import add_instructor, reverse_library_url
from .component import CONTAINER_TEMPLATES, get_component_templates
-from .user import user_with_role
-__all__ = ['library_handler', 'manage_library_users']
+__all__ = ['library_handler']
log = logging.getLogger(__name__)
@@ -311,42 +306,3 @@ def library_blocks_view(library, user, response_format):
'xblock_info': xblock_info,
'templates': CONTAINER_TEMPLATES,
})
-
-
-def manage_library_users(request, library_key_string):
- """
- Studio UI for editing the users within a library.
-
- Uses the /course_team/:library_key/:user_email/ REST API to make changes.
- """
- library_key = CourseKey.from_string(library_key_string)
- if not isinstance(library_key, LibraryLocator):
- raise Http404 # This is not a library
- user_perms = get_user_permissions(request.user, library_key)
- if not user_perms & STUDIO_VIEW_USERS:
- raise PermissionDenied()
- library = modulestore().get_library(library_key)
- if library is None:
- raise Http404
-
- # Segment all the users explicitly associated with this library, ensuring each user only has one role listed:
- instructors = set(CourseInstructorRole(library_key).users_with_role())
- staff = set(CourseStaffRole(library_key).users_with_role()) - instructors
- users = set(LibraryUserRole(library_key).users_with_role()) - instructors - staff
-
- formatted_users = []
- for user in instructors:
- formatted_users.append(user_with_role(user, 'instructor'))
- for user in staff:
- formatted_users.append(user_with_role(user, 'staff'))
- for user in users:
- formatted_users.append(user_with_role(user, 'library_user'))
-
- return render_to_response('manage_users_lib.html', {
- 'context_library': library,
- 'users': formatted_users,
- 'allow_actions': bool(user_perms & STUDIO_EDIT_ROLES),
- 'library_key': str(library_key),
- 'lib_users_url': reverse_library_url('manage_library_users', library_key_string),
- 'show_children_previews': library.show_children_previews
- })
diff --git a/cms/djangoapps/contentstore/views/tests/test_import_export.py b/cms/djangoapps/contentstore/views/tests/test_import_export.py
index 260992343fdd..8caeb2e84ec1 100644
--- a/cms/djangoapps/contentstore/views/tests/test_import_export.py
+++ b/cms/djangoapps/contentstore/views/tests/test_import_export.py
@@ -723,6 +723,17 @@ def test_import_failure_for_unknown_failures(self, exception, mocked_import, moc
status_response = self.get_import_status(self.course.id, good_file)
self.assertImportStatusResponse(status_response, self.UpdatingError, import_error.UNKNOWN_ERROR_IN_IMPORT)
+ def test_import_handler_rejects_legacy_library_key(self):
+ """
+ Passing a legacy (v1) LibraryLocator key to import_handler must return 404.
+ This guards against the early-reject added in import_handler from being
+ accidentally removed.
+ """
+ lib_key = LibraryLocator(org='TestOrg', library='TestLib')
+ url = reverse_course_url('import_handler', lib_key)
+ resp = self.client.get(url)
+ self.assertEqual(resp.status_code, 404) # noqa: PT009
+
@ddt.data('zip', 'tar')
def test_import_status_response_is_not_cached(self, fmt):
"""To test import_status endpoint response is not cached"""
@@ -945,6 +956,16 @@ def test_export_course_does_not_exist(self, url):
resp = self.client.get_html(url)
self.assertEqual(resp.status_code, 404) # noqa: PT009
+ def test_export_handler_rejects_legacy_library_key(self):
+ """
+ Passing a legacy (v1) LibraryLocator key to export_handler must return 404
+ because modulestore().get_course() returns None for a library key.
+ """
+ lib_key = LibraryLocator(org='TestOrg', library='TestLib')
+ url = reverse_course_url('export_handler', lib_key)
+ resp = self.client.get(url)
+ self.assertEqual(resp.status_code, 404) # noqa: PT009
+
def test_non_course_author(self):
"""
Verify that users who aren't authors of the course are unable to export it
diff --git a/cms/djangoapps/contentstore/views/tests/test_library.py b/cms/djangoapps/contentstore/views/tests/test_library.py
index 172f87addb56..d1c04fec7df0 100644
--- a/cms/djangoapps/contentstore/views/tests/test_library.py
+++ b/cms/djangoapps/contentstore/views/tests/test_library.py
@@ -17,11 +17,10 @@
from organizations.exceptions import InvalidOrganizationException
from cms.djangoapps.contentstore.tests.utils import AjaxEnabledTestClient, CourseTestCase, parse_json
-from cms.djangoapps.contentstore.utils import reverse_course_url, reverse_library_url
from cms.djangoapps.course_creators.models import CourseCreator
from cms.djangoapps.course_creators.views import add_user_with_status_granted as grant_course_creator_status
from common.djangoapps.student import auth
-from common.djangoapps.student.roles import CourseInstructorRole, CourseStaffRole, LibraryUserRole
+from common.djangoapps.student.roles import CourseInstructorRole, CourseStaffRole
from xmodule.modulestore.tests.factories import LibraryFactory # pylint: disable=wrong-import-order
from ..component import get_component_templates
@@ -427,33 +426,6 @@ def test_advanced_problem_types(self):
for advance_problem_type in settings.ADVANCED_PROBLEM_TYPES:
self.assertNotIn(advance_problem_type['component'], problem_type_categories) # noqa: PT009
- def test_manage_library_users(self):
- """
- Simple test that the Library "User Access" view works.
- Also tests that we can use the REST API to assign a user to a library.
- """
- library = LibraryFactory.create()
- extra_user, _ = self.create_non_staff_user()
- manage_users_url = reverse_library_url('manage_library_users', str(library.location.library_key))
-
- response = self.client.get(manage_users_url)
- self.assertEqual(response.status_code, 200) # noqa: PT009
- # extra_user has not been assigned to the library so should not show up in the list:
- self.assertNotContains(response, extra_user.username)
-
- # Now add extra_user to the library:
- user_details_url = reverse_course_url(
- 'course_team_handler',
- library.location.library_key, kwargs={'email': extra_user.email}
- )
- edit_response = self.client.ajax_post(user_details_url, {"role": LibraryUserRole.ROLE})
- self.assertIn(edit_response.status_code, (200, 204)) # noqa: PT009
-
- # Now extra_user should apear in the list:
- response = self.client.get(manage_users_url)
- self.assertEqual(response.status_code, 200) # noqa: PT009
- self.assertContains(response, extra_user.username)
-
def test_component_limits(self):
"""
Test that component limits in libraries are respected.
diff --git a/cms/djangoapps/contentstore/views/user.py b/cms/djangoapps/contentstore/views/user.py
index a5e926e7fefe..21f8680440c2 100644
--- a/cms/djangoapps/contentstore/views/user.py
+++ b/cms/djangoapps/contentstore/views/user.py
@@ -9,13 +9,12 @@
from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.decorators.http import require_http_methods, require_POST
from opaque_keys.edx.keys import CourseKey
-from opaque_keys.edx.locator import LibraryLocator
from cms.djangoapps.course_creators.views import user_requested_access
from common.djangoapps.student import auth
from common.djangoapps.student.auth import STUDIO_EDIT_ROLES, STUDIO_VIEW_USERS, get_user_permissions
from common.djangoapps.student.models import CourseEnrollment
-from common.djangoapps.student.roles import CourseInstructorRole, CourseStaffRole, LibraryUserRole
+from common.djangoapps.student.roles import CourseInstructorRole, CourseStaffRole
from common.djangoapps.util.json_request import JsonResponse, expect_json
from ..utils import get_course_team_url
@@ -95,12 +94,8 @@ def _course_team_user(request, course_key, email):
}
return JsonResponse(msg, 404)
- is_library = isinstance(course_key, LibraryLocator)
# Ordered list of roles: can always move self to the right, but need STUDIO_EDIT_ROLES to move any user left
- if is_library:
- role_hierarchy = (CourseInstructorRole, CourseStaffRole, LibraryUserRole)
- else:
- role_hierarchy = (CourseInstructorRole, CourseStaffRole)
+ role_hierarchy = (CourseInstructorRole, CourseStaffRole)
if request.method == "GET":
# just return info about the user
@@ -164,7 +159,7 @@ def _course_team_user(request, course_key, email):
return JsonResponse(msg, 400)
auth.remove_users(request.user, role, user)
- if new_role and not is_library:
+ if new_role:
# The user may be newly added to this course.
# auto-enroll the user in the course so that "View Live" will work.
CourseEnrollment.enroll(user, course_key)
diff --git a/cms/static/cms/js/spec/main.js b/cms/static/cms/js/spec/main.js
index de76a6dda5a5..019fb2b67887 100644
--- a/cms/static/cms/js/spec/main.js
+++ b/cms/static/cms/js/spec/main.js
@@ -257,7 +257,6 @@
'js/spec/views/paging_spec',
'js/spec/views/pages/course_rerun_spec',
'js/spec/views/pages/index_spec',
- 'js/spec/views/pages/library_users_spec',
'js/spec/views/modals/base_modal_spec',
'js/spec/views/modals/move_xblock_modal_spec'
];
diff --git a/cms/static/js/factories/export.js b/cms/static/js/factories/export.js
index b2e8132064f8..a3ada7502360 100644
--- a/cms/static/js/factories/export.js
+++ b/cms/static/js/factories/export.js
@@ -3,7 +3,7 @@ define([
], function(domReady, Export, $, gettext) {
'use strict';
- return function(courselikeHomeUrl, library, statusUrl) {
+ return function(courselikeHomeUrl, statusUrl) {
var $submitBtn = $('.action-export'),
unloading = false,
previousExport = Export.storedExport(courselikeHomeUrl);
@@ -15,7 +15,7 @@ define([
var startExport = function(e) {
e.preventDefault();
$submitBtn.hide();
- Export.reset(library);
+ Export.reset();
Export.start(statusUrl).then(onComplete);
$.ajax({
type: 'POST',
@@ -30,7 +30,7 @@ define([
if (!unloading) {
$(window).off('beforeunload.import');
- Export.reset(library);
+ Export.reset();
onComplete();
Export.showError(gettext('Your export has failed.'));
@@ -47,7 +47,7 @@ define([
if (previousExport.completed !== true) {
$submitBtn.hide();
}
- Export.resume(library).then(onComplete);
+ Export.resume().then(onComplete);
}
domReady(function() {
diff --git a/cms/static/js/factories/manage_users_lib.js b/cms/static/js/factories/manage_users_lib.js
deleted file mode 100644
index 434eb3baa77f..000000000000
--- a/cms/static/js/factories/manage_users_lib.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- Code for editing users and assigning roles within a library context.
-*/
-define(['underscore', 'gettext', 'js/views/manage_users_and_roles'],
- function(_, gettext, ManageUsersAndRoles) {
- 'use strict';
-
- return function(containerName, users, tplUserURL, current_user_id, allow_actions) {
- function updateMessages(messages) {
- var local_messages = _.extend({}, messages);
- local_messages.alreadyMember.title = gettext('Already a library team member');
- local_messages.deleteUser.messageTpl = gettext(
- 'Are you sure you want to delete {email} from the library “{container}”?'
- );
- return local_messages;
- }
- // Roles order are important: first role is considered initial role (the role added to user when (s)he's added
- // Last role is considered an admin role (unrestricted access + ability to manage other users' permissions)
- // Changing roles is performed in promote-demote fashion, so moves only to adjacent roles is allowed
- var roles = [
- {key: 'library_user', name: gettext('Library User')},
- {key: 'staff', name: gettext('Staff')},
- {key: 'instructor', name: gettext('Admin')}
- ];
-
- var options = {
- el: $('#content'),
- containerName: containerName,
- tplUserURL: tplUserURL,
- roles: roles,
- users: users,
- messages_modifier: updateMessages,
- current_user_id: current_user_id,
- allow_actions: allow_actions
- };
-
- var view = new ManageUsersAndRoles(options);
- view.render();
- };
- });
diff --git a/cms/static/js/features/import/factories/import.js b/cms/static/js/features/import/factories/import.js
index d9fe7b06fab4..78ad40261a2a 100644
--- a/cms/static/js/features/import/factories/import.js
+++ b/cms/static/js/features/import/factories/import.js
@@ -12,8 +12,8 @@ define([
const IMPORTABLE_FILE_TYPES = /\.tar\.gz$|\.zip$/;
return {
- Import: function(feedbackUrl, library) {
- var dbError,
+ Import: function(feedbackUrl) {
+ var dbError = gettext('There was an error while importing the new course to our database.'),
$bar = $('.progress-bar'),
$fill = $('.progress-fill'),
$submitBtn = $('.submit-button'),
@@ -52,12 +52,6 @@ define([
}
};
- if (library) {
- dbError = gettext('There was an error while importing the new library to our database.');
- } else {
- dbError = gettext('There was an error while importing the new course to our database.');
- }
-
$(window).on('beforeunload', function() { unloading = true; });
// Display the status of last file upload on page load
diff --git a/cms/static/js/spec/views/pages/library_users_spec.js b/cms/static/js/spec/views/pages/library_users_spec.js
deleted file mode 100644
index 08dd6065eb9c..000000000000
--- a/cms/static/js/spec/views/pages/library_users_spec.js
+++ /dev/null
@@ -1,172 +0,0 @@
-define([
- 'jquery', 'sinon', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers', 'common/js/spec_helpers/view_helpers',
- 'js/factories/manage_users_lib', 'common/js/components/utils/view_utils'
-],
-function($, sinon, AjaxHelpers, ViewHelpers, ManageUsersFactory, ViewUtils) {
- 'use strict';
-
- var requests, xhrFactory;
-
- describe('Library Instructor Access Page', function() {
- var changeRoleUrl = 'dummy_change_role_url/@@EMAIL@@';
- var team_member_fixture = readFixtures('team-member.underscore');
-
- function setRole(email, role) {
- var $user_li = $('li.user-item[data-email="' + email + '"]');
- var $role_action = $('li.action-role a.make-' + role, $user_li);
- expect($role_action).toBeVisible();
- $role_action.click();
- }
-
- function getUrl(email) {
- return changeRoleUrl.replace('@@EMAIL@@', email);
- }
-
- describe('read-write access', function() {
- var mockHTML = readFixtures('mock/mock-manage-users-lib.underscore');
-
- beforeEach(function(done) {
- xhrFactory = sinon.useFakeXMLHttpRequest();
- requests = [];
- requests.currentIndex = 0;
- requests.restore = function() { xhrFactory.restore(); };
- xhrFactory.onCreate = function(req) { requests.push(req); };
- ViewHelpers.installMockAnalytics();
- setFixtures(mockHTML);
- appendSetFixtures($('
-%block>
-
-<%block name="content">
-
-
-
-
- ${_("Settings")}
- > ${_("User Access")}
-
-
-
-
-
-
-
-
-
- %if allow_actions:
-
-
-
- %endif
-
-
-
-
${_("Loading")}
-
-
-
- % if allow_actions and len(users) == 1:
-
-
-
${_('Add More Users to This Library')}
-
-
${_('Grant other members of your course team access to this library. New library users must have an active {studio_name} account.').format(studio_name=settings.STUDIO_SHORT_NAME)}