From 4e455fd87fd567c6ebac9d593c56e499bc015c92 Mon Sep 17 00:00:00 2001 From: Don Mitchell Date: Mon, 21 Oct 2013 14:38:03 -0400 Subject: [PATCH] Limit read access to people with write access. Add unit tests for auth --- .../contentstore/tests/test_orphan.py | 16 +++++++++++++ cms/djangoapps/contentstore/tests/utils.py | 2 +- cms/djangoapps/contentstore/views/item.py | 23 +++++++++++++------ 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/cms/djangoapps/contentstore/tests/test_orphan.py b/cms/djangoapps/contentstore/tests/test_orphan.py index 566cc0cf56..c51c808f00 100644 --- a/cms/djangoapps/contentstore/tests/test_orphan.py +++ b/cms/djangoapps/contentstore/tests/test_orphan.py @@ -5,6 +5,7 @@ import json from contentstore.tests.utils import CourseTestCase from xmodule.modulestore.django import editable_modulestore from django.core.urlresolvers import reverse +from student.models import CourseEnrollment class TestOrphan(CourseTestCase): """ @@ -70,3 +71,18 @@ class TestOrphan(CourseTestCase): self.client.get(url, HTTP_ACCEPT='application/json').content ) self.assertEqual(len(orphans), 0, "Orphans not deleted {}".format(orphans)) + + def test_not_permitted(self): + """ + Test that auth restricts get and delete appropriately + """ + test_user_client, test_user = self.createNonStaffAuthedUserClient() + CourseEnrollment.enroll(test_user, self.course.location.course_id) + url = reverse( + 'orphan', + kwargs={'course_id': '{}.{}'.format(self.course.location.org, self.course.location.course)} + ) + response = test_user_client.get(url) + self.assertEqual(response.status_code, 403) + response = test_user_client.delete(url) + self.assertEqual(response.status_code, 403) diff --git a/cms/djangoapps/contentstore/tests/utils.py b/cms/djangoapps/contentstore/tests/utils.py index 6c00ab4111..03ad159822 100644 --- a/cms/djangoapps/contentstore/tests/utils.py +++ b/cms/djangoapps/contentstore/tests/utils.py @@ -65,7 +65,7 @@ class CourseTestCase(ModuleStoreTestCase): def createNonStaffAuthedUserClient(self): """ - Create a non-staff user, log them in, and return the client to use for testing. + Create a non-staff user, log them in, and return the client, user to use for testing. """ uname = 'teststudent' password = 'foo' diff --git a/cms/djangoapps/contentstore/views/item.py b/cms/djangoapps/contentstore/views/item.py index 273cc6ebd9..16fbb32a6b 100644 --- a/cms/djangoapps/contentstore/views/item.py +++ b/cms/djangoapps/contentstore/views/item.py @@ -7,7 +7,7 @@ from django.core.exceptions import PermissionDenied from django.contrib.auth.decorators import login_required from xmodule.modulestore import Location -from xmodule.modulestore.django import modulestore +from xmodule.modulestore.django import modulestore, loc_mapper from xmodule.modulestore.inheritance import own_metadata from xmodule.modulestore.exceptions import ItemNotFoundError, InvalidLocationError @@ -21,6 +21,8 @@ from .access import has_access from .helpers import _xmodule_recurse from xmodule.x_module import XModuleDescriptor from django.views.decorators.http import require_http_methods +from xmodule.modulestore.locator import CourseLocator +from student.models import CourseEnrollment __all__ = ['save_item', 'create_item', 'delete_item', 'orphan'] @@ -216,10 +218,17 @@ def orphan(request, course_id): :param request: :param course_id: Locator syntax course_id """ + course_loc = CourseLocator(course_id=course_id) if request.method == 'GET': - return JsonResponse(modulestore().get_orphans(course_id, DETACHED_CATEGORIES, 'draft')) - if request.method == 'DELETE' and request.user.is_staff: - items = modulestore().get_orphans(course_id, DETACHED_CATEGORIES, 'draft') - for item in items: - modulestore('draft').delete_item(item, True) - return JsonResponse({'deleted': items}) + if has_access(request.user, course_loc): + return JsonResponse(modulestore().get_orphans(course_id, DETACHED_CATEGORIES, 'draft')) + else: + raise PermissionDenied() + if request.method == 'DELETE': + if request.user.is_staff: + items = modulestore().get_orphans(course_id, DETACHED_CATEGORIES, 'draft') + for item in items: + modulestore('draft').delete_item(item, True) + return JsonResponse({'deleted': items}) + else: + raise PermissionDenied()