Added DjangoSudo functionality for instructor dashboard and course team page

This commit is contained in:
Waheed Ahmed
2015-01-13 09:36:08 -05:00
committed by Awais Jibran
parent ae0e21b32a
commit bc052db1ee
88 changed files with 1227 additions and 553 deletions

View File

@@ -33,6 +33,7 @@ Feature: CMS.Help
Then I should see online help for "grading"
And I am viewing the course team settings
And I get sudo access with password "test"
Then I should see online help for "course-team"
And I select the Advanced Settings

View File

@@ -1343,6 +1343,7 @@ class ContentStoreTest(ContentStoreTestCase):
resp = self._show_course_overview(course_key)
self.assertEqual(resp.status_code, 200)
self.assertContains(resp, 'Chapter 2')
self.grant_sudo_access(unicode(course_key), self.user_password)
# go to various pages
test_get_html('import_handler')

View File

@@ -22,10 +22,10 @@ class TestCourseAccess(ModuleStoreTestCase):
Create a pool of users w/o granting them any permissions
"""
user_password = super(TestCourseAccess, self).setUp()
self.user_password = super(TestCourseAccess, self).setUp()
self.client = AjaxEnabledTestClient()
self.client.login(username=self.user.username, password=user_password)
self.client.login(username=self.user.username, password=self.user_password)
# create a course via the view handler which has a different strategy for permissions than the factory
self.course_key = self.store.make_course_key('myu', 'mydept.mycourse', 'myrun')
@@ -93,6 +93,7 @@ class TestCourseAccess(ModuleStoreTestCase):
user_by_role[role].append(user)
self.assertTrue(auth.has_course_author_access(user, self.course_key), "{} does not have access".format(user))
self.grant_sudo_access(unicode(self.course_key), self.user_password)
course_team_url = reverse_course_url('course_team_handler', self.course_key)
response = self.client.get_html(course_team_url)
for role in [CourseInstructorRole, CourseStaffRole]: # Global and org-based roles don't appear on this page

View File

@@ -29,6 +29,7 @@ from opaque_keys.edx.keys import UsageKey
from student.auth import has_course_author_access
from django.utils.translation import ugettext as _
from sudo.utils import revoke_sudo_privileges
from models.settings.course_grading import CourseGradingModel
__all__ = ['OPEN_ENDED_COMPONENT_TYPES',
@@ -163,6 +164,12 @@ def container_handler(request, usage_key_string):
with modulestore().bulk_operations(usage_key.course_key):
try:
course, xblock, lms_link, preview_lms_link = _get_item_in_course(request, usage_key)
# Revoke sudo privileges from a request explicitly
region = unicode(course.id)
if request.is_sudo(region=region):
revoke_sudo_privileges(request, region=region)
except ItemNotFoundError:
return HttpResponseBadRequest()

View File

@@ -17,6 +17,8 @@ from django.conf import settings
from django.utils.translation import ugettext as _
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import ensure_csrf_cookie
from django_sudo_helpers.decorators import sudo_required
from sudo.utils import revoke_sudo_privileges
from edxmako.shortcuts import render_to_response
from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey
@@ -68,6 +70,11 @@ def _display_library(library_key_string, request):
"""
Displays single library
"""
# Revoke sudo privileges from a request explicitly
if request.is_sudo(region=library_key_string):
revoke_sudo_privileges(request, region=library_key_string)
library_key = CourseKey.from_string(library_key_string)
if not isinstance(library_key, LibraryLocator):
log.exception("Non-library key passed to content libraries API.") # Should never happen due to url regex
@@ -197,6 +204,7 @@ def library_blocks_view(library, user, response_format):
})
@sudo_required
def manage_library_users(request, library_key_string):
"""
Studio UI for editing the users within a library.

View File

@@ -12,6 +12,7 @@ from django.utils import http
import contentstore.views.component as views
from contentstore.views.tests.utils import StudioPageTestCase
from django_sudo_helpers.tests.utils import sudo_middleware_process_request
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.tests.factories import ItemFactory
@@ -171,6 +172,7 @@ class ContainerPageTestCase(StudioPageTestCase):
"""
request = RequestFactory().get('foo')
request.user = self.user
sudo_middleware_process_request(request)
# Check for invalid 'usage_key_strings'
self.assertRaises(

View File

@@ -114,6 +114,7 @@ class TestCourseIndex(CourseTestCase):
"""
course_staff_client, course_staff = self.create_non_staff_authed_user_client()
for course in [self.course, self.odd_course]:
self.grant_sudo_access(unicode(course.id), 'foo')
permission_url = reverse_course_url('course_team_handler', course.id, kwargs={'email': course_staff.email})
self.client.post(

View File

@@ -30,10 +30,10 @@ class UnitTestLibraries(ModuleStoreTestCase):
"""
def setUp(self):
user_password = super(UnitTestLibraries, self).setUp()
self.user_password = super(UnitTestLibraries, self).setUp()
self.client = AjaxEnabledTestClient()
self.client.login(username=self.user.username, password=user_password)
self.client.login(username=self.user.username, password=self.user_password)
######################################################
# Tests for /library/ - list and create libraries:
@@ -207,6 +207,7 @@ class UnitTestLibraries(ModuleStoreTestCase):
"""
library = LibraryFactory.create()
extra_user, _ = self.create_non_staff_user()
self.grant_sudo_access(unicode(library.location.library_key), self.user_password)
manage_users_url = reverse_library_url('manage_library_users', unicode(library.location.library_key))
response = self.client.get(manage_users_url)

View File

@@ -14,6 +14,7 @@ from student import auth
class UsersTestCase(CourseTestCase):
def setUp(self):
super(UsersTestCase, self).setUp()
self.grant_sudo_access(unicode(self.course.id), self.user_password)
self.ext_user = User.objects.create_user(
"joe", "joe@comedycentral.com", "haha")
self.ext_user.is_active = True

View File

@@ -11,6 +11,7 @@ from xmodule.modulestore.django import modulestore
from opaque_keys.edx.keys import CourseKey
from opaque_keys.edx.locator import LibraryLocator
from util.json_request import JsonResponse, expect_json
from django_sudo_helpers.decorators import sudo_required
from student.roles import CourseInstructorRole, CourseStaffRole, LibraryUserRole
from course_creators.views import user_requested_access
@@ -38,6 +39,7 @@ def request_course_creator(request):
@login_required
@ensure_csrf_cookie
@require_http_methods(("GET", "POST", "PUT", "DELETE"))
@sudo_required
def course_team_handler(request, course_key_string=None, email=None):
"""
The restful handler for course team users.

View File

@@ -5,7 +5,7 @@ django admin page for the course creators table
from course_creators.models import CourseCreator, update_creator_state, send_user_notification, send_admin_notification
from course_creators.views import update_course_creator_group
from ratelimitbackend import admin
from django.contrib import admin
from django.conf import settings
from django.dispatch import receiver
from edxmako.shortcuts import render_to_string

View File

@@ -11,6 +11,7 @@ import mock
from course_creators.admin import CourseCreatorAdmin
from course_creators.models import CourseCreator
from django.core import mail
from sudo.utils import region_name
from student.roles import CourseCreatorRole
from student import auth
@@ -46,6 +47,16 @@ class CourseCreatorAdminTest(TestCase):
"STUDIO_REQUEST_EMAIL": self.studio_request_email
}
def grant_sudo_access(self, region, password):
"""
Grant sudo access to staff or instructor user.
"""
self.client.post(
'/sudo/?region={}'.format(region_name(region)),
{'password': password},
follow=True
)
@mock.patch('course_creators.admin.render_to_string', mock.Mock(side_effect=mock_render_to_string, autospec=True))
@mock.patch('django.contrib.auth.models.User.email_user')
def test_change_status(self, email_user):
@@ -161,6 +172,7 @@ class CourseCreatorAdminTest(TestCase):
self.assertFalse(self.creator_admin.has_change_permission(self.request))
def test_rate_limit_login(self):
self.grant_sudo_access('django_admin', 'foo')
with mock.patch.dict('django.conf.settings.FEATURES', {'ENABLE_CREATOR_GROUP': True}):
post_params = {'username': self.user.username, 'password': 'wrong_password'}
# try logging in 30 times, the default limit in the number of failed