Added DjangoSudo functionality for instructor dashboard and course team page
This commit is contained in:
committed by
Awais Jibran
parent
ae0e21b32a
commit
bc052db1ee
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user