diff --git a/cms/djangoapps/contentstore/features/help.feature b/cms/djangoapps/contentstore/features/help.feature
index 9e7da805f2..567a2f2526 100644
--- a/cms/djangoapps/contentstore/features/help.feature
+++ b/cms/djangoapps/contentstore/features/help.feature
@@ -33,7 +33,6 @@ 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
diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py
index bac6b41199..79feeae460 100644
--- a/cms/djangoapps/contentstore/tests/test_contentstore.py
+++ b/cms/djangoapps/contentstore/tests/test_contentstore.py
@@ -1343,7 +1343,6 @@ 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')
diff --git a/cms/djangoapps/contentstore/tests/test_permissions.py b/cms/djangoapps/contentstore/tests/test_permissions.py
index f2253d0c4d..f509e807f2 100644
--- a/cms/djangoapps/contentstore/tests/test_permissions.py
+++ b/cms/djangoapps/contentstore/tests/test_permissions.py
@@ -22,10 +22,10 @@ class TestCourseAccess(ModuleStoreTestCase):
Create a pool of users w/o granting them any permissions
"""
- self.user_password = super(TestCourseAccess, self).setUp()
+ user_password = super(TestCourseAccess, self).setUp()
self.client = AjaxEnabledTestClient()
- self.client.login(username=self.user.username, password=self.user_password)
+ self.client.login(username=self.user.username, password=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,7 +93,6 @@ 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
diff --git a/cms/djangoapps/contentstore/views/component.py b/cms/djangoapps/contentstore/views/component.py
index 6435123beb..994af7c1db 100644
--- a/cms/djangoapps/contentstore/views/component.py
+++ b/cms/djangoapps/contentstore/views/component.py
@@ -29,7 +29,6 @@ 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',
@@ -164,12 +163,6 @@ 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()
diff --git a/cms/djangoapps/contentstore/views/library.py b/cms/djangoapps/contentstore/views/library.py
index 6a88c9c80d..1323aa4f09 100644
--- a/cms/djangoapps/contentstore/views/library.py
+++ b/cms/djangoapps/contentstore/views/library.py
@@ -17,8 +17,6 @@ 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
@@ -70,11 +68,6 @@ 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
@@ -204,7 +197,6 @@ 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.
diff --git a/cms/djangoapps/contentstore/views/tests/test_container_page.py b/cms/djangoapps/contentstore/views/tests/test_container_page.py
index 032f6b268d..b22e06327f 100644
--- a/cms/djangoapps/contentstore/views/tests/test_container_page.py
+++ b/cms/djangoapps/contentstore/views/tests/test_container_page.py
@@ -12,7 +12,6 @@ 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
@@ -172,7 +171,6 @@ class ContainerPageTestCase(StudioPageTestCase):
"""
request = RequestFactory().get('foo')
request.user = self.user
- sudo_middleware_process_request(request)
# Check for invalid 'usage_key_strings'
self.assertRaises(
diff --git a/cms/djangoapps/contentstore/views/tests/test_course_index.py b/cms/djangoapps/contentstore/views/tests/test_course_index.py
index 397ee36caa..fa3a97cffb 100644
--- a/cms/djangoapps/contentstore/views/tests/test_course_index.py
+++ b/cms/djangoapps/contentstore/views/tests/test_course_index.py
@@ -114,7 +114,6 @@ 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(
diff --git a/cms/djangoapps/contentstore/views/tests/test_library.py b/cms/djangoapps/contentstore/views/tests/test_library.py
index 51d87dc4b4..9e1abbbdf0 100644
--- a/cms/djangoapps/contentstore/views/tests/test_library.py
+++ b/cms/djangoapps/contentstore/views/tests/test_library.py
@@ -30,10 +30,10 @@ class UnitTestLibraries(ModuleStoreTestCase):
"""
def setUp(self):
- self.user_password = super(UnitTestLibraries, self).setUp()
+ user_password = super(UnitTestLibraries, self).setUp()
self.client = AjaxEnabledTestClient()
- self.client.login(username=self.user.username, password=self.user_password)
+ self.client.login(username=self.user.username, password=user_password)
######################################################
# Tests for /library/ - list and create libraries:
@@ -207,7 +207,6 @@ 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)
diff --git a/cms/djangoapps/contentstore/views/tests/test_user.py b/cms/djangoapps/contentstore/views/tests/test_user.py
index c2e058904b..ce99a266ef 100644
--- a/cms/djangoapps/contentstore/views/tests/test_user.py
+++ b/cms/djangoapps/contentstore/views/tests/test_user.py
@@ -14,7 +14,6 @@ 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
diff --git a/cms/djangoapps/contentstore/views/user.py b/cms/djangoapps/contentstore/views/user.py
index 27d84051f4..7ee92c0ba4 100644
--- a/cms/djangoapps/contentstore/views/user.py
+++ b/cms/djangoapps/contentstore/views/user.py
@@ -11,7 +11,6 @@ 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
@@ -39,7 +38,6 @@ 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.
diff --git a/cms/djangoapps/course_creators/admin.py b/cms/djangoapps/course_creators/admin.py
index 2fd7260c48..5eaa8c4ac3 100644
--- a/cms/djangoapps/course_creators/admin.py
+++ b/cms/djangoapps/course_creators/admin.py
@@ -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 django.contrib import admin
+from ratelimitbackend import admin
from django.conf import settings
from django.dispatch import receiver
from edxmako.shortcuts import render_to_string
diff --git a/cms/djangoapps/course_creators/tests/test_admin.py b/cms/djangoapps/course_creators/tests/test_admin.py
index 057550c280..47131cb198 100644
--- a/cms/djangoapps/course_creators/tests/test_admin.py
+++ b/cms/djangoapps/course_creators/tests/test_admin.py
@@ -11,7 +11,6 @@ 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
@@ -47,16 +46,6 @@ 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):
@@ -172,7 +161,6 @@ 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
diff --git a/cms/envs/common.py b/cms/envs/common.py
index d9efbcc665..a683dce912 100644
--- a/cms/envs/common.py
+++ b/cms/envs/common.py
@@ -319,9 +319,6 @@ MIDDLEWARE_CLASSES = (
# catches any uncaught RateLimitExceptions and returns a 403 instead of a 500
'ratelimitbackend.middleware.RateLimitMiddleware',
- # force re-authentication before activating administrative functions
- 'sudo.middleware.SudoMiddleware',
-
# for expiring inactive sessions
'session_inactivity_timeout.middleware.SessionInactivityTimeout',
@@ -764,9 +761,6 @@ INSTALLED_APPS = (
'openedx.core.djangoapps.credit',
'xblock_django',
-
- # Allows sudo-mode
- 'sudo',
)
diff --git a/cms/static/sass/elements/_modal.scss b/cms/static/sass/elements/_modal.scss
index c1dc3a8ca2..3d9c4663cc 100644
--- a/cms/static/sass/elements/_modal.scss
+++ b/cms/static/sass/elements/_modal.scss
@@ -70,129 +70,3 @@
width: 100%;
background: $black;
}
-
-.sudo-modal {
- @extend .modal;
- background: $shadow-d2;
- border: 1px solid rgba(0, 0, 0, 0.9);
- border-radius: 0;
- box-shadow: 0 15px 80px 15px rgba(0,0,0, 0.5);
- color: $white;
- display: none;
- left: 50%;
- padding: 8px;
- position: absolute;
- width: 480px;
- height: auto;
-
- .inner-wrapper {
- @extend %ui-depth1;
- background: rgb(245,245,245);
- border-radius: 0;
- border: 1px solid rgba(0, 0, 0, 0.9);
- box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.7);
- overflow: hidden;
- padding-left: ($baseline/2);
- padding-right: ($baseline/2);
- padding-bottom: ($baseline/2);
- position: relative;
-
- header {
- @extend %ui-depth1;
- overflow: hidden;
- padding: 28px $baseline 0;
- position: relative;
-
- &::before {
- @include background-image(radial-gradient(50% 50%, circle closest-side, rgba(255,255,255, 0.8) 0%, rgba(255,255,255, 0) 100%));
- content: "";
- display: block;
- height: 400px;
- left: 0;
- margin: 0 auto;
- position: absolute;
- top: -140px;
- width: 100%;
- z-index: 1;
- }
-
- hr {
- border: none;
- margin: 0;
- position: relative;
- z-index: 2;
-
- &::after {
- bottom: 0;
- content: "";
- display: block;
- position: absolute;
- top: -1px;
- }
- }
-
- h2 {
- position: relative;
- text-align: center;
- text-shadow: 0 1px rgba(255,255,255, 0.4);
- z-index: 2;
- }
- }
-
- form {
- margin-bottom: 12px;
- padding: 0 ($baseline*2) $baseline;
- position: relative;
- z-index: 2;
-
- label {
- color: rgb(51, 51, 51);
-
- &.field-error {
- display: block;
- color: #8F0E0E;
-
- + input, + textarea {
- border: 1px solid #CA1111;
- color: #8F0E0E;
- }
- }
- }
-
- input[type="password"] {
- background: rgb(255,255,255);
- display: block;
- height: 45px;
- margin-bottom: $baseline;
- width: 100%;
- }
-
- input[type="submit"] {
- border: 1px solid #CFC6C6;
- border-radius: 3px;
- box-shadow: 0px 1px 0px 0px #FFF inset;
- color: #333;
- display: inline-block;
- font-weight: bold;
- background-color: #EEE;
- background-image: linear-gradient(#EEE, #D6CECE);
- padding: 12px 18px;
- text-decoration: none;
- text-shadow: 0px 1px 0px #F9F8F8;
- background-clip: padding-box;
- font-size: 0.8125em;
- }
- }
- }
-}
-
-#sudo_overlay {
- position: fixed;
- top: 0px;
- left: 0px;
- display: block;
- height: 100%;
- width: 100%;
- background: #000;
- opacity: 0.5;
-}
diff --git a/cms/templates/sudo/sudo.html b/cms/templates/sudo/sudo.html
deleted file mode 100644
index bd2017c759..0000000000
--- a/cms/templates/sudo/sudo.html
+++ /dev/null
@@ -1,42 +0,0 @@
-{% block body %}
- {% load i18n %}
- {% load compressed %}
- {% compressed_css 'style-main' %}
-
-
-
-
-
- {% trans "Confirm Your Password to Access the Course Team Settings" %}
-
-
-
-
-
-
-
-
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/cms/urls.py b/cms/urls.py
index df148530a3..2c69ccfea1 100644
--- a/cms/urls.py
+++ b/cms/urls.py
@@ -2,8 +2,7 @@ from django.conf import settings
from django.conf.urls import patterns, include, url
# There is a course creators admin table.
-from edx_admin import admin
-
+from ratelimitbackend import admin
admin.autodiscover()
# pylint: disable=bad-continuation
@@ -51,8 +50,6 @@ urlpatterns = patterns(
url(r'^heartbeat$', include('heartbeat.urls')),
url(r'^user_api/', include('openedx.core.djangoapps.user_api.legacy_urls')),
-
- url(r'^sudo/$', 'sudo.views.sudo'),
)
# User creation and updating views
diff --git a/common/djangoapps/course_modes/admin.py b/common/djangoapps/course_modes/admin.py
index 4ace2e48f1..ac3c9efaa4 100644
--- a/common/djangoapps/course_modes/admin.py
+++ b/common/djangoapps/course_modes/admin.py
@@ -3,7 +3,7 @@ Django admin page for course modes
"""
from django.conf import settings
from pytz import timezone, UTC
-from django.contrib import admin
+from ratelimitbackend import admin
from course_modes.models import CourseMode
from django import forms
diff --git a/common/djangoapps/course_modes/tests/test_views.py b/common/djangoapps/course_modes/tests/test_views.py
index f24fe0ac09..3883a5acd8 100644
--- a/common/djangoapps/course_modes/tests/test_views.py
+++ b/common/djangoapps/course_modes/tests/test_views.py
@@ -380,7 +380,6 @@ class AdminCourseModePageTest(ModuleStoreTestCase):
}
self.client.login(username=user.username, password='test')
- self.grant_sudo_access('django_admin', 'test')
# creating new course mode from django admin page
response = self.client.post(reverse('admin:course_modes_coursemode_add'), data=data)
diff --git a/common/djangoapps/django_sudo_helpers/__init__.py b/common/djangoapps/django_sudo_helpers/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/common/djangoapps/django_sudo_helpers/decorators.py b/common/djangoapps/django_sudo_helpers/decorators.py
deleted file mode 100644
index 8d1fb11da9..0000000000
--- a/common/djangoapps/django_sudo_helpers/decorators.py
+++ /dev/null
@@ -1,61 +0,0 @@
-"""
-Custom decorator for django-sudo.
-"""
-from functools import wraps
-
-from sudo.settings import RESET_TOKEN
-from sudo.utils import new_sudo_token_on_activity
-from sudo.views import redirect_to_sudo
-from util.json_request import JsonResponse
-
-
-def sudo_required(func_or_region):
- """
- Enforces a view to have elevated privileges.
- Should likely be paired with ``@login_required``.
-
- >>> @sudo_required
- >>> def secure_page(request):
- >>> ...
-
- Can also specify a particular sudo region (to only
- allow access to that region).
-
- Also get course_id, course_key_string and library_key_string
- from kwargs and set as region if region itself is None.
-
- >>> @sudo_required('admin_page')
- >>> def secure_admin_page(request):
- >>> ...
- """
- def wrapper(func): # pylint: disable=missing-docstring
- @wraps(func)
- def inner(request, *args, **kwargs): # pylint: disable=missing-docstring
- course_specific_region = kwargs.get('course_id')
- if 'course_key_string' in kwargs:
- course_specific_region = kwargs.get('course_key_string')
- if 'library_key_string' in kwargs:
- course_specific_region = kwargs.get('library_key_string')
-
- # N.B. region is captured from the enclosing sudo_required function
- if not request.is_sudo(region=region or course_specific_region):
- response_format = request.REQUEST.get('format', 'html')
- if (response_format == 'json' or
- 'application/json' in request.META.get('HTTP_ACCEPT', 'application/json')):
- return JsonResponse({'error': 'Unauthorized'}, status=401)
-
- return redirect_to_sudo(request.get_full_path(), region=region or course_specific_region)
-
- if RESET_TOKEN is True:
- # Provide new sudo token content and reset timeout on activity
- new_sudo_token_on_activity(request, region=region or course_specific_region)
-
- return func(request, *args, **kwargs)
- return inner
-
- if callable(func_or_region):
- region = None
- return wrapper(func_or_region)
- else:
- region = func_or_region
- return wrapper
diff --git a/common/djangoapps/django_sudo_helpers/tests/__init__.py b/common/djangoapps/django_sudo_helpers/tests/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/common/djangoapps/django_sudo_helpers/tests/utils.py b/common/djangoapps/django_sudo_helpers/tests/utils.py
deleted file mode 100644
index 02dc68a30e..0000000000
--- a/common/djangoapps/django_sudo_helpers/tests/utils.py
+++ /dev/null
@@ -1,15 +0,0 @@
-"""
-django_sudo_heplers.utils
-"""
-import django.contrib.sessions.middleware
-import sudo.middleware
-
-
-def sudo_middleware_process_request(request):
- """
- Initialize the session and is_sudo on request object.
- """
- session_middleware = django.contrib.sessions.middleware.SessionMiddleware()
- session_middleware.process_request(request)
- sudo_middleware = sudo.middleware.SudoMiddleware()
- sudo_middleware.process_request(request)
diff --git a/common/djangoapps/edx_admin/__init__.py b/common/djangoapps/edx_admin/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/common/djangoapps/edx_admin/admin.py b/common/djangoapps/edx_admin/admin.py
deleted file mode 100644
index 6b7669dc99..0000000000
--- a/common/djangoapps/edx_admin/admin.py
+++ /dev/null
@@ -1,31 +0,0 @@
-"""
-RatelimitSudoAdminSite
-"""
-
-from django.contrib.admin import * # pylint: disable=wildcard-import, unused-wildcard-import
-from django.contrib.admin import (site as django_site,
- autodiscover as django_autodiscover)
-from ratelimitbackend.admin import RateLimitAdminSite
-from sudo.admin import SudoAdminSite
-
-
-class RatelimitSudoAdminSite(RateLimitAdminSite, SudoAdminSite):
- """
- A class that includes the features of both RateLimitAdminSite and SudoAdminSite
- """
- pass
-
-
-site = RatelimitSudoAdminSite() # pylint: disable=invalid-name
-
-
-def autodiscover(): # pylint: disable=function-redefined
- """
- Auto-Discover admin models.
- """
- django_autodiscover()
-
- # pylint: disable=protected-access
- for model, modeladmin in django_site._registry.items():
- if model not in site._registry:
- site.register(model, modeladmin.__class__)
diff --git a/common/djangoapps/edx_admin/models.py b/common/djangoapps/edx_admin/models.py
deleted file mode 100644
index 0f4957a236..0000000000
--- a/common/djangoapps/edx_admin/models.py
+++ /dev/null
@@ -1,3 +0,0 @@
-"""
-This space intentionally left blank
-"""
diff --git a/common/djangoapps/external_auth/admin.py b/common/djangoapps/external_auth/admin.py
index 1ee18dadc1..fad0917604 100644
--- a/common/djangoapps/external_auth/admin.py
+++ b/common/djangoapps/external_auth/admin.py
@@ -3,7 +3,7 @@ django admin pages for courseware model
'''
from external_auth.models import *
-from django.contrib import admin
+from ratelimitbackend import admin
class ExternalAuthMapAdmin(admin.ModelAdmin):
diff --git a/common/djangoapps/student/admin.py b/common/djangoapps/student/admin.py
index 1ec853ae59..7f355da572 100644
--- a/common/djangoapps/student/admin.py
+++ b/common/djangoapps/student/admin.py
@@ -9,7 +9,7 @@ from student.models import UserProfile, UserTestGroup, CourseEnrollmentAllowed,
from student.models import (
CourseEnrollment, Registration, PendingNameChange, CourseAccessRole, LinkedInAddToProfileConfiguration
)
-from django.contrib import admin
+from ratelimitbackend import admin
from student.roles import REGISTERED_ACCESS_ROLES
from xmodule.modulestore.django import modulestore
diff --git a/common/djangoapps/student/tests/test_admin_views.py b/common/djangoapps/student/tests/test_admin_views.py
index 6e28f97381..910bfe474e 100644
--- a/common/djangoapps/student/tests/test_admin_views.py
+++ b/common/djangoapps/student/tests/test_admin_views.py
@@ -17,9 +17,6 @@ class AdminCourseRolesPageTest(ModuleStoreTestCase):
self.user.save()
self.course = CourseFactory.create(org='edx')
- self.client.login(username=self.user.username, password='test')
- self.grant_sudo_access('django_admin', 'test')
-
def test_save_valid_data(self):
data = {
@@ -29,6 +26,8 @@ class AdminCourseRolesPageTest(ModuleStoreTestCase):
'email': self.user.email
}
+ self.client.login(username=self.user.username, password='test')
+
# # adding new role from django admin page
response = self.client.post(reverse('admin:student_courseaccessrole_add'), data=data)
self.assertRedirects(response, reverse('admin:student_courseaccessrole_changelist'))
@@ -52,6 +51,8 @@ class AdminCourseRolesPageTest(ModuleStoreTestCase):
'course_id': unicode(self.course.id)
}
+ self.client.login(username=self.user.username, password='test')
+
# # adding new role from django admin page
response = self.client.post(reverse('admin:student_courseaccessrole_add'), data=data)
self.assertRedirects(response, reverse('admin:student_courseaccessrole_changelist'))
@@ -68,6 +69,8 @@ class AdminCourseRolesPageTest(ModuleStoreTestCase):
}
+ self.client.login(username=self.user.username, password='test')
+
# # adding new role from django admin page
response = self.client.post(reverse('admin:student_courseaccessrole_add'), data=data)
self.assertRedirects(response, reverse('admin:student_courseaccessrole_changelist'))
@@ -85,6 +88,8 @@ class AdminCourseRolesPageTest(ModuleStoreTestCase):
}
+ self.client.login(username=self.user.username, password='test')
+
# # adding new role from django admin page
response = self.client.post(reverse('admin:student_courseaccessrole_add'), data=data)
self.assertRedirects(response, reverse('admin:student_courseaccessrole_changelist'))
@@ -104,6 +109,8 @@ class AdminCourseRolesPageTest(ModuleStoreTestCase):
'email': email
}
+ self.client.login(username=self.user.username, password='test')
+
# Adding new role with invalid data
response = self.client.post(reverse('admin:student_courseaccessrole_add'), data=data)
self.assertContains(
@@ -129,6 +136,8 @@ class AdminCourseRolesPageTest(ModuleStoreTestCase):
'email': self.user.email
}
+ self.client.login(username=self.user.username, password='test')
+
# # adding new role from django admin page
response = self.client.post(reverse('admin:student_courseaccessrole_add'), data=data)
self.assertContains(
diff --git a/common/djangoapps/terrain/steps.py b/common/djangoapps/terrain/steps.py
index f87d81e076..7006c42389 100644
--- a/common/djangoapps/terrain/steps.py
+++ b/common/djangoapps/terrain/steps.py
@@ -241,23 +241,3 @@ def view_course_team_settings(_step, whom):
world.click_course_settings()
link_css = 'li.nav-course-settings-team a'
world.css_click(link_css)
-
-
-@step('I get sudo access with password "([^"]*)"$')
-def i_get_sudo_access(_step, password):
- """
- Get sudo access for instructor or staff user.
- Set the password value of the element to the specified password.
- Note that wait_for empty is due to password field
- It will return password like this **** not text.
- """
-
- sudo_form = world.css_find('form.sudo-form')
- # check if sudo form is available then submit password to get sudo access
- # otherwise return True because sudo access already given.
- if len(sudo_form) > 0:
- css_selector = 'input[id=id_password]'
- world.retry_on_exception(lambda: world.css_find(css_selector)[0].fill(password))
- world.wait_for(lambda _: not world.css_has_value(css_selector, '', index=0))
- world.css_click('input[type=submit]')
- return True
diff --git a/common/djangoapps/track/admin.py b/common/djangoapps/track/admin.py
index d75f206846..e0835f5a8a 100644
--- a/common/djangoapps/track/admin.py
+++ b/common/djangoapps/track/admin.py
@@ -3,6 +3,6 @@ django admin pages for courseware model
'''
from track.models import TrackingLog
-from django.contrib import admin
+from ratelimitbackend import admin
admin.site.register(TrackingLog)
diff --git a/common/djangoapps/util/admin.py b/common/djangoapps/util/admin.py
index 8b20fc9fa1..de82409cc3 100644
--- a/common/djangoapps/util/admin.py
+++ b/common/djangoapps/util/admin.py
@@ -1,6 +1,6 @@
"""Admin interface for the util app. """
-from django.contrib import admin
+from ratelimitbackend import admin
from util.models import RateLimitConfiguration
diff --git a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py
index f84f840172..2a05094abc 100644
--- a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py
+++ b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py
@@ -17,7 +17,6 @@ from request_cache.middleware import RequestCache
from courseware.field_overrides import OverrideFieldData # pylint: disable=import-error
from openedx.core.lib.tempdir import mkdtemp_clean
-from sudo.utils import region_name
from xmodule.contentstore.django import _CONTENTSTORE
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.django import modulestore, clear_existing_modulestores
@@ -423,13 +422,3 @@ class ModuleStoreTestCase(TestCase):
fields={"display_name": "Syllabus"},
)
return self.toy_loc
-
- 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
- )
diff --git a/common/test/acceptance/pages/common/sudo_page.py b/common/test/acceptance/pages/common/sudo_page.py
deleted file mode 100644
index cfb9af4d12..0000000000
--- a/common/test/acceptance/pages/common/sudo_page.py
+++ /dev/null
@@ -1,57 +0,0 @@
-"""
-Django sudo page to get sudo access.
-"""
-
-from bok_choy.javascript import wait_for_js
-from bok_choy.page_object import PageObject
-
-
-class SudoPage(PageObject):
- """
- Sudo page to get sudo access
- """
- SUDO_FORM = 'form.sudo-form'
-
- def __init__(self, browser, redirect_page):
- super(SudoPage, self).__init__(browser)
- self.redirect_page = redirect_page
-
- def is_browser_on_page(self):
- return self.q(css=self.SUDO_FORM).present
-
- @property
- def url(self):
- """
- Construct a URL to the page which needs sudo access.
- """
- return self.redirect_page.url
-
- @property
- def sudo_password_input(self):
- """
- Returns sudo password input box.
- """
- return self.q(css='{} input[id=id_password]'.format(self.SUDO_FORM))
-
- @property
- def submit_button(self):
- """
- Returns submit button.
- """
- return self.q(css='{} input[type=submit]'.format(self.SUDO_FORM))
-
- @wait_for_js
- def submit_sudo_password_and_get_access(self, password):
- """
- Fill password in input field and click submit.
- """
- input_box = self.sudo_password_input.first.results[0]
- input_box.send_keys(password)
- self.click_submit()
- self.redirect_page.wait_for_page()
-
- def click_submit(self):
- """
- Click on submit button.
- """
- return self.submit_button.click()
diff --git a/common/test/acceptance/pages/lms/instructor_dashboard.py b/common/test/acceptance/pages/lms/instructor_dashboard.py
index f3e836c28a..b6c494e9a3 100644
--- a/common/test/acceptance/pages/lms/instructor_dashboard.py
+++ b/common/test/acceptance/pages/lms/instructor_dashboard.py
@@ -759,14 +759,12 @@ class DataDownloadPage(PageObject):
return self.report_download_links.map(lambda el: el.text)
-# pylint: disable=invalid-name
class StudentAdminPage(PageObject):
"""
Student admin section of the Instructor dashboard.
"""
url = None
- ENTRANCE_EXAM_CONTAINER = ".entrance-exam-grade-container"
- SG_CONTAINER = ".student-grade-container"
+ EE_CONTAINER = ".entrance-exam-grade-container"
def is_browser_on_page(self):
"""
@@ -775,161 +773,89 @@ class StudentAdminPage(PageObject):
return self.q(css='a[data-section=student_admin].active-section').present
@property
- def entrance_exam_student_email_input(self):
+ def student_email_input(self):
"""
- Returns email address/username input box for entrance exam.
+ Returns email address/username input box.
"""
- return self.q(css='{} input[name=entrance-exam-student-select-grade]'.format(self.ENTRANCE_EXAM_CONTAINER))
-
- @property
- def entrance_exam_reset_attempts_button(self):
- """
- Returns reset student attempts button for entrance exam.
- """
- return self.q(css='{} input[name=reset-entrance-exam-attempts]'.format(self.ENTRANCE_EXAM_CONTAINER))
-
- @property
- def entrance_exam_rescore_submission_button(self):
- """
- Returns rescore student submission button for entrance exam.
- """
- return self.q(css='{} input[name=rescore-entrance-exam]'.format(self.ENTRANCE_EXAM_CONTAINER))
-
- @property
- def skip_entrance_exam_button(self):
- """
- Return Let Student Skip Entrance Exam button.
- """
- return self.q(css='{} input[name=skip-entrance-exam]'.format(self.ENTRANCE_EXAM_CONTAINER))
-
- @property
- def entrance_exam_delete_student_state_button(self):
- """
- Returns delete student state button for entrance exam.
- """
- return self.q(css='{} input[name=delete-entrance-exam-state]'.format(self.ENTRANCE_EXAM_CONTAINER))
-
- @property
- def background_task_history_button(self):
- """
- Returns show background task history for student button for entrance exam.
- """
- return self.q(css='{} input[name=entrance-exam-task-history]'.format(self.ENTRANCE_EXAM_CONTAINER))
-
- @property
- def entrance_exam_top_notification(self):
- """
- Returns show background task history for student button for entrance exam.
- """
- return self.q(css='{} .request-response-error'.format(self.ENTRANCE_EXAM_CONTAINER)).first
+ return self.q(css='{} input[name=entrance-exam-student-select-grade]'.format(self.EE_CONTAINER))
@property
def reset_attempts_button(self):
"""
Returns reset student attempts button.
"""
- return self.q(css='{} input[name=reset-attempts-single]'.format(self.SG_CONTAINER))
+ return self.q(css='{} input[name=reset-entrance-exam-attempts]'.format(self.EE_CONTAINER))
@property
def rescore_submission_button(self):
"""
Returns rescore student submission button.
"""
- return self.q(css='{} input[name=rescore-problem-single]'.format(self.SG_CONTAINER))
+ return self.q(css='{} input[name=rescore-entrance-exam]'.format(self.EE_CONTAINER))
+
+ @property
+ def skip_entrance_exam_button(self):
+ """
+ Return Let Student Skip Entrance Exam button.
+ """
+ return self.q(css='{} input[name=skip-entrance-exam]'.format(self.EE_CONTAINER))
@property
def delete_student_state_button(self):
"""
Returns delete student state button.
"""
- return self.q(css='{} input[name=delete-state-single]'.format(self.SG_CONTAINER))
+ return self.q(css='{} input[name=delete-entrance-exam-state]'.format(self.EE_CONTAINER))
+
+ @property
+ def background_task_history_button(self):
+ """
+ Returns show background task history for student button.
+ """
+ return self.q(css='{} input[name=entrance-exam-task-history]'.format(self.EE_CONTAINER))
@property
def top_notification(self):
"""
Returns show background task history for student button.
"""
- return self.q(css='{} .request-response-error'.format(self.SG_CONTAINER)).first
+ return self.q(css='{} .request-response-error'.format(self.EE_CONTAINER)).first
- def is_entrance_exam_student_email_input_visible(self):
+ def is_student_email_input_visible(self):
"""
- Returns True if student email address/username input box is present
- for entrance exam.
+ Returns True if student email address/username input box is present.
"""
- return self.entrance_exam_student_email_input.is_present()
+ return self.student_email_input.is_present()
- def is_entrance_exam_reset_attempts_button_visible(self):
+ def is_reset_attempts_button_visible(self):
"""
- Returns True if reset student attempts button is present
- for entrance exam.
+ Returns True if reset student attempts button is present.
"""
- return self.entrance_exam_reset_attempts_button.is_present()
+ return self.reset_attempts_button.is_present()
- def is_entrance_exam_rescore_submission_button_visible(self):
+ def is_rescore_submission_button_visible(self):
"""
- Returns True if rescore student submission button is present
- for entrance exam.
+ Returns True if rescore student submission button is present.
"""
- return self.entrance_exam_rescore_submission_button.is_present()
+ return self.rescore_submission_button.is_present()
- def is_entrance_exam_delete_student_state_button_visible(self):
+ def is_delete_student_state_button_visible(self):
"""
- Returns True if delete student state for entrance exam button is present
- for entrance exam.
+ Returns True if delete student state for entrance exam button is present.
"""
- return self.entrance_exam_delete_student_state_button.is_present()
+ return self.delete_student_state_button.is_present()
def is_background_task_history_button_visible(self):
"""
- Returns True if show background task history for student button is present
- for entrance exam.
+ Returns True if show background task history for student button is present.
"""
return self.background_task_history_button.is_present()
def is_background_task_history_table_visible(self):
"""
- Returns True if background task history table is present
- for entrance exam.
+ Returns True if background task history table is present.
"""
- return self.q(css='{} .entrance-exam-task-history-table'.format(self.ENTRANCE_EXAM_CONTAINER)).is_present()
-
- def entrance_exam_click_reset_attempts_button(self):
- """
- clicks reset student attempts button for entrance exam.
- """
- return self.entrance_exam_reset_attempts_button.click()
-
- def entrance_exam_click_rescore_submissions_button(self):
- """
- clicks rescore submissions button for entrance exam.
- """
- return self.entrance_exam_rescore_submission_button.click()
-
- def click_skip_entrance_exam_button(self):
- """
- clicks let student skip entrance exam button for entrance exam.
- """
- return self.skip_entrance_exam_button.click()
-
- def entrance_exam_click_delete_student_state_button(self):
- """
- clicks delete student state button for entrance exam.
- """
- return self.entrance_exam_delete_student_state_button.click()
-
- def entrance_exam_click_task_history_button(self):
- """
- clicks background task history button for entrance exam.
- """
- return self.background_task_history_button.click()
-
- def set_student_email_for_ee(self, email_addres):
- """
- Sets given email address as value of student email address/username input box
- for entrance exam.
- """
- input_box = self.entrance_exam_student_email_input.first.results[0]
- input_box.send_keys(email_addres)
+ return self.q(css='{} .entrance-exam-task-history-table'.format(self.EE_CONTAINER)).is_present()
def click_reset_attempts_button(self):
"""
@@ -943,13 +869,30 @@ class StudentAdminPage(PageObject):
"""
return self.rescore_submission_button.click()
+ def click_skip_entrance_exam_button(self):
+ """
+ clicks let student skip entrance exam button.
+ """
+ return self.skip_entrance_exam_button.click()
+
def click_delete_student_state_button(self):
"""
- clicks delete student state button and confirm the action.
+ clicks delete student state button.
"""
- with self.handle_alert(confirm=True):
- self.delete_student_state_button.click()
- self.wait_for_ajax()
+ return self.delete_student_state_button.click()
+
+ def click_task_history_button(self):
+ """
+ clicks background task history button.
+ """
+ return self.background_task_history_button.click()
+
+ def set_student_email(self, email_addres):
+ """
+ Sets given email address as value of student email address/username input box.
+ """
+ input_box = self.student_email_input.first.results[0]
+ input_box.send_keys(email_addres)
class CertificatesPage(PageObject):
diff --git a/common/test/acceptance/pages/lms/staff_view.py b/common/test/acceptance/pages/lms/staff_view.py
index 64a3451e82..b4eeb5d505 100644
--- a/common/test/acceptance/pages/lms/staff_view.py
+++ b/common/test/acceptance/pages/lms/staff_view.py
@@ -68,14 +68,31 @@ class StaffDebugPage(PageObject):
def is_browser_on_page(self):
return self.q(css='section.staff-modal').present
- def click_student_grade_adjustments(self, user=None):
+ def reset_attempts(self, user=None):
"""
This clicks on the reset attempts link with an optionally
specified user.
"""
if user:
self.q(css='input[id^=sd_fu_]').first.fill(user)
- self.q(css='section.staff-modal a.staff-debug-grade-adjustments').click()
+ self.q(css='section.staff-modal a.staff-debug-reset').click()
+
+ def delete_state(self, user=None):
+ """
+ This delete's a student's state for the problem
+ """
+ if user:
+ self.q(css='input[id^=sd_fu_]').fill(user)
+ self.q(css='section.staff-modal a.staff-debug-sdelete').click()
+
+ def rescore(self, user=None):
+ """
+ This clicks on the reset attempts link with an optionally
+ specified user.
+ """
+ if user:
+ self.q(css='input[id^=sd_fu_]').first.fill(user)
+ self.q(css='section.staff-modal a.staff-debug-rescore').click()
@property
def idash_msg(self):
diff --git a/common/test/acceptance/tests/discussion/test_cohort_management.py b/common/test/acceptance/tests/discussion/test_cohort_management.py
index 0d4fcd8cfb..921f471dbf 100644
--- a/common/test/acceptance/tests/discussion/test_cohort_management.py
+++ b/common/test/acceptance/tests/discussion/test_cohort_management.py
@@ -9,7 +9,7 @@ from pytz import UTC, utc
from bok_choy.promise import EmptyPromise
from nose.plugins.attrib import attr
from .helpers import CohortTestMixin
-from ..helpers import UniqueCourseTest, EventsTestMixin, create_user_partition_json, get_sudo_access
+from ..helpers import UniqueCourseTest, EventsTestMixin, create_user_partition_json
from xmodule.partitions.partitions import Group
from ...fixtures.course import CourseFixture, XBlockFixtureDesc
from ...pages.lms.auto_auth import AutoAuthPage
@@ -53,16 +53,14 @@ class CohortConfigurationTest(EventsTestMixin, UniqueCourseTest, CohortTestMixin
).visit().get_user_id()
# login as an instructor
- instructor_password = 'test'
self.instructor_name = "instructor_user"
self.instructor_id = AutoAuthPage(
self.browser, username=self.instructor_name, email="instructor_user@example.com",
- course_id=self.course_id, staff=True, password=instructor_password
+ course_id=self.course_id, staff=True
).visit().get_user_id()
# go to the membership page on the instructor dashboard
self.instructor_dashboard_page = InstructorDashboardPage(self.browser, self.course_id)
- get_sudo_access(self.browser, self.instructor_dashboard_page, instructor_password)
self.instructor_dashboard_page.visit()
self.cohort_management_page = self.instructor_dashboard_page.select_cohort_management()
@@ -650,16 +648,14 @@ class CohortDiscussionTopicsTest(UniqueCourseTest, CohortTestMixin):
self.cohort_id = self.add_manual_cohort(self.course_fixture, self.cohort_name)
# login as an instructor
- self.instructor_password = 'test'
self.instructor_name = "instructor_user"
self.instructor_id = AutoAuthPage(
self.browser, username=self.instructor_name, email="instructor_user@example.com",
- course_id=self.course_id, staff=True, password=self.instructor_password
+ course_id=self.course_id, staff=True
).visit().get_user_id()
# go to the membership page on the instructor dashboard
self.instructor_dashboard_page = InstructorDashboardPage(self.browser, self.course_id)
- get_sudo_access(self.browser, self.instructor_dashboard_page, self.instructor_password)
self.instructor_dashboard_page.visit()
self.cohort_management_page = self.instructor_dashboard_page.select_cohort_management()
self.cohort_management_page.wait_for_page()
@@ -944,16 +940,14 @@ class CohortContentGroupAssociationTest(UniqueCourseTest, CohortTestMixin):
})
# login as an instructor
- instructor_password = 'test'
self.instructor_name = "instructor_user"
self.instructor_id = AutoAuthPage(
self.browser, username=self.instructor_name, email="instructor_user@example.com",
- course_id=self.course_id, staff=True, password=instructor_password
+ course_id=self.course_id, staff=True
).visit().get_user_id()
# go to the membership page on the instructor dashboard
self.instructor_dashboard_page = InstructorDashboardPage(self.browser, self.course_id)
- get_sudo_access(self.browser, self.instructor_dashboard_page, instructor_password)
self.instructor_dashboard_page.visit()
self.cohort_management_page = self.instructor_dashboard_page.select_cohort_management()
diff --git a/common/test/acceptance/tests/helpers.py b/common/test/acceptance/tests/helpers.py
index 3c2e45e15d..1b8b597520 100644
--- a/common/test/acceptance/tests/helpers.py
+++ b/common/test/acceptance/tests/helpers.py
@@ -25,7 +25,6 @@ from selenium.webdriver.support.select import Select
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from unittest import TestCase
-from ..pages.common.sudo_page import SudoPage
from ..pages.common import BASE_URL
@@ -685,12 +684,3 @@ class TestWithSearchIndexMixin(object):
def _cleanup_index_file(self):
""" Removes search index backing file """
remove_file(self.TEST_INDEX_FILENAME)
-
-
-def get_sudo_access(browser, redirect_page, password):
- """
- Get sudo access for instructor or staff user.
- """
- sudo_password_page = SudoPage(browser, redirect_page)
- sudo_password_page.visit()
- sudo_password_page.submit_sudo_password_and_get_access(password)
diff --git a/common/test/acceptance/tests/lms/test_lms_cohorted_courseware_search.py b/common/test/acceptance/tests/lms/test_lms_cohorted_courseware_search.py
index da6905f116..323d1bebf0 100644
--- a/common/test/acceptance/tests/lms/test_lms_cohorted_courseware_search.py
+++ b/common/test/acceptance/tests/lms/test_lms_cohorted_courseware_search.py
@@ -9,7 +9,6 @@ from ...pages.studio.overview import CourseOutlinePage
from ...pages.lms.courseware_search import CoursewareSearchPage
from ...pages.lms.staff_view import StaffPage
from ...fixtures.course import XBlockFixtureDesc
-from ..helpers import get_sudo_access
from nose.plugins.attrib import attr
@@ -84,13 +83,13 @@ class CoursewareSearchCohortTest(ContainerBase):
super(CoursewareSearchCohortTest, self).tearDown()
os.remove(self.TEST_INDEX_FILENAME)
- def _auto_auth(self, username, email, staff, password='test'):
+ def _auto_auth(self, username, email, staff):
"""
Logout and login with given credentials.
"""
LogoutPage(self.browser).visit()
StudioAutoAuthPage(self.browser, username=username, email=email,
- course_id=self.course_id, staff=staff, password=password).visit()
+ course_id=self.course_id, staff=staff).visit()
def _studio_reindex(self):
"""
@@ -194,7 +193,7 @@ class CoursewareSearchCohortTest(ContainerBase):
Each cohort is assigned one student.
"""
instructor_dashboard_page = InstructorDashboardPage(self.browser, self.course_id)
- get_sudo_access(self.browser, instructor_dashboard_page, 'test')
+ instructor_dashboard_page.visit()
cohort_management_page = instructor_dashboard_page.select_cohort_management()
def add_cohort_with_student(cohort_name, content_group, student):
diff --git a/common/test/acceptance/tests/lms/test_lms_instructor_dashboard.py b/common/test/acceptance/tests/lms/test_lms_instructor_dashboard.py
index de598cde13..0b1fc27b18 100644
--- a/common/test/acceptance/tests/lms/test_lms_instructor_dashboard.py
+++ b/common/test/acceptance/tests/lms/test_lms_instructor_dashboard.py
@@ -6,7 +6,7 @@ End-to-end tests for the LMS Instructor Dashboard.
from nose.plugins.attrib import attr
from bok_choy.promise import EmptyPromise
-from ..helpers import UniqueCourseTest, get_modal_alert, EventsTestMixin, get_sudo_access
+from ..helpers import UniqueCourseTest, get_modal_alert, EventsTestMixin
from ...pages.common.logout import LogoutPage
from ...pages.lms.auto_auth import AutoAuthPage
from ...pages.lms.instructor_dashboard import InstructorDashboardPage
@@ -22,9 +22,7 @@ class BaseInstructorDashboardTest(EventsTestMixin, UniqueCourseTest):
Logs in as an instructor and returns the id.
"""
username = "test_instructor_{uuid}".format(uuid=self.unique_id[0:6])
- auto_auth_page = AutoAuthPage(
- self.browser, username=username, course_id=self.course_id, staff=True, password="test"
- )
+ auto_auth_page = AutoAuthPage(self.browser, username=username, course_id=self.course_id, staff=True)
return username, auto_auth_page.visit().get_user_id()
def visit_instructor_dashboard(self):
@@ -32,7 +30,6 @@ class BaseInstructorDashboardTest(EventsTestMixin, UniqueCourseTest):
Visits the instructor dashboard.
"""
instructor_dashboard_page = InstructorDashboardPage(self.browser, self.course_id)
- get_sudo_access(self.browser, instructor_dashboard_page, "test")
instructor_dashboard_page.visit()
return instructor_dashboard_page
@@ -145,10 +142,10 @@ class EntranceExamGradeTest(BaseInstructorDashboardTest):
Then I see Student Email input box, Reset Student Attempt, Rescore Student Submission,
Delete Student State for entrance exam and Show Background Task History for Student buttons
"""
- self.assertTrue(self.student_admin_section.is_entrance_exam_student_email_input_visible())
- self.assertTrue(self.student_admin_section.is_entrance_exam_reset_attempts_button_visible())
- self.assertTrue(self.student_admin_section.is_entrance_exam_rescore_submission_button_visible())
- self.assertTrue(self.student_admin_section.is_entrance_exam_delete_student_state_button_visible())
+ self.assertTrue(self.student_admin_section.is_student_email_input_visible())
+ self.assertTrue(self.student_admin_section.is_reset_attempts_button_visible())
+ self.assertTrue(self.student_admin_section.is_rescore_submission_button_visible())
+ self.assertTrue(self.student_admin_section.is_delete_student_state_button_visible())
self.assertTrue(self.student_admin_section.is_background_task_history_button_visible())
def test_clicking_reset_student_attempts_button_without_email_shows_error(self):
@@ -161,10 +158,10 @@ class EntranceExamGradeTest(BaseInstructorDashboardTest):
Then I should be shown an Error Notification
And The Notification message should read 'Please enter a student email address or username.'
"""
- self.student_admin_section.entrance_exam_click_reset_attempts_button()
+ self.student_admin_section.click_reset_attempts_button()
self.assertEqual(
'Please enter a student email address or username.',
- self.student_admin_section.entrance_exam_top_notification.text[0]
+ self.student_admin_section.top_notification.text[0]
)
def test_clicking_reset_student_attempts_button_with_success(self):
@@ -177,8 +174,8 @@ class EntranceExamGradeTest(BaseInstructorDashboardTest):
email address or username
Then I should be shown an alert with success message
"""
- self.student_admin_section.set_student_email_for_ee(self.student_identifier)
- self.student_admin_section.entrance_exam_click_reset_attempts_button()
+ self.student_admin_section.set_student_email(self.student_identifier)
+ self.student_admin_section.click_reset_attempts_button()
alert = get_modal_alert(self.student_admin_section.browser)
alert.dismiss()
@@ -191,10 +188,10 @@ class EntranceExamGradeTest(BaseInstructorDashboardTest):
Adjustment after non existing student email address or username
Then I should be shown an error message
"""
- self.student_admin_section.set_student_email_for_ee('non_existing@example.com')
- self.student_admin_section.entrance_exam_click_reset_attempts_button()
+ self.student_admin_section.set_student_email('non_existing@example.com')
+ self.student_admin_section.click_reset_attempts_button()
self.student_admin_section.wait_for_ajax()
- self.assertGreater(len(self.student_admin_section.entrance_exam_top_notification.text[0]), 0)
+ self.assertGreater(len(self.student_admin_section.top_notification.text[0]), 0)
def test_clicking_rescore_submission_button_with_success(self):
"""
@@ -205,8 +202,8 @@ class EntranceExamGradeTest(BaseInstructorDashboardTest):
Adjustment after entering a valid student email address or username
Then I should be shown an alert with success message
"""
- self.student_admin_section.set_student_email_for_ee(self.student_identifier)
- self.student_admin_section.entrance_exam_click_rescore_submissions_button()
+ self.student_admin_section.set_student_email(self.student_identifier)
+ self.student_admin_section.click_rescore_submissions_button()
alert = get_modal_alert(self.student_admin_section.browser)
alert.dismiss()
@@ -219,10 +216,10 @@ class EntranceExamGradeTest(BaseInstructorDashboardTest):
Adjustment after non existing student email address or username
Then I should be shown an error message
"""
- self.student_admin_section.set_student_email_for_ee('non_existing@example.com')
- self.student_admin_section.entrance_exam_click_rescore_submissions_button()
+ self.student_admin_section.set_student_email('non_existing@example.com')
+ self.student_admin_section.click_rescore_submissions_button()
self.student_admin_section.wait_for_ajax()
- self.assertGreater(len(self.student_admin_section.entrance_exam_top_notification.text[0]), 0)
+ self.assertGreater(len(self.student_admin_section.top_notification.text[0]), 0)
def test_clicking_skip_entrance_exam_button_with_success(self):
"""
@@ -234,7 +231,7 @@ class EntranceExamGradeTest(BaseInstructorDashboardTest):
email address or username
Then I should be shown an alert with success message
"""
- self.student_admin_section.set_student_email_for_ee(self.student_identifier)
+ self.student_admin_section.set_student_email(self.student_identifier)
self.student_admin_section.click_skip_entrance_exam_button()
#first we have window.confirm
alert = get_modal_alert(self.student_admin_section.browser)
@@ -254,14 +251,14 @@ class EntranceExamGradeTest(BaseInstructorDashboardTest):
student email address or username
Then I should be shown an error message
"""
- self.student_admin_section.set_student_email_for_ee('non_existing@example.com')
+ self.student_admin_section.set_student_email('non_existing@example.com')
self.student_admin_section.click_skip_entrance_exam_button()
#first we have window.confirm
alert = get_modal_alert(self.student_admin_section.browser)
alert.accept()
self.student_admin_section.wait_for_ajax()
- self.assertGreater(len(self.student_admin_section.entrance_exam_top_notification.text[0]), 0)
+ self.assertGreater(len(self.student_admin_section.top_notification.text[0]), 0)
def test_clicking_delete_student_attempts_button_with_success(self):
"""
@@ -273,8 +270,8 @@ class EntranceExamGradeTest(BaseInstructorDashboardTest):
email address or username
Then I should be shown an alert with success message
"""
- self.student_admin_section.set_student_email_for_ee(self.student_identifier)
- self.student_admin_section.entrance_exam_click_delete_student_state_button()
+ self.student_admin_section.set_student_email(self.student_identifier)
+ self.student_admin_section.click_delete_student_state_button()
alert = get_modal_alert(self.student_admin_section.browser)
alert.dismiss()
@@ -289,10 +286,10 @@ class EntranceExamGradeTest(BaseInstructorDashboardTest):
email address or username
Then I should be shown an error message
"""
- self.student_admin_section.set_student_email_for_ee('non_existing@example.com')
- self.student_admin_section.entrance_exam_click_delete_student_state_button()
+ self.student_admin_section.set_student_email('non_existing@example.com')
+ self.student_admin_section.click_delete_student_state_button()
self.student_admin_section.wait_for_ajax()
- self.assertGreater(len(self.student_admin_section.entrance_exam_top_notification.text[0]), 0)
+ self.assertGreater(len(self.student_admin_section.top_notification.text[0]), 0)
def test_clicking_task_history_button_with_success(self):
"""
@@ -304,8 +301,8 @@ class EntranceExamGradeTest(BaseInstructorDashboardTest):
email address or username
Then I should be shown an table listing all background tasks
"""
- self.student_admin_section.set_student_email_for_ee(self.student_identifier)
- self.student_admin_section.entrance_exam_click_task_history_button()
+ self.student_admin_section.set_student_email(self.student_identifier)
+ self.student_admin_section.click_task_history_button()
self.assertTrue(self.student_admin_section.is_background_task_history_table_visible())
diff --git a/common/test/acceptance/tests/lms/test_lms_user_preview.py b/common/test/acceptance/tests/lms/test_lms_user_preview.py
index 0ff88471d2..292bbf8dcf 100644
--- a/common/test/acceptance/tests/lms/test_lms_user_preview.py
+++ b/common/test/acceptance/tests/lms/test_lms_user_preview.py
@@ -3,12 +3,10 @@
Tests the "preview" selector in the LMS that allows changing between Staff, Student, and Content Groups.
"""
-from ..helpers import UniqueCourseTest, create_user_partition_json, get_modal_alert
+from ..helpers import UniqueCourseTest, create_user_partition_json
from ...pages.studio.auto_auth import AutoAuthPage
from ...pages.lms.courseware import CoursewarePage
-from ...pages.lms.instructor_dashboard import InstructorDashboardPage, StudentAdminPage
from ...pages.lms.staff_view import StaffPage
-from ...pages.common.sudo_page import SudoPage
from ...fixtures.course import CourseFixture, XBlockFixtureDesc
from xmodule.partitions.partitions import Group
from textwrap import dedent
@@ -38,9 +36,8 @@ class StaffViewTest(UniqueCourseTest):
# Auto-auth register for the course.
# Do this as global staff so that you will see the Staff View
- self.staff_password = 'test'
AutoAuthPage(self.browser, username=self.USERNAME, email=self.EMAIL,
- course_id=self.course_id, staff=True, password=self.staff_password).visit()
+ course_id=self.course_id, staff=True).visit()
def _goto_staff_page(self):
"""
@@ -102,41 +99,26 @@ class StaffDebugTest(CourseWithoutContentGroupsTest):
"""
Tests that verify the staff debug info.
"""
-
- def _goto_student_admin_section(self):
- """
- Get sudo access and return student admin section.
- """
- instructor_page = InstructorDashboardPage(self.browser, self.course_id)
- sudo_page = SudoPage(self.browser, instructor_page)
- sudo_page.wait_for_page()
- sudo_page.submit_sudo_password_and_get_access(self.staff_password)
-
- student_admin_section = StudentAdminPage(self.browser)
- student_admin_section.wait_for_page()
- return student_admin_section
-
def test_reset_attempts_empty(self):
"""
Test that we reset even when there is no student state
"""
staff_debug_page = self._goto_staff_page().open_staff_debug_info()
- staff_debug_page.click_student_grade_adjustments()
- student_admin_section = self._goto_student_admin_section()
- student_admin_section.click_reset_attempts_button()
- alert = get_modal_alert(student_admin_section.browser)
- alert.dismiss()
+ staff_debug_page.reset_attempts()
+ msg = staff_debug_page.idash_msg[0]
+ self.assertEqual(u'Successfully reset the attempts '
+ 'for user {}'.format(self.USERNAME), msg)
def test_delete_state_empty(self):
"""
Test that we delete properly even when there isn't state to delete.
"""
staff_debug_page = self._goto_staff_page().open_staff_debug_info()
- staff_debug_page.click_student_grade_adjustments()
- student_admin_section = self._goto_student_admin_section()
- student_admin_section.click_delete_student_state_button()
- self.assertEqual(len(student_admin_section.top_notification.text[0]), 0)
+ staff_debug_page.delete_state()
+ msg = staff_debug_page.idash_msg[0]
+ self.assertEqual(u'Successfully deleted student state '
+ 'for user {}'.format(self.USERNAME), msg)
def test_reset_attempts_state(self):
"""
@@ -146,11 +128,10 @@ class StaffDebugTest(CourseWithoutContentGroupsTest):
staff_page.answer_problem()
staff_debug_page = staff_page.open_staff_debug_info()
- staff_debug_page.click_student_grade_adjustments()
- student_admin_section = self._goto_student_admin_section()
- student_admin_section.click_reset_attempts_button()
- alert = get_modal_alert(student_admin_section.browser)
- alert.dismiss()
+ staff_debug_page.reset_attempts()
+ msg = staff_debug_page.idash_msg[0]
+ self.assertEqual(u'Successfully reset the attempts '
+ 'for user {}'.format(self.USERNAME), msg)
def test_rescore_state(self):
"""
@@ -160,11 +141,9 @@ class StaffDebugTest(CourseWithoutContentGroupsTest):
staff_page.answer_problem()
staff_debug_page = staff_page.open_staff_debug_info()
- staff_debug_page.click_student_grade_adjustments()
- student_admin_section = self._goto_student_admin_section()
- student_admin_section.click_rescore_submissions_button()
- alert = get_modal_alert(student_admin_section.browser)
- alert.dismiss()
+ staff_debug_page.rescore()
+ msg = staff_debug_page.idash_msg[0]
+ self.assertEqual(u'Successfully rescored problem for user STAFF_TESTER', msg)
def test_student_state_delete(self):
"""
@@ -174,10 +153,10 @@ class StaffDebugTest(CourseWithoutContentGroupsTest):
staff_page.answer_problem()
staff_debug_page = staff_page.open_staff_debug_info()
- staff_debug_page.click_student_grade_adjustments()
- student_admin_section = self._goto_student_admin_section()
- student_admin_section.click_delete_student_state_button()
- self.assertEqual(len(student_admin_section.top_notification.text[0]), 0)
+ staff_debug_page.delete_state()
+ msg = staff_debug_page.idash_msg[0]
+ self.assertEqual(u'Successfully deleted student state '
+ 'for user {}'.format(self.USERNAME), msg)
def test_student_by_email(self):
"""
@@ -187,11 +166,10 @@ class StaffDebugTest(CourseWithoutContentGroupsTest):
staff_page.answer_problem()
staff_debug_page = staff_page.open_staff_debug_info()
- staff_debug_page.click_student_grade_adjustments(self.EMAIL)
- student_admin_section = self._goto_student_admin_section()
- student_admin_section.click_reset_attempts_button()
- alert = get_modal_alert(student_admin_section.browser)
- alert.dismiss()
+ staff_debug_page.reset_attempts(self.EMAIL)
+ msg = staff_debug_page.idash_msg[0]
+ self.assertEqual(u'Successfully reset the attempts '
+ 'for user {}'.format(self.EMAIL), msg)
def test_bad_student(self):
"""
@@ -201,10 +179,10 @@ class StaffDebugTest(CourseWithoutContentGroupsTest):
staff_page.answer_problem()
staff_debug_page = staff_page.open_staff_debug_info()
- staff_debug_page.click_student_grade_adjustments('INVALIDUSER')
- student_admin_section = self._goto_student_admin_section()
- student_admin_section.click_delete_student_state_button()
- self.assertGreater(len(student_admin_section.top_notification.text[0]), 0)
+ staff_debug_page.delete_state('INVALIDUSER')
+ msg = staff_debug_page.idash_msg[0]
+ self.assertEqual(u'Failed to delete student state. '
+ 'User does not exist.', msg)
def test_reset_attempts_for_problem_loaded_via_ajax(self):
"""
@@ -215,11 +193,10 @@ class StaffDebugTest(CourseWithoutContentGroupsTest):
staff_page.answer_problem()
staff_debug_page = staff_page.open_staff_debug_info()
- staff_debug_page.click_student_grade_adjustments()
- student_admin_section = self._goto_student_admin_section()
- student_admin_section.click_reset_attempts_button()
- alert = get_modal_alert(student_admin_section.browser)
- alert.dismiss()
+ staff_debug_page.reset_attempts()
+ msg = staff_debug_page.idash_msg[0]
+ self.assertEqual(u'Successfully reset the attempts '
+ 'for user {}'.format(self.USERNAME), msg)
def test_rescore_state_for_problem_loaded_via_ajax(self):
"""
@@ -230,11 +207,9 @@ class StaffDebugTest(CourseWithoutContentGroupsTest):
staff_page.answer_problem()
staff_debug_page = staff_page.open_staff_debug_info()
- staff_debug_page.click_student_grade_adjustments()
- student_admin_section = self._goto_student_admin_section()
- student_admin_section.click_rescore_submissions_button()
- alert = get_modal_alert(student_admin_section.browser)
- alert.dismiss()
+ staff_debug_page.rescore()
+ msg = staff_debug_page.idash_msg[0]
+ self.assertEqual(u'Successfully rescored problem for user STAFF_TESTER', msg)
def test_student_state_delete_for_problem_loaded_via_ajax(self):
"""
@@ -245,10 +220,10 @@ class StaffDebugTest(CourseWithoutContentGroupsTest):
staff_page.answer_problem()
staff_debug_page = staff_page.open_staff_debug_info()
- staff_debug_page.click_student_grade_adjustments()
- student_admin_section = self._goto_student_admin_section()
- student_admin_section.click_delete_student_state_button()
- self.assertEqual(len(student_admin_section.top_notification.text[0]), 0)
+ staff_debug_page.delete_state()
+ msg = staff_debug_page.idash_msg[0]
+ self.assertEqual(u'Successfully deleted student state '
+ 'for user {}'.format(self.USERNAME), msg)
class CourseWithContentGroupsTest(StaffViewTest):
diff --git a/common/test/acceptance/tests/studio/test_studio_course_team.py b/common/test/acceptance/tests/studio/test_studio_course_team.py
index b289b5bc05..80dda78a09 100644
--- a/common/test/acceptance/tests/studio/test_studio_course_team.py
+++ b/common/test/acceptance/tests/studio/test_studio_course_team.py
@@ -5,7 +5,6 @@ from flaky import flaky
from nose.plugins.attrib import attr
from .base_studio_test import StudioCourseTest
-from ..helpers import get_sudo_access
from ...pages.studio.auto_auth import AutoAuthPage
from ...pages.studio.users import CourseTeamPage
@@ -39,7 +38,6 @@ class CourseTeamPageTest(StudioCourseTest):
self.page = CourseTeamPage( # pylint:disable=attribute-defined-outside-init
self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']
)
- get_sudo_access(self.browser, self.page, self.user.get('password'))
self._go_to_course_team_page()
def _go_to_course_team_page(self):
@@ -127,7 +125,6 @@ class CourseTeamPageTest(StudioCourseTest):
self.page.add_user_to_course(self.other_user.get('email'))
self._assert_user_present(self.other_user, present=True)
self.log_in(self.other_user)
- get_sudo_access(self.browser, self.page, self.other_user.get('password'))
self._assert_current_course(visible=True)
@flaky # TODO fix this, see TNL-2667
@@ -146,7 +143,6 @@ class CourseTeamPageTest(StudioCourseTest):
self._assert_user_present(self.other_user, present=True)
self.log_in(self.other_user)
- get_sudo_access(self.browser, self.page, self.other_user.get('password'))
self._assert_current_course(visible=True)
self._go_to_course_team_page()
@@ -208,7 +204,6 @@ class CourseTeamPageTest(StudioCourseTest):
self._assert_is_admin(other)
self.log_in(self.other_user)
- get_sudo_access(self.browser, self.page, self.other_user.get('password'))
self._go_to_course_team_page()
other = self.page.get_user(self.other_user.get('email'))
self.assertTrue(other.is_current_user)
@@ -240,14 +235,12 @@ class CourseTeamPageTest(StudioCourseTest):
# precondition check - frank is an admin and can add/delete/promote/demote users
self.log_in(self.other_user)
- get_sudo_access(self.browser, self.page, self.other_user.get('password'))
self._go_to_course_team_page()
other = self.page.get_user(self.other_user.get('email'))
self.assertTrue(other.is_current_user)
self._assert_can_manage_users()
self.log_in(self.user)
- get_sudo_access(self.browser, self.page, self.user.get('password'))
self._go_to_course_team_page()
other = self.page.get_user(self.other_user.get('email'))
other.click_demote()
@@ -256,7 +249,6 @@ class CourseTeamPageTest(StudioCourseTest):
self._assert_is_staff(other)
self.log_in(self.other_user)
- get_sudo_access(self.browser, self.page, self.other_user.get('password'))
self._go_to_course_team_page()
other = self.page.get_user(self.other_user.get('email'))
self.assertTrue(other.is_current_user)
@@ -342,7 +334,6 @@ class CourseTeamPageTest(StudioCourseTest):
self.assertFalse(current.can_promote)
self.log_in(self.other_user)
- get_sudo_access(self.browser, self.page, self.other_user.get('password'))
self._go_to_course_team_page()
current = self.page.get_user(self.user.get('email'))
diff --git a/common/test/acceptance/tests/studio/test_studio_library.py b/common/test/acceptance/tests/studio/test_studio_library.py
index d25e196c29..0086024f69 100644
--- a/common/test/acceptance/tests/studio/test_studio_library.py
+++ b/common/test/acceptance/tests/studio/test_studio_library.py
@@ -7,7 +7,6 @@ from flaky import flaky
from .base_studio_test import StudioLibraryTest
from ...fixtures.course import XBlockFixtureDesc
-from ..helpers import get_sudo_access
from ...pages.studio.auto_auth import AutoAuthPage
from ...pages.studio.utils import add_component
from ...pages.studio.library import LibraryEditPage
@@ -515,7 +514,6 @@ class LibraryUsersPageTest(StudioLibraryTest):
AutoAuthPage(self.browser, username="second", email="second@example.com", no_login=True).visit()
self.page = LibraryUsersPage(self.browser, self.library_key)
- get_sudo_access(self.browser, self.page, self.user.get("password"))
self.page.visit()
def _refresh_page(self):
diff --git a/common/test/acceptance/tests/test_cohorted_courseware.py b/common/test/acceptance/tests/test_cohorted_courseware.py
index 7dec1d1412..a893252f89 100644
--- a/common/test/acceptance/tests/test_cohorted_courseware.py
+++ b/common/test/acceptance/tests/test_cohorted_courseware.py
@@ -11,7 +11,6 @@ from ..pages.studio.settings_group_configurations import GroupConfigurationsPage
from ..pages.studio.auto_auth import AutoAuthPage as StudioAutoAuthPage
from ..fixtures.course import XBlockFixtureDesc
from ..fixtures import LMS_BASE_URL
-from .helpers import get_sudo_access
from ..pages.studio.component_editor import ComponentVisibilityEditorView
from ..pages.lms.instructor_dashboard import InstructorDashboardPage
from ..pages.lms.courseware import CoursewarePage
@@ -55,12 +54,8 @@ class EndToEndCohortedCoursewareTest(ContainerBase):
).visit()
# Start logged in as the staff user.
- self.instructor_password = 'test'
StudioAutoAuthPage(
- self.browser,
- username=self.staff_user["username"],
- email=self.staff_user["email"],
- password=self.instructor_password
+ self.browser, username=self.staff_user["username"], email=self.staff_user["email"]
).visit()
def populate_course_fixture(self, course_fixture):
@@ -143,7 +138,6 @@ class EndToEndCohortedCoursewareTest(ContainerBase):
Each cohort is assigned one student.
"""
instructor_dashboard_page = InstructorDashboardPage(self.browser, self.course_id)
- get_sudo_access(self.browser, instructor_dashboard_page, self.instructor_password)
instructor_dashboard_page.visit()
cohort_management_page = instructor_dashboard_page.select_cohort_management()
diff --git a/lms/djangoapps/bulk_email/tests/test_course_optout.py b/lms/djangoapps/bulk_email/tests/test_course_optout.py
index 09b87ed5ff..e72edd222d 100644
--- a/lms/djangoapps/bulk_email/tests/test_course_optout.py
+++ b/lms/djangoapps/bulk_email/tests/test_course_optout.py
@@ -27,7 +27,7 @@ class TestOptoutCourseEmails(ModuleStoreTestCase):
def setUp(self):
super(TestOptoutCourseEmails, self).setUp()
course_title = u"ẗëṡẗ title イ乇丂イ ᄊ乇丂丂ムg乇 キo尺 ムレレ тэѕт мэѕѕаБэ"
- self.course = CourseFactory.create(display_name=course_title, run='T12015')
+ self.course = CourseFactory.create(display_name=course_title)
self.instructor = AdminFactory.create()
self.student = UserFactory.create()
CourseEnrollmentFactory.create(user=self.student, course_id=self.course.id)
@@ -47,7 +47,6 @@ class TestOptoutCourseEmails(ModuleStoreTestCase):
"""Navigate to the instructor dash's email view"""
# Pull up email view on instructor dashboard
url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id.to_deprecated_string()})
- self.grant_sudo_access(unicode(self.course.id), 'test')
response = self.client.get(url)
email_section = ''
# If this fails, it is likely because ENABLE_INSTRUCTOR_EMAIL is set to False
diff --git a/lms/djangoapps/bulk_email/tests/test_email.py b/lms/djangoapps/bulk_email/tests/test_email.py
index 7bb2b827d9..9a85bd2ba5 100644
--- a/lms/djangoapps/bulk_email/tests/test_email.py
+++ b/lms/djangoapps/bulk_email/tests/test_email.py
@@ -53,7 +53,7 @@ class EmailSendFromDashboardTestCase(ModuleStoreTestCase):
def setUp(self):
super(EmailSendFromDashboardTestCase, self).setUp()
course_title = u"ẗëṡẗ title イ乇丂イ ᄊ乇丂丂ムg乇 キo尺 ムレレ тэѕт мэѕѕаБэ"
- self.course = CourseFactory.create(display_name=course_title, run="1T2015")
+ self.course = CourseFactory.create(display_name=course_title)
self.instructor = InstructorFactory(course_key=self.course.id)
@@ -75,7 +75,6 @@ class EmailSendFromDashboardTestCase(ModuleStoreTestCase):
self.url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id.to_deprecated_string()})
# Response loads the whole instructor dashboard, so no need to explicitly
# navigate to a particular email section
- self.grant_sudo_access(unicode(self.course.id), 'test')
response = self.client.get(self.url)
email_section = '
'
# If this fails, it is likely because ENABLE_INSTRUCTOR_EMAIL is set to False
diff --git a/lms/djangoapps/bulk_email/tests/test_err_handling.py b/lms/djangoapps/bulk_email/tests/test_err_handling.py
index a2457051df..9b8db791d9 100644
--- a/lms/djangoapps/bulk_email/tests/test_err_handling.py
+++ b/lms/djangoapps/bulk_email/tests/test_err_handling.py
@@ -47,10 +47,9 @@ class TestEmailErrors(ModuleStoreTestCase):
def setUp(self):
super(TestEmailErrors, self).setUp()
course_title = u"ẗëṡẗ title イ乇丂イ ᄊ乇丂丂ムg乇 キo尺 ムレレ тэѕт мэѕѕаБэ"
- self.course = CourseFactory.create(display_name=course_title, run="1T2015")
+ self.course = CourseFactory.create(display_name=course_title)
self.instructor = AdminFactory.create()
self.client.login(username=self.instructor.username, password="test")
- self.grant_sudo_access(unicode(self.course.id), 'test')
# load initial content (since we don't run migrations as part of tests):
call_command("loaddata", "course_email_template.json")
diff --git a/lms/djangoapps/courseware/admin.py b/lms/djangoapps/courseware/admin.py
index 16843ba22d..78c9fc826f 100644
--- a/lms/djangoapps/courseware/admin.py
+++ b/lms/djangoapps/courseware/admin.py
@@ -3,7 +3,7 @@ django admin pages for courseware model
'''
from courseware.models import StudentModule, OfflineComputedGrade, OfflineComputedGradeLog
-from django.contrib import admin
+from ratelimitbackend import admin
admin.site.register(StudentModule)
diff --git a/lms/djangoapps/courseware/features/lti.feature b/lms/djangoapps/courseware/features/lti.feature
index c3d6c2f643..3ac9564f7a 100644
--- a/lms/djangoapps/courseware/features/lti.feature
+++ b/lms/djangoapps/courseware/features/lti.feature
@@ -51,7 +51,6 @@ Feature: LMS.LTI component
Then I see text "Problem Scores: 5/10"
And I see graph with total progress "5%"
Then I click on the "Instructor" tab
- Then I get sudo access with password "test"
And I click on the "Student Admin" tab
And I click on the "View Gradebook" link
And I see in the gradebook table that "HW" is "50"
@@ -91,7 +90,6 @@ Feature: LMS.LTI component
Then I see text "Problem Scores: 8/10"
And I see graph with total progress "8%"
Then I click on the "Instructor" tab
- Then I get sudo access with password "test"
And I click on the "Student Admin" tab
And I click on the "View Gradebook" link
And I see in the gradebook table that "HW" is "80"
@@ -118,7 +116,6 @@ Feature: LMS.LTI component
Then I see text "Problem Scores: 0/10"
And I see graph with total progress "0%"
Then I click on the "Instructor" tab
- Then I get sudo access with password "test"
And I click on the "Student Admin" tab
And I click on the "View Gradebook" link
And I see in the gradebook table that "HW" is "0"
diff --git a/lms/djangoapps/courseware/features/staff_debug_info.feature b/lms/djangoapps/courseware/features/staff_debug_info.feature
new file mode 100644
index 0000000000..519e4b3c13
--- /dev/null
+++ b/lms/djangoapps/courseware/features/staff_debug_info.feature
@@ -0,0 +1,13 @@
+@shard_1
+Feature: LMS.Debug staff info links
+ As a course staff in an edX course
+ In order to test my understanding of the material
+ I want to click on staff debug info links
+
+ Scenario: I can reset student attempts
+ When i am staff member for the course "model_course"
+ And I am viewing a "multiple choice" problem
+ And I can view staff debug info
+ Then I can reset student attempts
+ Then I cannot see delete student state link
+ Then I cannot see rescore student submission link
diff --git a/lms/djangoapps/courseware/features/staff_debug_info.py b/lms/djangoapps/courseware/features/staff_debug_info.py
new file mode 100644
index 0000000000..9d183a5be9
--- /dev/null
+++ b/lms/djangoapps/courseware/features/staff_debug_info.py
@@ -0,0 +1,51 @@
+"""
+Steps for staff_debug_info.feature lettuce tests
+"""
+
+from django.contrib.auth.models import User
+from lettuce import world, step
+from common import create_course, course_id
+from courseware.courses import get_course_by_id
+from instructor.access import allow_access
+
+
+@step(u'i am staff member for the course "([^"]*)"$')
+def i_am_staff_member_for_the_course(step, course_number):
+ # Create the course
+ create_course(step, course_number)
+ course = get_course_by_id(course_id(course_number))
+
+ # Create the user
+ world.create_user('robot', 'test')
+ user = User.objects.get(username='robot')
+
+ # Add user as a course staff.
+ allow_access(course, user, "staff")
+
+ world.log_in(username='robot', password='test')
+
+
+@step(u'I can view staff debug info')
+def view_staff_debug_info(step):
+ css_selector = "a.instructor-info-action"
+ world.css_click(css_selector)
+ world.wait_for_visible("section.staff-modal")
+
+
+@step(u'I can reset student attempts')
+def view_staff_debug_info(step):
+ css_selector = "a.staff-debug-reset"
+ world.css_click(css_selector)
+ world.wait_for_ajax_complete()
+
+
+@step(u'I cannot see delete student state link')
+def view_staff_debug_info(step):
+ css_selector = "a.staff-debug-sdelete"
+ world.is_css_not_present(css_selector)
+
+
+@step(u'I cannot see rescore student submission link')
+def view_staff_debug_info(step):
+ css_selector = "a.staff-debug-rescore"
+ world.is_css_not_present(css_selector)
diff --git a/lms/djangoapps/courseware/tests/test_entrance_exam.py b/lms/djangoapps/courseware/tests/test_entrance_exam.py
index 504e366ea9..46dbe5413d 100644
--- a/lms/djangoapps/courseware/tests/test_entrance_exam.py
+++ b/lms/djangoapps/courseware/tests/test_entrance_exam.py
@@ -386,7 +386,6 @@ class EntranceExamTestCases(LoginEnrollmentTestCase, ModuleStoreTestCase):
# hit skip entrance exam api in instructor app
instructor = InstructorFactory(course_key=self.course.id)
self.client.login(username=instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
url = reverse('mark_student_can_skip_entrance_exam', kwargs={'course_id': unicode(self.course.id)})
response = self.client.post(url, {
'unique_student_identifier': self.request.user.email,
diff --git a/lms/djangoapps/courseware/tests/test_tabs.py b/lms/djangoapps/courseware/tests/test_tabs.py
index 828b03d8ed..b50d4d793a 100644
--- a/lms/djangoapps/courseware/tests/test_tabs.py
+++ b/lms/djangoapps/courseware/tests/test_tabs.py
@@ -383,7 +383,6 @@ class EntranceExamsTabsTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase):
instructor = InstructorFactory(course_key=self.course.id)
self.client.logout()
self.client.login(username=instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
url = reverse('mark_student_can_skip_entrance_exam', kwargs={'course_id': unicode(self.course.id)})
response = self.client.post(url, {
diff --git a/lms/djangoapps/courseware/tests/test_view_authentication.py b/lms/djangoapps/courseware/tests/test_view_authentication.py
index a1609b62b8..52cf037a9e 100644
--- a/lms/djangoapps/courseware/tests/test_view_authentication.py
+++ b/lms/djangoapps/courseware/tests/test_view_authentication.py
@@ -67,7 +67,6 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
'book_index': index})
for index, __ in enumerate(course.textbooks)
])
- self.grant_sudo_access(unicode(course.id), 'test')
for url in urls:
self.assert_request_status_code(404, url)
@@ -82,7 +81,6 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
'book_index': index})
for index in xrange(len(course.textbooks))
])
- self.grant_sudo_access(unicode(course.id), 'test')
for url in urls:
self.assert_request_status_code(200, url)
@@ -209,8 +207,6 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
urls = [reverse('instructor_dashboard', kwargs={'course_id': self.course.id.to_deprecated_string()}),
reverse('instructor_dashboard', kwargs={'course_id': self.test_course.id.to_deprecated_string()})]
- self.grant_sudo_access(unicode(self.course.id), 'test')
- self.grant_sudo_access(unicode(self.test_course.id), 'test')
# Shouldn't be able to get to the instructor pages
for url in urls:
self.assert_request_status_code(404, url)
@@ -222,8 +218,6 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
"""
self.login(self.staff_user)
- self.grant_sudo_access(unicode(self.course.id), 'test')
- self.grant_sudo_access(unicode(self.test_course.id), 'test')
# Now should be able to get to self.course, but not self.test_course
url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id.to_deprecated_string()})
self.assert_request_status_code(200, url)
@@ -238,8 +232,6 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
"""
self.login(self.instructor_user)
- self.grant_sudo_access(unicode(self.course.id), 'test')
- self.grant_sudo_access(unicode(self.test_course.id), 'test')
# Now should be able to get to self.course, but not self.test_course
url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id.to_deprecated_string()})
self.assert_request_status_code(200, url)
@@ -253,9 +245,6 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
and student profile pages for course in their org.
"""
self.login(self.org_staff_user)
- self.grant_sudo_access(unicode(self.course.id), 'test')
- self.grant_sudo_access(unicode(self.test_course.id), 'test')
- self.grant_sudo_access(unicode(self.other_org_course.id), 'test')
url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id.to_deprecated_string()})
self.assert_request_status_code(200, url)
@@ -271,9 +260,6 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
and student profile pages for course in their org.
"""
self.login(self.org_instructor_user)
- self.grant_sudo_access(unicode(self.course.id), 'test')
- self.grant_sudo_access(unicode(self.test_course.id), 'test')
- self.grant_sudo_access(unicode(self.other_org_course.id), 'test')
url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id.to_deprecated_string()})
self.assert_request_status_code(200, url)
@@ -289,8 +275,6 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
"""
self.login(self.global_staff_user)
- self.grant_sudo_access(unicode(self.course.id), 'test')
- self.grant_sudo_access(unicode(self.test_course.id), 'test')
# and now should be able to load both
urls = [reverse('instructor_dashboard', kwargs={'course_id': self.course.id.to_deprecated_string()}),
reverse('instructor_dashboard', kwargs={'course_id': self.test_course.id.to_deprecated_string()})]
@@ -403,26 +387,6 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.login(self.global_staff_user)
self.assertTrue(self.enroll(self.course))
- def test_org_instructor_cannot_access_without_sudo(self):
- """
- Test that org instructor cannot load the instructor dashboard without sudo access
- and it redirect org instructor to sudo password page.
- """
- self.login(self.org_instructor_user)
- url = reverse('instructor_dashboard', kwargs={'course_id': unicode(self.course.id)})
- response = self.assert_request_status_code(401, url)
- self.assertIn('Unauthorized', response.content)
-
- def test_org_staff_cannot_access_without_sudo(self):
- """
- Test that org staff cannot load the instructor dashboard without sudo access
- and it redirect org staff to sudo password page.
- """
- self.login(self.org_staff_user)
- url = reverse('instructor_dashboard', kwargs={'course_id': unicode(self.course.id)})
- response = self.assert_request_status_code(401, url)
- self.assertIn('Unauthorized', response.content)
-
@attr('shard_1')
class TestBetatesterAccess(ModuleStoreTestCase, CourseAccessTestMixin):
diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py
index 9a75eb633b..8dbfcb42d0 100644
--- a/lms/djangoapps/courseware/tests/test_views.py
+++ b/lms/djangoapps/courseware/tests/test_views.py
@@ -32,7 +32,6 @@ from course_modes.models import CourseMode
from courseware.testutils import RenderXBlockTestMixin
from courseware.tests.factories import StudentModuleFactory
from edxmako.tests import mako_middleware_process_request
-from django_sudo_helpers.tests.utils import sudo_middleware_process_request
from student.models import CourseEnrollment
from student.tests.factories import AdminFactory, UserFactory, CourseEnrollmentFactory
from util.tests.test_date_utils import fake_ugettext, fake_pgettext
@@ -1153,7 +1152,6 @@ class TestIndexView(ModuleStoreTestCase):
)
request.user = user
mako_middleware_process_request(request)
- sudo_middleware_process_request(request)
# Trigger the assertions embedded in the ViewCheckerBlocks
response = views.index(request, unicode(course.id), chapter=chapter.url_name, section=section.url_name)
diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py
index 9a0b7b6a7f..403d47a2d9 100644
--- a/lms/djangoapps/courseware/views.py
+++ b/lms/djangoapps/courseware/views.py
@@ -25,7 +25,6 @@ from django.shortcuts import redirect
from certificates import api as certs_api
from edxmako.shortcuts import render_to_response, render_to_string, marketing_link
from django.views.decorators.csrf import ensure_csrf_cookie
-from sudo.utils import revoke_sudo_privileges
from django.views.decorators.cache import cache_control
from django.db import transaction
from markupsafe import escape
@@ -341,10 +340,6 @@ def index(request, course_id, chapter=None, section=None,
- HTTPresponse
"""
- # Revoke sudo privileges from a request explicitly
- if request.is_sudo(region=course_id):
- revoke_sudo_privileges(request, region=course_id)
-
course_key = CourseKey.from_string(course_id)
user = User.objects.prefetch_related("groups").get(id=request.user.id)
diff --git a/lms/djangoapps/instructor/features/bulk_email.feature b/lms/djangoapps/instructor/features/bulk_email.feature
index b1766bf9ca..39d2c00c83 100644
--- a/lms/djangoapps/instructor/features/bulk_email.feature
+++ b/lms/djangoapps/instructor/features/bulk_email.feature
@@ -7,8 +7,6 @@ Feature: LMS.Instructor Dash Bulk Email
Scenario: Send bulk email
Given there is a course with a staff, instructor and student
And I am logged in to the course as "
"
- Then I go to instructor tab
- Then I get sudo access with password "test"
When I send email to ""
Then Email is sent to ""
diff --git a/lms/djangoapps/instructor/features/bulk_email.py b/lms/djangoapps/instructor/features/bulk_email.py
index 81c11ea35e..90eed1ebd9 100644
--- a/lms/djangoapps/instructor/features/bulk_email.py
+++ b/lms/djangoapps/instructor/features/bulk_email.py
@@ -96,13 +96,6 @@ def log_into_the_course(step, role): # pylint: disable=unused-argument
world.expected_addresses['myself'] = [my_email]
-@step("I go to instructor tab")
-def i_got_to_instructor_tab(step): # pylint: disable=unused-argument
- url = '/courses/{}'.format(world.bulk_email_course_key)
- world.visit(url)
- world.css_click('a[href="{}/instructor"]'.format(url))
-
-
@step(u'I send email to "([^"]*)"')
def when_i_send_an_email(step, recipient): # pylint: disable=unused-argument
@@ -122,6 +115,9 @@ def when_i_send_an_email(step, recipient): # pylint: disable=unused-argument
call_command('loaddata', 'course_email_template.json')
# Go to the email section of the instructor dash
+ url = '/courses/{}'.format(world.bulk_email_course_key)
+ world.visit(url)
+ world.css_click('a[href="{}/instructor"]'.format(url))
world.css_click('a[data-section="send_email"]')
# Select the recipient
diff --git a/lms/djangoapps/instructor/features/common.py b/lms/djangoapps/instructor/features/common.py
index d71a2edf9c..27e15d7aca 100644
--- a/lms/djangoapps/instructor/features/common.py
+++ b/lms/djangoapps/instructor/features/common.py
@@ -12,7 +12,6 @@ from mock import patch
from nose.tools import assert_in # pylint: disable=no-name-in-module
from courseware.tests.factories import StaffFactory, InstructorFactory
-from terrain.steps import i_get_sudo_access
@step(u'Given I am "([^"]*)" for a very large course')
@@ -72,17 +71,11 @@ def i_am_staff_or_instructor(step, role): # pylint: disable=unused-argument
)
-def go_to_instructor_tab(step):
+def go_to_section(section_name):
# section name should be one of
# course_info, membership, student_admin, data_download, analytics, send_email
world.visit(u'/courses/{}'.format(world.course_key))
world.css_click(u'a[href="/courses/{}/instructor"]'.format(world.course_key))
- i_get_sudo_access(step, 'test')
-
-
-def go_to_section(section_name):
- # section name should be one of
- # course_info, membership, student_admin, data_download, analytics, send_email
world.css_click('a[data-section="{0}"]'.format(section_name))
@@ -91,7 +84,6 @@ def click_a_button(step, button): # pylint: disable=unused-argument
if button == "Generate Grade Report":
# Go to the data download section of the instructor dash
- go_to_instructor_tab(step)
go_to_section("data_download")
# Click generate grade report button
@@ -109,21 +101,18 @@ def click_a_button(step, button): # pylint: disable=unused-argument
elif button == "Grading Configuration":
# Go to the data download section of the instructor dash
- go_to_instructor_tab(step)
go_to_section("data_download")
world.css_click('input[name="dump-gradeconf"]')
elif button == "List enrolled students' profile information":
# Go to the data download section of the instructor dash
- go_to_instructor_tab(step)
go_to_section("data_download")
world.css_click('input[name="list-profiles"]')
elif button == "Download profile information as a CSV":
# Go to the data download section of the instructor dash
- go_to_instructor_tab(step)
go_to_section("data_download")
world.css_click('input[name="list-profiles-csv"]')
@@ -143,5 +132,4 @@ def click_a_button(step, tab_name): # pylint: disable=unused-argument
'Analytics': 'analytics',
'Email': 'send_email',
}
- go_to_instructor_tab(step)
go_to_section(tab_name_dict[tab_name])
diff --git a/lms/djangoapps/instructor/tests/test_api.py b/lms/djangoapps/instructor/tests/test_api.py
index 523f965037..e5d7ec3aec 100644
--- a/lms/djangoapps/instructor/tests/test_api.py
+++ b/lms/djangoapps/instructor/tests/test_api.py
@@ -283,7 +283,6 @@ class TestInstructorAPIDenyLevels(ModuleStoreTestCase, LoginEnrollmentTestCase):
CourseEnrollment.enroll(staff_member, self.course.id)
CourseFinanceAdminRole(self.course.id).add_users(staff_member)
self.client.login(username=staff_member.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
# Try to promote to forums admin - not working
# update_forum_role(self.course.id, staff_member, FORUM_ROLE_ADMINISTRATOR, 'allow')
@@ -306,23 +305,6 @@ class TestInstructorAPIDenyLevels(ModuleStoreTestCase, LoginEnrollmentTestCase):
"Staff member should not be allowed to access endpoint " + endpoint
)
- def test_staff_level_without_sudo_access(self):
- """
- Ensure that a staff member redirected to sudo password page without sudo access.
- """
- staff_member = StaffFactory(course_key=self.course.id)
- CourseEnrollment.enroll(staff_member, self.course.id)
- CourseFinanceAdminRole(self.course.id).add_users(staff_member)
- self.client.login(username=staff_member.username, password='test')
-
- for endpoint, args in self.staff_level_endpoints:
- self._access_endpoint(
- endpoint,
- args,
- 401,
- ""
- )
-
def test_instructor_level(self):
"""
Ensure that an instructor member can access all endpoints.
@@ -332,7 +314,6 @@ class TestInstructorAPIDenyLevels(ModuleStoreTestCase, LoginEnrollmentTestCase):
CourseFinanceAdminRole(self.course.id).add_users(inst)
self.client.login(username=inst.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
for endpoint, args in self.staff_level_endpoints:
# TODO: make these work
@@ -356,31 +337,6 @@ class TestInstructorAPIDenyLevels(ModuleStoreTestCase, LoginEnrollmentTestCase):
"Instructor should be allowed to access endpoint " + endpoint
)
- def test_instructor_level_without_sudo_access(self):
- """
- Ensure that an instructor member redirected to sudo password page without sudo access.
- """
- inst = InstructorFactory(course_key=self.course.id)
- CourseEnrollment.enroll(inst, self.course.id)
- CourseFinanceAdminRole(self.course.id).add_users(inst)
- self.client.login(username=inst.username, password='test')
-
- for endpoint, args in self.staff_level_endpoints:
- self._access_endpoint(
- endpoint,
- args,
- 401,
- ""
- )
-
- for endpoint, args in self.instructor_level_endpoints:
- self._access_endpoint(
- endpoint,
- args,
- 401,
- ""
- )
-
@attr('shard_1')
@patch.dict(settings.FEATURES, {'ALLOW_AUTOMATED_SIGNUPS': True})
@@ -395,7 +351,6 @@ class TestInstructorAPIBulkAccountCreationAndEnrollment(ModuleStoreTestCase, Log
self.course = CourseFactory.create()
self.instructor = InstructorFactory(course_key=self.course.id)
self.client.login(username=self.instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
self.url = reverse('register_and_enroll_students', kwargs={'course_id': self.course.id.to_deprecated_string()})
self.not_enrolled_student = UserFactory(
@@ -700,7 +655,6 @@ class TestInstructorAPIEnrollment(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.course = CourseFactory.create()
self.instructor = InstructorFactory(course_key=self.course.id)
self.client.login(username=self.instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
self.enrolled_student = UserFactory(username='EnrolledStudent', first_name='Enrolled', last_name='Student')
CourseEnrollment.enroll(
@@ -1277,7 +1231,6 @@ class TestInstructorAPIEnrollment(ModuleStoreTestCase, LoginEnrollmentTestCase):
manually enrolling the students for the paid courses.
"""
paid_course = self.create_paid_course()
- self.grant_sudo_access(unicode(paid_course.id), 'test')
url = reverse('students_update_enrollment', kwargs={'course_id': paid_course.id.to_deprecated_string()})
params = {'identifiers': self.notregistered_email, 'action': 'enroll', 'email_students': False,
'auto_enroll': False}
@@ -1303,7 +1256,6 @@ class TestInstructorAPIEnrollment(ModuleStoreTestCase, LoginEnrollmentTestCase):
test to unenroll allow to enroll user.
"""
paid_course = self.create_paid_course()
- self.grant_sudo_access(unicode(paid_course.id), 'test')
url = reverse('students_update_enrollment', kwargs={'course_id': paid_course.id.to_deprecated_string()})
params = {'identifiers': self.notregistered_email, 'action': 'enroll', 'email_students': False,
'auto_enroll': False, 'reason': 'testing..'}
@@ -1354,7 +1306,6 @@ class TestInstructorAPIEnrollment(ModuleStoreTestCase, LoginEnrollmentTestCase):
test unenrolled user already not enrolled in a course.
"""
paid_course = self.create_paid_course()
- self.grant_sudo_access(unicode(paid_course.id), 'test')
course_enrollment = CourseEnrollment.objects.filter(
user__email=self.notregistered_email, course_id=paid_course.id
)
@@ -1452,7 +1403,6 @@ class TestInstructorAPIBulkBetaEnrollment(ModuleStoreTestCase, LoginEnrollmentTe
self.course = CourseFactory.create()
self.instructor = InstructorFactory(course_key=self.course.id)
self.client.login(username=self.instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
self.beta_tester = BetaTesterFactory(course_key=self.course.id)
CourseEnrollment.enroll(
@@ -1781,7 +1731,6 @@ class TestInstructorAPILevelsAccess(ModuleStoreTestCase, LoginEnrollmentTestCase
self.course = CourseFactory.create()
self.instructor = InstructorFactory(course_key=self.course.id)
self.client.login(username=self.instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
self.other_instructor = InstructorFactory(course_key=self.course.id)
self.other_staff = StaffFactory(course_key=self.course.id)
@@ -2020,7 +1969,6 @@ class TestInstructorAPILevelsDataDump(ModuleStoreTestCase, LoginEnrollmentTestCa
self.course_mode.save()
self.instructor = InstructorFactory(course_key=self.course.id)
self.client.login(username=self.instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
self.cart = Order.get_cart_for_user(self.instructor)
self.coupon_code = 'abcde'
self.coupon = Coupon(code=self.coupon_code, description='testing code', course_id=self.course.id,
@@ -2448,7 +2396,6 @@ class TestInstructorAPILevelsDataDump(ModuleStoreTestCase, LoginEnrollmentTestCa
UserProfileFactory.create(user=self.students[0], meta='{"company": "asdasda"}')
self.client.login(username=self.instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
url = reverse('get_enrollment_report', kwargs={'course_id': self.course.id.to_deprecated_string()})
response = self.client.get(url, {})
self.assertIn('Your detailed enrollment report is being generated!', response.content)
@@ -2498,7 +2445,6 @@ class TestInstructorAPILevelsDataDump(ModuleStoreTestCase, LoginEnrollmentTestCa
CourseFinanceAdminRole(self.course.id).add_users(self.instructor)
self.client.login(username=self.instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
url = reverse('get_enrollment_report', kwargs={'course_id': self.course.id.to_deprecated_string()})
response = self.client.get(url, {})
@@ -2521,7 +2467,6 @@ class TestInstructorAPILevelsDataDump(ModuleStoreTestCase, LoginEnrollmentTestCa
CourseFinanceAdminRole(self.course.id).add_users(self.instructor)
self.client.login(username=self.instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
url = reverse('get_enrollment_report', kwargs={'course_id': self.course.id.to_deprecated_string()})
response = self.client.get(url, {})
@@ -2547,7 +2492,6 @@ class TestInstructorAPILevelsDataDump(ModuleStoreTestCase, LoginEnrollmentTestCa
CourseFinanceAdminRole(self.course.id).add_users(self.instructor)
self.client.login(username=self.instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
url = reverse('get_enrollment_report', kwargs={'course_id': self.course.id.to_deprecated_string()})
response = self.client.get(url, {})
@@ -2705,7 +2649,6 @@ class TestInstructorAPIRegradeTask(ModuleStoreTestCase, LoginEnrollmentTestCase)
self.course = CourseFactory.create()
self.instructor = InstructorFactory(course_key=self.course.id)
self.client.login(username=self.instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
self.student = UserFactory()
CourseEnrollment.enroll(self.student, self.course.id)
@@ -2875,8 +2818,6 @@ class TestEntranceExamInstructorAPIRegradeTask(ModuleStoreTestCase, LoginEnrollm
# Add instructor to invalid ee course
CourseInstructorRole(self.course_with_invalid_ee.id).add_users(self.instructor)
self.client.login(username=self.instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course_with_invalid_ee.id), 'test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
self.student = UserFactory()
CourseEnrollment.enroll(self.student, self.course.id)
@@ -2986,7 +2927,6 @@ class TestEntranceExamInstructorAPIRegradeTask(ModuleStoreTestCase, LoginEnrollm
self.client.logout()
staff_user = StaffFactory(course_key=self.course.id)
self.client.login(username=staff_user.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
url = reverse('reset_student_attempts_for_entrance_exam',
kwargs={'course_id': unicode(self.course.id)})
response = self.client.get(url, {
@@ -3117,7 +3057,6 @@ class TestInstructorSendEmail(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.course = CourseFactory.create()
self.instructor = InstructorFactory(course_key=self.course.id)
self.client.login(username=self.instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
test_subject = u'\u1234 test subject'
test_message = u'\u6824 test message'
self.full_test_message = {
@@ -3243,7 +3182,6 @@ class TestInstructorAPITaskLists(ModuleStoreTestCase, LoginEnrollmentTestCase):
)
self.instructor = InstructorFactory(course_key=self.course.id)
self.client.login(username=self.instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
self.student = UserFactory()
CourseEnrollment.enroll(self.student, self.course.id)
@@ -3360,7 +3298,6 @@ class TestInstructorEmailContentList(ModuleStoreTestCase, LoginEnrollmentTestCas
self.course = CourseFactory.create()
self.instructor = InstructorFactory(course_key=self.course.id)
self.client.login(username=self.instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
self.tasks = {}
self.emails = {}
self.emails_info = {}
@@ -3615,7 +3552,6 @@ class TestDueDateExtensions(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.instructor = InstructorFactory(course_key=course.id)
self.client.login(username=self.instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
def test_change_due_date(self):
url = reverse('change_due_date', kwargs={'course_id': self.course.id.to_deprecated_string()})
@@ -3740,7 +3676,6 @@ class TestCourseRegistrationCodes(ModuleStoreTestCase):
CourseModeFactory.create(course_id=self.course.id, min_price=50)
self.instructor = InstructorFactory(course_key=self.course.id)
self.client.login(username=self.instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
CourseSalesAdminRole(self.course.id).add_users(self.instructor)
url = reverse('generate_registration_codes',
@@ -4216,7 +4151,6 @@ class TestBulkCohorting(ModuleStoreTestCase):
Verify that we get the error we expect for a given file input.
"""
self.client.login(username=self.staff_user.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
response = self.call_add_users_to_cohorts(file_content, suffix=file_suffix)
self.assertEqual(response.status_code, 400)
result = json.loads(response.content)
@@ -4230,7 +4164,6 @@ class TestBulkCohorting(ModuleStoreTestCase):
"""
mock_store_upload.return_value = (None, 'fake_file_name.csv')
self.client.login(username=self.staff_user.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
response = self.call_add_users_to_cohorts(file_content)
self.assertEqual(response.status_code, 204)
self.assertTrue(mock_store_upload.called)
diff --git a/lms/djangoapps/instructor/tests/test_api_email_localization.py b/lms/djangoapps/instructor/tests/test_api_email_localization.py
index 5f70efd271..d9fd87df93 100644
--- a/lms/djangoapps/instructor/tests/test_api_email_localization.py
+++ b/lms/djangoapps/instructor/tests/test_api_email_localization.py
@@ -33,7 +33,6 @@ class TestInstructorAPIEnrollmentEmailLocalization(ModuleStoreTestCase):
self.instructor = InstructorFactory(course_key=self.course.id)
set_user_preference(self.instructor, LANGUAGE_KEY, 'zh-cn')
self.client.login(username=self.instructor.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
self.student = UserFactory.create()
set_user_preference(self.student, LANGUAGE_KEY, 'fr')
diff --git a/lms/djangoapps/instructor/tests/test_certificates.py b/lms/djangoapps/instructor/tests/test_certificates.py
index 6362d92165..84cae88433 100644
--- a/lms/djangoapps/instructor/tests/test_certificates.py
+++ b/lms/djangoapps/instructor/tests/test_certificates.py
@@ -96,7 +96,6 @@ class CertificatesInstructorDashTest(ModuleStoreTestCase):
def _assert_certificates_visible(self, is_visible):
"""Check that the certificates section is visible on the instructor dash. """
- self.grant_sudo_access(unicode(self.course.id), 'test')
response = self.client.get(self.url)
if is_visible:
self.assertContains(response, "Certificates")
@@ -123,7 +122,6 @@ class CertificatesInstructorDashTest(ModuleStoreTestCase):
def _assert_certificate_status(self, cert_name, expected_status):
"""Check the certificate status display on the instructor dash. """
- self.grant_sudo_access(unicode(self.course.id), 'test')
response = self.client.get(self.url)
if expected_status == 'started':
@@ -140,7 +138,6 @@ class CertificatesInstructorDashTest(ModuleStoreTestCase):
def _assert_enable_certs_button_is_disabled(self):
"""Check that the "enable student-generated certificates" button is disabled. """
- self.grant_sudo_access(unicode(self.course.id), 'test')
response = self.client.get(self.url)
expected_html = ''
self.assertContains(response, expected_html)
@@ -182,13 +179,11 @@ class CertificatesInstructorApiTest(ModuleStoreTestCase):
# Global staff have access
self.client.login(username=self.global_staff.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
response = self.client.post(url)
self.assertEqual(response.status_code, 302)
def test_generate_example_certificates(self):
self.client.login(username=self.global_staff.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
url = reverse(
'generate_example_certificates',
kwargs={'course_id': unicode(self.course.id)}
@@ -207,7 +202,6 @@ class CertificatesInstructorApiTest(ModuleStoreTestCase):
@ddt.data(True, False)
def test_enable_certificate_generation(self, is_enabled):
self.client.login(username=self.global_staff.username, password='test')
- self.grant_sudo_access(unicode(self.course.id), 'test')
url = reverse(
'enable_certificate_generation',
kwargs={'course_id': unicode(self.course.id)}
diff --git a/lms/djangoapps/instructor/tests/test_ecommerce.py b/lms/djangoapps/instructor/tests/test_ecommerce.py
index 24bf4b6861..7fb4f895ac 100644
--- a/lms/djangoapps/instructor/tests/test_ecommerce.py
+++ b/lms/djangoapps/instructor/tests/test_ecommerce.py
@@ -29,7 +29,6 @@ class TestECommerceDashboardViews(ModuleStoreTestCase):
# Create instructor account
self.instructor = AdminFactory.create()
self.client.login(username=self.instructor.username, password="test")
- self.grant_sudo_access(unicode(self.course.id), "test")
mode = CourseMode(
course_id=self.course.id.to_deprecated_string(), mode_slug='honor',
mode_display_name='honor', min_price=10, currency='usd'
diff --git a/lms/djangoapps/instructor/tests/test_email.py b/lms/djangoapps/instructor/tests/test_email.py
index 9aa7b9b0c1..d18e9f403a 100644
--- a/lms/djangoapps/instructor/tests/test_email.py
+++ b/lms/djangoapps/instructor/tests/test_email.py
@@ -29,7 +29,6 @@ class TestNewInstructorDashboardEmailViewMongoBacked(ModuleStoreTestCase):
# Create instructor account
instructor = AdminFactory.create()
self.client.login(username=instructor.username, password="test")
- self.grant_sudo_access(unicode(self.course.id), "test")
# URL for instructor dash
self.url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id.to_deprecated_string()})
diff --git a/lms/djangoapps/instructor/tests/test_legacy_enrollment.py b/lms/djangoapps/instructor/tests/test_legacy_enrollment.py
index 467a44de97..314185bcdd 100644
--- a/lms/djangoapps/instructor/tests/test_legacy_enrollment.py
+++ b/lms/djangoapps/instructor/tests/test_legacy_enrollment.py
@@ -35,8 +35,6 @@ class TestInstructorEnrollsStudent(ModuleStoreTestCase, LoginEnrollmentTestCase)
self.course = CourseFactory.create()
- self.grant_sudo_access(unicode(self.course.id), "test")
-
self.users = [
UserFactory.create(username="student%d" % i, email="student%d@test.com" % i)
for i in xrange(USER_COUNT)
@@ -54,6 +52,7 @@ class TestInstructorEnrollsStudent(ModuleStoreTestCase, LoginEnrollmentTestCase)
"""
course = self.course
+
# Run the Un-enroll students command
url = reverse('instructor_dashboard_legacy', kwargs={'course_id': course.id.to_deprecated_string()})
response = self.client.post(
diff --git a/lms/djangoapps/instructor/tests/test_legacy_raw_download_csv.py b/lms/djangoapps/instructor/tests/test_legacy_raw_download_csv.py
index a3a9490cbd..4f7cfdf9ed 100644
--- a/lms/djangoapps/instructor/tests/test_legacy_raw_download_csv.py
+++ b/lms/djangoapps/instructor/tests/test_legacy_raw_download_csv.py
@@ -44,7 +44,6 @@ class TestRawGradeCSV(TestSubmittingProblems):
"""
# Answer second problem correctly with 2nd user to expose bug
self.login(self.instructor, self.password)
- self.grant_sudo_access(unicode(self.course.id), self.password)
resp = self.submit_question_answer('p2', {'2_1': 'Correct'})
self.assertEqual(resp.status_code, 200)
diff --git a/lms/djangoapps/instructor/tests/test_legacy_xss.py b/lms/djangoapps/instructor/tests/test_legacy_xss.py
index 4d8ec5d741..ff541ff69c 100644
--- a/lms/djangoapps/instructor/tests/test_legacy_xss.py
+++ b/lms/djangoapps/instructor/tests/test_legacy_xss.py
@@ -52,10 +52,9 @@ class TestXss(ModuleStoreTestCase):
)
req.user = self._instructor
req.session = {}
- req.is_sudo = lambda region=None: True
mako_middleware_process_request(req)
- resp = legacy.instructor_dashboard(request=req, course_id=self._course.id.to_deprecated_string())
+ resp = legacy.instructor_dashboard(req, self._course.id.to_deprecated_string())
respUnicode = resp.content.decode(settings.DEFAULT_CHARSET)
self.assertNotIn(self._evil_student.profile.name, respUnicode)
self.assertIn(escape(self._evil_student.profile.name), respUnicode)
diff --git a/lms/djangoapps/instructor/tests/test_spoc_gradebook.py b/lms/djangoapps/instructor/tests/test_spoc_gradebook.py
index 0ccf42a00b..2e0ca99a73 100644
--- a/lms/djangoapps/instructor/tests/test_spoc_gradebook.py
+++ b/lms/djangoapps/instructor/tests/test_spoc_gradebook.py
@@ -39,7 +39,6 @@ class TestGradebook(ModuleStoreTestCase):
kwargs['grading_policy'] = self.grading_policy
self.course = CourseFactory.create(**kwargs)
- self.grant_sudo_access(unicode(self.course.id), 'test')
chapter = ItemFactory.create(
parent_location=self.course.location,
category="sequential",
diff --git a/lms/djangoapps/instructor/tests/views/test_instructor_dashboard.py b/lms/djangoapps/instructor/tests/views/test_instructor_dashboard.py
index 27e19953cf..3694308b45 100644
--- a/lms/djangoapps/instructor/tests/views/test_instructor_dashboard.py
+++ b/lms/djangoapps/instructor/tests/views/test_instructor_dashboard.py
@@ -43,7 +43,6 @@ class TestInstructorDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
# Create instructor account
self.instructor = AdminFactory.create()
self.client.login(username=self.instructor.username, password="test")
- self.grant_sudo_access(unicode(self.course.id), 'test')
# URL for instructor dash
self.url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id.to_deprecated_string()})
@@ -203,7 +202,6 @@ class TestInstructorDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
student_cart.purchase()
self.client.login(username=self.instructor.username, password="test")
- self.grant_sudo_access(unicode(self.course.id), 'test')
CourseFinanceAdminRole(self.course.id).add_users(self.instructor)
single_purchase_total = PaidCourseRegistration.get_total_amount_of_purchased_item(self.course.id)
bulk_purchase_total = CourseRegCodeItem.get_total_amount_of_purchased_item(self.course.id)
@@ -236,13 +234,3 @@ class TestInstructorDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
expected_result,
'CCX Coaches are able to create their own Custom Courses based on this course' in response.content
)
-
- def test_sudo_required_on_dashboard(self):
- """
- Test that sudo_required redirect user to password page.
- """
- # Logout to remove sudo access.
- self.client.logout()
- self.client.login(username=self.instructor.username, password="test")
- response = self.client.get(self.url, content_type='html', HTTP_ACCEPT='html')
- self.assertEqual(response.status_code, 302)
diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py
index a57572ce50..6027525c94 100644
--- a/lms/djangoapps/instructor/views/api.py
+++ b/lms/djangoapps/instructor/views/api.py
@@ -52,7 +52,6 @@ from django_comment_common.models import (
)
from edxmako.shortcuts import render_to_response, render_to_string
from courseware.models import StudentModule
-from django_sudo_helpers.decorators import sudo_required
from shoppingcart.models import (
Coupon,
CourseRegistrationCode,
@@ -318,7 +317,6 @@ COUNTRY_INDEX = 3
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
def register_and_enroll_students(request, course_id): # pylint: disable=too-many-statements
"""
Create new account and Enroll students in this course.
@@ -519,7 +517,6 @@ def create_and_enroll_user(email, username, name, country, password, course_id):
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
@require_post_params(action="enroll or unenroll", identifiers="stringified list of emails and/or usernames")
-@sudo_required
def students_update_enrollment(request, course_id):
"""
Enroll or unenroll students by email.
@@ -687,7 +684,6 @@ def students_update_enrollment(request, course_id):
identifiers="stringified list of emails and/or usernames",
action="add or remove",
)
-@sudo_required
def bulk_beta_modify_access(request, course_id):
"""
Enroll or unenroll users in beta testing program.
@@ -769,7 +765,6 @@ def bulk_beta_modify_access(request, course_id):
rolename="'instructor', 'staff', 'beta', or 'ccx_coach'",
action="'allow' or 'revoke'"
)
-@sudo_required
def modify_access(request, course_id):
"""
Modify staff/instructor access of other user.
@@ -845,7 +840,6 @@ def modify_access(request, course_id):
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('instructor')
@require_query_params(rolename="'instructor', 'staff', or 'beta'")
-@sudo_required
def list_course_role_members(request, course_id):
"""
List instructors and staff.
@@ -896,7 +890,6 @@ def list_course_role_members(request, course_id):
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
def get_grading_config(request, course_id):
"""
Respond with json which contains a html formatted grade summary.
@@ -917,7 +910,6 @@ def get_grading_config(request, course_id):
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
def get_sale_records(request, course_id, csv=False): # pylint: disable=unused-argument, redefined-outer-name
"""
return the summary of all sales records for a particular course
@@ -949,7 +941,6 @@ def get_sale_records(request, course_id, csv=False): # pylint: disable=unused-a
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
def get_sale_order_records(request, course_id): # pylint: disable=unused-argument, redefined-outer-name
"""
return the summary of all sales records for a particular course
@@ -991,7 +982,6 @@ def get_sale_order_records(request, course_id): # pylint: disable=unused-argume
@require_level('staff')
@require_POST
-@sudo_required
def sale_validation(request, course_id):
"""
This method either invalidate or re validate the sale against the invoice number depending upon the event type
@@ -1057,7 +1047,6 @@ def re_validate_invoice(obj_invoice):
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
def get_students_features(request, course_id, csv=False): # pylint: disable=redefined-outer-name
"""
Respond with json which contains a summary of all enrolled students profile information.
@@ -1133,7 +1122,6 @@ def get_students_features(request, course_id, csv=False): # pylint: disable=red
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
def get_students_who_may_enroll(request, course_id):
"""
Initiate generation of a CSV file containing information about
@@ -1165,7 +1153,6 @@ def get_students_who_may_enroll(request, course_id):
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_POST
@require_level('staff')
-@sudo_required
def add_users_to_cohorts(request, course_id):
"""
View method that accepts an uploaded file (using key "uploaded-file")
@@ -1210,7 +1197,6 @@ def add_users_to_cohorts(request, course_id):
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
def get_coupon_codes(request, course_id): # pylint: disable=unused-argument
"""
Respond with csv which contains a summary of all Active Coupons.
@@ -1240,7 +1226,6 @@ def get_coupon_codes(request, course_id): # pylint: disable=unused-argument
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
@require_finance_admin
def get_enrollment_report(request, course_id):
"""
@@ -1266,7 +1251,6 @@ def get_enrollment_report(request, course_id):
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
@require_finance_admin
def get_exec_summary_report(request, course_id):
"""
@@ -1366,7 +1350,6 @@ def random_code_generator():
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
@require_POST
-@sudo_required
def get_registration_codes(request, course_id): # pylint: disable=unused-argument
"""
Respond with csv which contains a summary of all Registration Codes.
@@ -1570,7 +1553,6 @@ def generate_registration_codes(request, course_id):
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
@require_POST
-@sudo_required
def active_registration_codes(request, course_id): # pylint: disable=unused-argument
"""
Respond with csv which contains a summary of all Active Registration Codes.
@@ -1602,7 +1584,6 @@ def active_registration_codes(request, course_id): # pylint: disable=unused-arg
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
@require_POST
-@sudo_required
def spent_registration_codes(request, course_id): # pylint: disable=unused-argument
"""
Respond with csv which contains a summary of all Spent(used) Registration Codes.
@@ -1633,7 +1614,6 @@ def spent_registration_codes(request, course_id): # pylint: disable=unused-argu
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
def get_anon_ids(request, course_id): # pylint: disable=unused-argument
"""
Respond with 2-column CSV output of user-id, anonymized-user-id
@@ -1672,7 +1652,6 @@ def get_anon_ids(request, course_id): # pylint: disable=unused-argument
@require_query_params(
unique_student_identifier="email or username of student for whom to get progress url"
)
-@sudo_required
def get_student_progress_url(request, course_id):
"""
Get the progress url of a student.
@@ -1702,7 +1681,6 @@ def get_student_progress_url(request, course_id):
problem_to_reset="problem urlname to reset"
)
@common_exceptions_400
-@sudo_required
def reset_student_attempts(request, course_id):
"""
@@ -1781,7 +1759,6 @@ def reset_student_attempts(request, course_id):
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
@common_exceptions_400
-@sudo_required
def reset_student_attempts_for_entrance_exam(request, course_id): # pylint: disable=invalid-name
"""
@@ -1848,7 +1825,6 @@ def reset_student_attempts_for_entrance_exam(request, course_id): # pylint: dis
@require_level('instructor')
@require_query_params(problem_to_reset="problem urlname to reset")
@common_exceptions_400
-@sudo_required
def rescore_problem(request, course_id):
"""
Starts a background process a students attempts counter. Optionally deletes student state for a problem.
@@ -1903,7 +1879,6 @@ def rescore_problem(request, course_id):
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('instructor')
@common_exceptions_400
-@sudo_required
def rescore_entrance_exam(request, course_id):
"""
Starts a background process a students attempts counter for entrance exam.
@@ -1955,7 +1930,6 @@ def rescore_entrance_exam(request, course_id):
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
def list_background_email_tasks(request, course_id): # pylint: disable=unused-argument
"""
List background email tasks.
@@ -1974,7 +1948,6 @@ def list_background_email_tasks(request, course_id): # pylint: disable=unused-a
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
def list_email_content(request, course_id): # pylint: disable=unused-argument
"""
List the content of bulk emails sent
@@ -1993,7 +1966,6 @@ def list_email_content(request, course_id): # pylint: disable=unused-argument
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
def list_instructor_tasks(request, course_id):
"""
List instructor tasks.
@@ -2039,7 +2011,6 @@ def list_instructor_tasks(request, course_id):
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
def list_entrance_exam_instructor_tasks(request, course_id): # pylint: disable=invalid-name
"""
List entrance exam related instructor tasks.
@@ -2074,7 +2045,6 @@ def list_entrance_exam_instructor_tasks(request, course_id): # pylint: disable=
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
def list_report_downloads(_request, course_id):
"""
List grade CSV files that are available for download for this course.
@@ -2094,7 +2064,6 @@ def list_report_downloads(_request, course_id):
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
@require_finance_admin
def list_financial_report_downloads(_request, course_id):
"""
@@ -2115,7 +2084,6 @@ def list_financial_report_downloads(_request, course_id):
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
def calculate_grades_csv(request, course_id):
"""
AlreadyRunningError is raised if the course's grades are already being updated.
@@ -2140,7 +2108,6 @@ def calculate_grades_csv(request, course_id):
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
def problem_grade_report(request, course_id):
"""
Request a CSV showing students' grades for all problems in the
@@ -2170,7 +2137,6 @@ def problem_grade_report(request, course_id):
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
@require_query_params('rolename')
-@sudo_required
def list_forum_members(request, course_id):
"""
Lists forum members of a certain rolename.
@@ -2233,7 +2199,6 @@ def list_forum_members(request, course_id):
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
@require_post_params(send_to="sending to whom", subject="subject line", message="message text")
-@sudo_required
def send_email(request, course_id):
"""
Send an email to self, staff, or everyone involved in a course.
@@ -2292,7 +2257,6 @@ def send_email(request, course_id):
action="'allow' or 'revoke'",
)
@common_exceptions_400
-@sudo_required
def update_forum_role_membership(request, course_id):
"""
Modify user's forum role.
@@ -2378,7 +2342,6 @@ def _display_unit(unit):
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
@require_query_params('student', 'url', 'due_datetime')
-@sudo_required
def change_due_date(request, course_id):
"""
Grants a due date extension to a student for a particular unit.
@@ -2400,7 +2363,6 @@ def change_due_date(request, course_id):
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
@require_query_params('student', 'url')
-@sudo_required
def reset_due_date(request, course_id):
"""
Rescinds a due date extension for a student on a particular unit.
@@ -2427,7 +2389,6 @@ def reset_due_date(request, course_id):
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
@require_query_params('url')
-@sudo_required
def show_unit_extensions(request, course_id):
"""
Shows all of the students which have due date extensions for the given unit.
@@ -2442,7 +2403,6 @@ def show_unit_extensions(request, course_id):
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
@require_query_params('student')
-@sudo_required
def show_student_extensions(request, course_id):
"""
Shows all of the due date extensions granted to a particular student in a
@@ -2529,7 +2489,6 @@ def enable_certificate_generation(request, course_id=None):
#---- Gradebook (shown to small courses only) ----
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
-@sudo_required
def spoc_gradebook(request, course_id):
"""
Show the gradebook for this course:
@@ -2571,7 +2530,6 @@ def spoc_gradebook(request, course_id):
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('staff')
@require_POST
-@sudo_required
def mark_student_can_skip_entrance_exam(request, course_id): # pylint: disable=invalid-name
"""
Mark a student to skip entrance exam.
diff --git a/lms/djangoapps/instructor/views/instructor_dashboard.py b/lms/djangoapps/instructor/views/instructor_dashboard.py
index c5f78ea90d..4339a7a7a8 100644
--- a/lms/djangoapps/instructor/views/instructor_dashboard.py
+++ b/lms/djangoapps/instructor/views/instructor_dashboard.py
@@ -34,7 +34,6 @@ from courseware.courses import get_course_by_id, get_studio_url
from django_comment_client.utils import has_forum_access
from django_comment_common.models import FORUM_ROLE_ADMINISTRATOR
from student.models import CourseEnrollment
-from django_sudo_helpers.decorators import sudo_required
from shoppingcart.models import Coupon, PaidCourseRegistration, CourseRegCodeItem
from course_modes.models import CourseMode, CourseModesArchive
from student.roles import CourseFinanceAdminRole, CourseSalesAdminRole
@@ -66,33 +65,8 @@ class InstructorDashboardTab(CourseTab):
return user and has_access(user, 'staff', course, course.id)
-def check_staff_or_404():
- """
- Decorator with argument that requires an access level of the requesting
- user. If the requirement is not satisfied, returns an
- Http404 (404).
-
- Assumes that request is in args[0].
- Assumes that course_id is in kwargs['course_id'].
- """
-
- def decorator(func): # pylint: disable=missing-docstring
- def wrapped(*args, **kwargs): # pylint: disable=missing-docstring
- request = args[0]
- course = get_course_by_id(CourseKey.from_string(kwargs['course_id']))
- user_is_staff = has_access(request.user, "staff", course)
- if user_is_staff:
- return func(*args, **kwargs)
- else:
- raise Http404
- return wrapped
- return decorator
-
-
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
-@check_staff_or_404()
-@sudo_required
def instructor_dashboard_2(request, course_id):
""" Display the instructor dashboard for a course. """
try:
@@ -112,16 +86,16 @@ def instructor_dashboard_2(request, course_id):
'forum_admin': has_forum_access(request.user, course_key, FORUM_ROLE_ADMINISTRATOR),
}
- is_white_label = CourseMode.is_white_label(course_key)
+ if not access['staff']:
+ raise Http404()
- unique_student_identifier = request.GET.get("unique_student_identifier", "")
- problem_to_reset = request.GET.get("problem_to_reset", "")
+ is_white_label = CourseMode.is_white_label(course_key)
sections = [
_section_course_info(course, access),
_section_membership(course, access, is_white_label),
_section_cohort_management(course, access),
- _section_student_admin(course, access, unique_student_identifier, problem_to_reset),
+ _section_student_admin(course, access),
_section_data_download(course, access),
]
@@ -433,21 +407,11 @@ def _is_small_course(course_key):
return is_small_course
-def _section_student_admin(course, access, unique_student_identifier, problem_to_reset):
+def _section_student_admin(course, access):
""" Provide data for the corresponding dashboard section """
course_key = course.id
is_small_course = _is_small_course(course_key)
- problem_url = None
- if problem_to_reset:
- problem_url = reverse(
- 'jump_to',
- kwargs={
- 'course_id': unicode(course_key),
- 'location': problem_to_reset
- }
- )
-
section_data = {
'section_key': 'student_admin',
'section_display_name': _('Student Admin'),
@@ -470,9 +434,6 @@ def _section_student_admin(course, access, unique_student_identifier, problem_to
'list_entrace_exam_instructor_tasks_url': reverse('list_entrance_exam_instructor_tasks',
kwargs={'course_id': unicode(course_key)}),
'spoc_gradebook_url': reverse('spoc_gradebook', kwargs={'course_id': unicode(course_key)}),
- 'unique_student_identifier': unique_student_identifier,
- 'problem_to_reset': problem_to_reset,
- 'problem_url': problem_url,
}
return section_data
diff --git a/lms/djangoapps/instructor/views/legacy.py b/lms/djangoapps/instructor/views/legacy.py
index 6e8ca50ac9..173a36ae41 100644
--- a/lms/djangoapps/instructor/views/legacy.py
+++ b/lms/djangoapps/instructor/views/legacy.py
@@ -52,7 +52,6 @@ from student.models import (
CourseEnrollment,
CourseEnrollmentAllowed,
)
-from django_sudo_helpers.decorators import sudo_required
import track.views
from django.utils.translation import ugettext as _
@@ -80,7 +79,6 @@ def split_by_comma_and_whitespace(a_str):
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
-@sudo_required
def instructor_dashboard(request, course_id):
"""Display the instructor dashboard for a course."""
course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
diff --git a/lms/djangoapps/shoppingcart/admin.py b/lms/djangoapps/shoppingcart/admin.py
index 7fa009ecd0..fae033a849 100644
--- a/lms/djangoapps/shoppingcart/admin.py
+++ b/lms/djangoapps/shoppingcart/admin.py
@@ -1,5 +1,5 @@
"""Django admin interface for the shopping cart models. """
-from django.contrib import admin
+from ratelimitbackend import admin
from shoppingcart.models import (
PaidCourseRegistrationAnnotation,
Coupon,
diff --git a/lms/djangoapps/verify_student/admin.py b/lms/djangoapps/verify_student/admin.py
index cda4087799..6a7c69b9e2 100644
--- a/lms/djangoapps/verify_student/admin.py
+++ b/lms/djangoapps/verify_student/admin.py
@@ -1,8 +1,4 @@
-"""
-django admin pages for verify_student models
-"""
-
-from django.contrib import admin
+from ratelimitbackend import admin
from config_models.admin import ConfigurationModelAdmin
from verify_student.models import (
SoftwareSecurePhotoVerification,
diff --git a/lms/envs/common.py b/lms/envs/common.py
index 4b11d62e9a..833c8c6d61 100644
--- a/lms/envs/common.py
+++ b/lms/envs/common.py
@@ -1176,10 +1176,6 @@ MIDDLEWARE_CLASSES = (
# catches any uncaught RateLimitExceptions and returns a 403 instead of a 500
'ratelimitbackend.middleware.RateLimitMiddleware',
-
- # force re-authentication before activating administrative functions
- 'sudo.middleware.SudoMiddleware',
-
# needs to run after locale middleware (or anything that modifies the request context)
'edxmako.middleware.MakoMiddleware',
@@ -1901,9 +1897,6 @@ INSTALLED_APPS = (
# Surveys
'survey',
- # Allows sudo-mode
- 'sudo',
-
'lms.djangoapps.lms_xblock',
'openedx.core.djangoapps.content.course_overviews',
diff --git a/lms/static/coffee/src/instructor_dashboard/data_download.coffee b/lms/static/coffee/src/instructor_dashboard/data_download.coffee
index 38f97c34c9..4fa8de081e 100644
--- a/lms/static/coffee/src/instructor_dashboard/data_download.coffee
+++ b/lms/static/coffee/src/instructor_dashboard/data_download.coffee
@@ -27,13 +27,13 @@ class DataDownload
@$problem_grade_report_csv_btn = @$section.find("input[name='problem-grade-report']'")
# response areas
- @$download = @$section.find '.data-download-container'
- @$download_display_text = @$download.find '.data-display-text'
+ @$download = @$section.find '.data-download-container'
+ @$download_display_text = @$download.find '.data-display-text'
@$download_request_response_error = @$download.find '.request-response-error'
- @$reports = @$section.find '.reports-download-container'
- @$download_display_table = @$reports.find '.data-display-table'
- @$reports_request_response = @$reports.find '.request-response'
- @$reports_request_response_error = @$reports.find '.request-response-error'
+ @$reports = @$section.find '.reports-download-container'
+ @$download_display_table = @$reports.find '.data-display-table'
+ @$reports_request_response = @$reports.find '.request-response'
+ @$reports_request_response_error = @$reports.find '.request-response-error'
@report_downloads = new (ReportDownloads()) @$section
@instructor_tasks = new (PendingInstructorTasks()) @$section
@@ -58,14 +58,12 @@ class DataDownload
$.ajax
dataType: 'json'
url: url
- error: std_ajax_err((=>
+ error: (std_ajax_err) =>
@$reports_request_response_error.text gettext("Error generating student profile information. Please try again.")
- $(".msg-error").css({"display": "block"})
- ), true)
-
+ $(".msg-error").css({"display":"block"})
success: (data) =>
@$reports_request_response.text data['status']
- $(".msg-confirm").css({"display": "block"})
+ $(".msg-confirm").css({"display":"block"})
@$list_studs_btn.click (e) =>
url = @$list_studs_btn.data 'endpoint'
@@ -78,11 +76,9 @@ class DataDownload
$.ajax
dataType: 'json'
url: url
- error: std_ajax_err((=>
+ error: (std_ajax_err) =>
@clear_display()
@$download_request_response_error.text gettext("Error getting student list.")
- ), true)
-
success: (data) =>
@clear_display()
@@ -99,7 +95,7 @@ class DataDownload
$table_placeholder = $ '', class: 'slickgrid'
@$download_display_table.append $table_placeholder
grid = new Slick.Grid($table_placeholder, grid_data, columns, options)
- # grid.autosizeColumns()
+ # grid.autosizeColumns()
@$list_may_enroll_csv_btn.click (e) =>
@clear_display()
@@ -108,14 +104,12 @@ class DataDownload
$.ajax
dataType: 'json'
url: url
- error: std_ajax_err((=>
+ error: (std_ajax_err) =>
@$reports_request_response_error.text gettext("Error generating list of students who may enroll. Please try again.")
- $(".msg-error").css({"display": "block"})
- ), true)
-
+ $(".msg-error").css({"display":"block"})
success: (data) =>
@$reports_request_response.text data['status']
- $(".msg-confirm").css({"display": "block"})
+ $(".msg-confirm").css({"display":"block"})
@$grade_config_btn.click (e) =>
url = @$grade_config_btn.data 'endpoint'
@@ -123,10 +117,9 @@ class DataDownload
$.ajax
dataType: 'json'
url: url
- error: std_ajax_err((=>
+ error: (std_ajax_err) =>
@clear_display()
@$download_request_response_error.text gettext("Error retrieving grading configuration.")
- ), true)
success: (data) =>
@clear_display()
@$download_display_text.html data['grading_config_summary']
@@ -138,22 +131,20 @@ class DataDownload
@onClickGradeDownload @$problem_grade_report_csv_btn, gettext("Error generating problem grade report. Please try again.")
onClickGradeDownload: (button, errorMessage) ->
- # Clear any CSS styling from the request-response areas
- #$(".msg-confirm").css({"display":"none"})
- #$(".msg-error").css({"display":"none"})
- @clear_display()
- url = button.data 'endpoint'
- $.ajax
- dataType: 'json'
- url: url
- error: std_ajax_err((=>
- @.$reports_request_response_error.text gettext('Error generating student profile information. Please try again.')
- $('.msg-error').css 'display': 'block'
- ), true
- )
- success: (data) =>
- @$reports_request_response.text data['status']
- $(".msg-confirm").css({"display": "block"})
+ # Clear any CSS styling from the request-response areas
+ #$(".msg-confirm").css({"display":"none"})
+ #$(".msg-error").css({"display":"none"})
+ @clear_display()
+ url = button.data 'endpoint'
+ $.ajax
+ dataType: 'json'
+ url: url
+ error: (std_ajax_err) =>
+ @$reports_request_response_error.text errorMessage
+ $(".msg-error").css({"display":"block"})
+ success: (data) =>
+ @$reports_request_response.text data['status']
+ $(".msg-confirm").css({"display":"block"})
# handler for when the section title is clicked.
onClickTitle: ->
@@ -175,8 +166,8 @@ class DataDownload
@$reports_request_response.empty()
@$reports_request_response_error.empty()
# Clear any CSS styling from the request-response areas
- $(".msg-confirm").css({"display": "none"})
- $(".msg-error").css({"display": "none"})
+ $(".msg-confirm").css({"display":"none"})
+ $(".msg-error").css({"display":"none"})
# export for use
# create parent namespaces if they do not already exist.
diff --git a/lms/static/coffee/src/instructor_dashboard/membership.coffee b/lms/static/coffee/src/instructor_dashboard/membership.coffee
index 057c89cec5..4dc86bc849 100644
--- a/lms/static/coffee/src/instructor_dashboard/membership.coffee
+++ b/lms/static/coffee/src/instructor_dashboard/membership.coffee
@@ -14,7 +14,7 @@ emailStudents = false
class MemberListWidget
# create a MemberListWidget `$container` is a jquery object to embody.
# `params` holds template parameters. `params` should look like the defaults below.
- constructor: (@$container, params = {}) ->
+ constructor: (@$container, params={}) ->
params = _.defaults params,
title: "Member List"
info: """
@@ -117,15 +117,14 @@ class AuthListWidget extends MemberListWidget
# create revoke button and insert it into the row
label_trans = gettext("Revoke access")
- $revoke_btn = $ _.template(' <%= label %>
',
- {label: label_trans}),
+ $revoke_btn = $ _.template(' <%= label %>
', {label: label_trans}),
class: 'revoke'
$revoke_btn.click =>
- @modify_member_access member.email, 'revoke', (error) =>
- # abort on error
- return @show_errors error unless error is null
- @clear_errors()
- @reload_list()
+ @modify_member_access member.email, 'revoke', (error) =>
+ # abort on error
+ return @show_errors error unless error is null
+ @clear_errors()
+ @reload_list()
@add_row [member.username, member.email, $revoke_btn]
# clear error display
@@ -140,13 +139,11 @@ class AuthListWidget extends MemberListWidget
$.ajax
dataType: 'json'
url: @list_endpoint
- data:
- rolename: @rolename
+ data: rolename: @rolename
success: (data) => cb? null, data[@rolename]
- error: std_ajax_err((=>
- # Translators: A rolename appears this sentence. A rolename is something like "staff" or "beta tester".
+ error: std_ajax_err =>
+ `// Translators: A rolename appears this sentence. A rolename is something like "staff" or "beta tester".`
cb? gettext("Error fetching list for role") + " '#{@rolename}'"
- ), true)
# send ajax request to modify access
# (add or remove them from the list)
@@ -161,9 +158,7 @@ class AuthListWidget extends MemberListWidget
rolename: @rolename
action: action
success: (data) => @member_response data
- error: std_ajax_err((=>
- cb? gettext "Error changing user's permissions."
- ), true)
+ error: std_ajax_err => cb? gettext "Error changing user's permissions."
member_response: (data) ->
@clear_errors()
@@ -209,15 +204,15 @@ class @AutoEnrollmentViaCsv
event.preventDefault()
data = new FormData(event.currentTarget)
$.ajax
- dataType: 'json'
- type: 'POST'
- url: event.currentTarget.action
- data: data
- processData: false
- contentType: false
- success: (data) =>
- @processing = false
- @display_response data
+ dataType: 'json'
+ type: 'POST'
+ url: event.currentTarget.action
+ data: data
+ processData: false
+ contentType: false
+ success: (data) =>
+ @processing = false
+ @display_response data
return false
@@ -251,7 +246,7 @@ class @AutoEnrollmentViaCsv
if student_result.is_general_error
details.push student_result.response
else
- response_message = student_result.username + ' (' + student_result.email + '): ' + ' (' + student_result.response + ')'
+ response_message = student_result.username + ' ('+ student_result.email + '): ' + ' (' + student_result.response + ')'
details.push response_message
@$results.append @render_notification_view type, title, message, details
@@ -266,23 +261,23 @@ class @AutoEnrollmentViaCsv
render_notification_view: (type, title, message, details) ->
notification_model = new NotificationModel()
notification_model.set({
- 'type': type,
- 'title': title,
- 'message': message,
- 'details': details,
+ 'type': type,
+ 'title': title,
+ 'message': message,
+ 'details': details,
});
- view = new NotificationView(model: notification_model);
+ view = new NotificationView(model:notification_model);
view.render()
return view.$el.html()
class BetaTesterBulkAddition
constructor: (@$container) ->
# gather elements
- @$identifier_input = @$container.find("textarea[name='student-ids-for-beta']")
- @$btn_beta_testers = @$container.find("input[name='beta-testers']")
- @$checkbox_autoenroll = @$container.find("input[name='auto-enroll']")
+ @$identifier_input = @$container.find("textarea[name='student-ids-for-beta']")
+ @$btn_beta_testers = @$container.find("input[name='beta-testers']")
+ @$checkbox_autoenroll = @$container.find("input[name='auto-enroll']")
@$checkbox_emailstudents = @$container.find("input[name='email-students-beta']")
- @$task_response = @$container.find(".request-response")
+ @$task_response = @$container.find(".request-response")
@$request_response_error = @$container.find(".request-response-error")
# click handlers
@@ -301,10 +296,7 @@ class BetaTesterBulkAddition
url: @$btn_beta_testers.data 'endpoint'
data: send_data
success: (data) => @display_response data
- error: std_ajax_err((=>
- @fail_with_error gettext "Error adding/removing users as beta testers."
- ), true)
-
+ error: std_ajax_err => @fail_with_error gettext "Error adding/removing users as beta testers."
# clear the input text field
clear_input: ->
@@ -373,13 +365,13 @@ class BetaTesterBulkAddition
class BatchEnrollment
constructor: (@$container) ->
# gather elements
- @$identifier_input = @$container.find("textarea[name='student-ids']")
- @$enrollment_button = @$container.find(".enrollment-button")
- @$is_course_white_label = @$container.find("#is_course_white_label").val()
- @$reason_field = @$container.find("textarea[name='reason-field']")
- @$checkbox_autoenroll = @$container.find("input[name='auto-enroll']")
+ @$identifier_input = @$container.find("textarea[name='student-ids']")
+ @$enrollment_button = @$container.find(".enrollment-button")
+ @$is_course_white_label = @$container.find("#is_course_white_label").val()
+ @$reason_field = @$container.find("textarea[name='reason-field']")
+ @$checkbox_autoenroll = @$container.find("input[name='auto-enroll']")
@$checkbox_emailstudents = @$container.find("input[name='email-students']")
- @$task_response = @$container.find(".request-response")
+ @$task_response = @$container.find(".request-response")
@$request_response_error = @$container.find(".request-response-error")
# attach click handler for enrollment buttons
@@ -403,9 +395,8 @@ class BatchEnrollment
url: $(event.target).data 'endpoint'
data: send_data
success: (data) => @display_response data
- error: std_ajax_err((=>
- @fail_with_error gettext "Error enrolling/unenrolling users."
- ), true)
+ error: std_ajax_err => @fail_with_error gettext "Error enrolling/unenrolling users."
+
# clear the input text field
clear_input: ->
@@ -487,7 +478,7 @@ class BatchEnrollment
else
allowed.push student_results
- # The instructor is trying to unenroll someone who is not enrolled or allowed to enroll; non-sensical action.
+ # The instructor is trying to unenroll someone who is not enrolled or allowed to enroll; non-sensical action.
else if data_from_server.action is 'unenroll' and not (student_results.before.enrollment) and not (student_results.before.allowed)
notunenrolled.push student_results
@@ -581,11 +572,11 @@ class AuthList
# rolename is the name of Role for forums for the forum endpoints
constructor: (@$container, @rolename) ->
# gather elements
- @$display_table = @$container.find('.auth-list-table')
+ @$display_table = @$container.find('.auth-list-table')
@$request_response_error = @$container.find('.request-response-error')
- @$add_section = @$container.find('.auth-list-add')
- @$allow_field = @$add_section.find("input[name='email']")
- @$allow_button = @$add_section.find("input[name='allow']")
+ @$add_section = @$container.find('.auth-list-add')
+ @$allow_field = @$add_section.find("input[name='email']")
+ @$allow_button = @$add_section.find("input[name='allow']")
# attach click handler
@$allow_button.click =>
@@ -606,7 +597,7 @@ class AuthList
options =
enableCellNavigation: true
enableColumnReorder: false
- # autoHeight: true
+ # autoHeight: true
forceFitColumns: true
# this is a hack to put a button/link in a slick grid cell
@@ -627,10 +618,10 @@ class AuthList
field: 'first_name'
name: 'First Name'
,
- # id: 'last_name'
- # field: 'last_name'
- # name: 'Last Name'
- # ,
+ # id: 'last_name'
+ # field: 'last_name'
+ # name: 'Last Name'
+ # ,
id: 'revoke'
field: 'revoke'
name: 'Revoke'
@@ -655,13 +646,9 @@ class AuthList
$.ajax
dataType: 'json'
url: @$display_table.data 'endpoint'
- data:
- rolename: @rolename
+ data: rolename: @rolename
success: load_auth_list
- error: std_ajax_err((=>
- @$request_response_error.text "Error fetching list for '#{@rolename}'"
- ), true)
-
+ error: std_ajax_err => @$request_response_error.text "Error fetching list for '#{@rolename}'"
# slickgrid's layout collapses when rendered
@@ -683,9 +670,8 @@ class AuthList
rolename: @rolename
action: action
success: (data) -> cb?(data)
- error: std_ajax_err((=>
- @$request_response_error.text gettext "Error changing user's permissions."
- ), true)
+ error: std_ajax_err => @$request_response_error.text gettext "Error changing user's permissions."
+
# Membership Section
class Membership
diff --git a/lms/static/coffee/src/instructor_dashboard/send_email.coffee b/lms/static/coffee/src/instructor_dashboard/send_email.coffee
index 6a950bfdc6..9851658b5a 100644
--- a/lms/static/coffee/src/instructor_dashboard/send_email.coffee
+++ b/lms/static/coffee/src/instructor_dashboard/send_email.coffee
@@ -79,9 +79,9 @@ class SendEmail
data: send_data
success: (data) =>
@display_response success_message
- error: std_ajax_err((=>
+
+ error: std_ajax_err =>
@fail_with_error gettext('Error sending email.')
- ), true)
else
@$task_response.empty()
@@ -99,41 +99,38 @@ class SendEmail
else
@$history_request_response_error.text gettext("There is no email history for this course.")
# Enable the msg-warning css display
- @$history_request_response_error.css({"display": "block"})
- error: std_ajax_err((=>
+ @$history_request_response_error.css({"display":"block"})
+ error: std_ajax_err =>
@$history_request_response_error.text gettext("There was an error obtaining email task history for this course.")
- ), true)
# List content history for emails sent
@$btn_task_history_email_content.click =>
url = @$btn_task_history_email_content.data 'endpoint'
$.ajax
dataType: 'json'
- url: url
+ url : url
success: (data) =>
if data.emails.length
create_email_content_table @$table_email_content_history, @$email_content_table_inner, data.emails
create_email_message_views @$email_messages_wrapper, data.emails
else
@$content_request_response_error.text gettext("There is no email history for this course.")
- @$content_request_response_error.css({"display": "block"})
- error: std_ajax_err((=>
+ @$content_request_response_error.css({"display":"block"})
+ error: std_ajax_err =>
@$content_request_response_error.text gettext("There was an error obtaining email content history for this course.")
- ), true)
-
fail_with_error: (msg) ->
console.warn msg
@$task_response.empty()
@$request_response_error.empty()
@$request_response_error.text msg
- $(".msg-confirm").css({"display": "none"})
+ $(".msg-confirm").css({"display":"none"})
display_response: (data_from_server) ->
@$task_response.empty()
@$request_response_error.empty()
@$task_response.text(data_from_server)
- $(".msg-confirm").css({"display": "block"})
+ $(".msg-confirm").css({"display":"block"})
# Email Section
diff --git a/lms/static/coffee/src/instructor_dashboard/student_admin.coffee b/lms/static/coffee/src/instructor_dashboard/student_admin.coffee
index 4114e19821..cabef93b0c 100644
--- a/lms/static/coffee/src/instructor_dashboard/student_admin.coffee
+++ b/lms/static/coffee/src/instructor_dashboard/student_admin.coffee
@@ -32,42 +32,37 @@ class @StudentAdmin
# some buttons are optional because they can be flipped by the instructor task feature switch
# student-specific
@$field_student_select_progress = find_and_assert @$section, "input[name='student-select-progress']"
- @$field_student_select_grade = find_and_assert @$section, "input[name='student-select-grade']"
- @$progress_link = find_and_assert @$section, "a.progress-link"
+ @$field_student_select_grade = find_and_assert @$section, "input[name='student-select-grade']"
+ @$progress_link = find_and_assert @$section, "a.progress-link"
@$field_problem_select_single = find_and_assert @$section, "input[name='problem-select-single']"
- @$btn_reset_attempts_single = find_and_assert @$section, "input[name='reset-attempts-single']"
- @$btn_delete_state_single = @$section.find "input[name='delete-state-single']"
- @$btn_rescore_problem_single = @$section.find "input[name='rescore-problem-single']"
- @$btn_task_history_single = @$section.find "input[name='task-history-single']"
- @$table_task_history_single = @$section.find ".task-history-single-table"
+ @$btn_reset_attempts_single = find_and_assert @$section, "input[name='reset-attempts-single']"
+ @$btn_delete_state_single = @$section.find "input[name='delete-state-single']"
+ @$btn_rescore_problem_single = @$section.find "input[name='rescore-problem-single']"
+ @$btn_task_history_single = @$section.find "input[name='task-history-single']"
+ @$table_task_history_single = @$section.find ".task-history-single-table"
# entrance-exam-specific
- @$field_entrance_exam_student_select_grade = @$section.find "input[name='entrance-exam-student-select-grade']"
- @$btn_reset_entrance_exam_attempts = @$section.find "input[name='reset-entrance-exam-attempts']"
- @$btn_delete_entrance_exam_state = @$section.find "input[name='delete-entrance-exam-state']"
- @$btn_rescore_entrance_exam = @$section.find "input[name='rescore-entrance-exam']"
- @$btn_skip_entrance_exam = @$section.find "input[name='skip-entrance-exam']"
- @$btn_entrance_exam_task_history = @$section.find "input[name='entrance-exam-task-history']"
- @$table_entrance_exam_task_history = @$section.find ".entrance-exam-task-history-table"
+ @$field_entrance_exam_student_select_grade = @$section.find "input[name='entrance-exam-student-select-grade']"
+ @$btn_reset_entrance_exam_attempts = @$section.find "input[name='reset-entrance-exam-attempts']"
+ @$btn_delete_entrance_exam_state = @$section.find "input[name='delete-entrance-exam-state']"
+ @$btn_rescore_entrance_exam = @$section.find "input[name='rescore-entrance-exam']"
+ @$btn_skip_entrance_exam = @$section.find "input[name='skip-entrance-exam']"
+ @$btn_entrance_exam_task_history = @$section.find "input[name='entrance-exam-task-history']"
+ @$table_entrance_exam_task_history = @$section.find ".entrance-exam-task-history-table"
# course-specific
- @$field_problem_select_all = @$section.find "input[name='problem-select-all']"
- @$btn_reset_attempts_all = @$section.find "input[name='reset-attempts-all']"
- @$btn_rescore_problem_all = @$section.find "input[name='rescore-problem-all']"
- @$btn_task_history_all = @$section.find "input[name='task-history-all']"
- @$table_task_history_all = @$section.find ".task-history-all-table"
- @instructor_tasks = new (PendingInstructorTasks()) @$section
+ @$field_problem_select_all = @$section.find "input[name='problem-select-all']"
+ @$btn_reset_attempts_all = @$section.find "input[name='reset-attempts-all']"
+ @$btn_rescore_problem_all = @$section.find "input[name='rescore-problem-all']"
+ @$btn_task_history_all = @$section.find "input[name='task-history-all']"
+ @$table_task_history_all = @$section.find ".task-history-all-table"
+ @instructor_tasks = new (PendingInstructorTasks()) @$section
# response areas
@$request_response_error_progress = find_and_assert @$section, ".student-specific-container .request-response-error"
@$request_response_error_grade = find_and_assert @$section, ".student-grade-container .request-response-error"
- @$request_response_error_ee = @$section.find ".entrance-exam-grade-container .request-response-error"
- @$request_response_error_all = @$section.find ".course-specific-container .request-response-error"
-
- $student_grade_container = find_and_assert @$section, ".student-grade-container"
- unique_student_identifier = @$field_student_select_grade.val()
- if unique_student_identifier
- @scroll_to_section($student_grade_container)
+ @$request_response_error_ee = @$section.find ".entrance-exam-grade-container .request-response-error"
+ @$request_response_error_all = @$section.find ".course-specific-container .request-response-error"
# attach click handlers
@@ -83,13 +78,10 @@ class @StudentAdmin
$.ajax
dataType: 'json'
url: @$progress_link.data 'endpoint'
- data:
- unique_student_identifier: unique_student_identifier
+ data: unique_student_identifier: unique_student_identifier
success: @clear_errors_then (data) ->
window.location = data.progress_url
- error: std_ajax_err((=>
- @$request_response_error_progress.text full_error_message
- ), true)
+ error: std_ajax_err => @$request_response_error_progress.text full_error_message
# reset attempts for student on problem
@$btn_reset_attempts_single.click =>
@@ -105,19 +97,15 @@ class @StudentAdmin
delete_module: false
success_message = gettext("Success! Problem attempts reset for problem '<%= problem_id %>' and student '<%= student_id %>'.")
error_message = gettext("Error resetting problem attempts for problem '<%= problem_id %>' and student '<%= student_id %>'. Make sure that the problem and student identifiers are complete and correct.")
- full_success_message = _.template(success_message,
- {problem_id: problem_to_reset, student_id: unique_student_identifier})
- full_error_message = _.template(error_message,
- {problem_id: problem_to_reset, student_id: unique_student_identifier})
+ full_success_message = _.template(success_message, {problem_id: problem_to_reset, student_id: unique_student_identifier})
+ full_error_message = _.template(error_message, {problem_id: problem_to_reset, student_id: unique_student_identifier})
$.ajax
dataType: 'json'
url: @$btn_reset_attempts_single.data 'endpoint'
data: send_data
success: @clear_errors_then -> alert full_success_message
- error: std_ajax_err((=>
- @$request_response_error_grade.text full_error_message
- ), true)
+ error: std_ajax_err => @$request_response_error_grade.text full_error_message
# delete state for student on problem
@$btn_delete_state_single.click =>
@@ -128,8 +116,7 @@ class @StudentAdmin
if not problem_to_reset
return @$request_response_error_grade.text gettext("Please enter a problem location.")
confirm_message = gettext("Delete student '<%= student_id %>'s state on problem '<%= problem_id %>'?")
- full_confirm_message = _.template(confirm_message,
- {student_id: unique_student_identifier, problem_id: problem_to_reset})
+ full_confirm_message = _.template(confirm_message, {student_id: unique_student_identifier, problem_id: problem_to_reset})
if window.confirm full_confirm_message
send_data =
@@ -137,17 +124,14 @@ class @StudentAdmin
problem_to_reset: problem_to_reset
delete_module: true
error_message = gettext("Error deleting student '<%= student_id %>'s state on problem '<%= problem_id %>'. Make sure that the problem and student identifiers are complete and correct.")
- full_error_message = _.template(error_message,
- {student_id: unique_student_identifier, problem_id: problem_to_reset})
+ full_error_message = _.template(error_message, {student_id: unique_student_identifier, problem_id: problem_to_reset})
$.ajax
dataType: 'json'
url: @$btn_delete_state_single.data 'endpoint'
data: send_data
success: @clear_errors_then -> alert gettext('Module state successfully deleted.')
- error: std_ajax_err((=>
- @$request_response_error_grade.text full_error_message
- ), true)
+ error: std_ajax_err => @$request_response_error_grade.text full_error_message
else
# Clear error messages if "Cancel" was chosen on confirmation alert
@clear_errors()
@@ -164,20 +148,16 @@ class @StudentAdmin
unique_student_identifier: unique_student_identifier
problem_to_reset: problem_to_reset
success_message = gettext("Started rescore problem task for problem '<%= problem_id %>' and student '<%= student_id %>'. Click the 'Show Background Task History for Student' button to see the status of the task.")
- full_success_message = _.template(success_message,
- {student_id: unique_student_identifier, problem_id: problem_to_reset})
+ full_success_message = _.template(success_message, {student_id: unique_student_identifier, problem_id: problem_to_reset})
error_message = gettext("Error starting a task to rescore problem '<%= problem_id %>' for student '<%= student_id %>'. Make sure that the the problem and student identifiers are complete and correct.")
- full_error_message = _.template(error_message,
- {student_id: unique_student_identifier, problem_id: problem_to_reset})
+ full_error_message = _.template(error_message, {student_id: unique_student_identifier, problem_id: problem_to_reset})
$.ajax
dataType: 'json'
url: @$btn_rescore_problem_single.data 'endpoint'
data: send_data
success: @clear_errors_then -> alert full_success_message
- error: std_ajax_err((=>
- @$request_response_error_grade.text full_error_message
- ), true)
+ error: std_ajax_err => @$request_response_error_grade.text full_error_message
# list task history for student+problem
@$btn_task_history_single.click =>
@@ -191,8 +171,7 @@ class @StudentAdmin
unique_student_identifier: unique_student_identifier
problem_location_str: problem_to_reset
error_message = gettext("Error getting task history for problem '<%= problem_id %>' and student '<%= student_id %>'. Make sure that the problem and student identifiers are complete and correct.")
- full_error_message = _.template(error_message,
- {student_id: unique_student_identifier, problem_id: problem_to_reset})
+ full_error_message = _.template(error_message, {student_id: unique_student_identifier, problem_id: problem_to_reset})
$.ajax
dataType: 'json'
@@ -200,11 +179,9 @@ class @StudentAdmin
data: send_data
success: @clear_errors_then (data) =>
create_task_list_table @$table_task_history_single, data.tasks
- error: std_ajax_err((=>
- @$request_response_error_grade.text full_error_message
- ), true)
+ error: std_ajax_err => @$request_response_error_grade.text full_error_message
- # reset entrance exam attempts for student
+ # reset entrance exam attempts for student
@$btn_reset_entrance_exam_attempts.click =>
unique_student_identifier = @$field_entrance_exam_student_select_grade.val()
if not unique_student_identifier
@@ -221,13 +198,12 @@ class @StudentAdmin
success_message = gettext("Entrance exam attempts is being reset for student '{student_id}'.")
full_success_message = interpolate_text(success_message, {student_id: unique_student_identifier})
alert full_success_message
- error: std_ajax_err((=>
+ error: std_ajax_err =>
error_message = gettext("Error resetting entrance exam attempts for student '{student_id}'. Make sure student identifier is correct.")
full_error_message = interpolate_text(error_message, {student_id: unique_student_identifier})
@$request_response_error_ee.text full_error_message
- ), true)
- # start task to rescore entrance exam for student
+ # start task to rescore entrance exam for student
@$btn_rescore_entrance_exam.click =>
unique_student_identifier = @$field_entrance_exam_student_select_grade.val()
if not unique_student_identifier
@@ -248,7 +224,7 @@ class @StudentAdmin
full_error_message = interpolate_text(error_message, {student_id: unique_student_identifier})
@$request_response_error_ee.text full_error_message
- # Mark a student to skip entrance exam
+ # Mark a student to skip entrance exam
@$btn_skip_entrance_exam.click =>
unique_student_identifier = @$field_entrance_exam_student_select_grade.val()
if not unique_student_identifier
@@ -270,7 +246,7 @@ class @StudentAdmin
error_message = gettext("An error occurred. Make sure that the student's username or email address is correct and try again.")
@$request_response_error_ee.text error_message
- # delete student state for entrance exam
+ # delete student state for entrance exam
@$btn_delete_entrance_exam_state.click =>
unique_student_identifier = @$field_entrance_exam_student_select_grade.val()
if not unique_student_identifier
@@ -332,9 +308,7 @@ class @StudentAdmin
url: @$btn_reset_attempts_all.data 'endpoint'
data: send_data
success: @clear_errors_then -> alert full_success_message
- error: std_ajax_err((=>
- @$request_response_error_all.text full_error_message
- ), true)
+ error: std_ajax_err => @$request_response_error_all.text full_error_message
else
# Clear error messages if "Cancel" was chosen on confirmation alert
@clear_errors()
@@ -360,9 +334,7 @@ class @StudentAdmin
url: @$btn_rescore_problem_all.data 'endpoint'
data: send_data
success: @clear_errors_then -> alert full_success_message
- error: std_ajax_err((=>
- @$request_response_error_all.text full_error_message
- ), true)
+ error: std_ajax_err => @$request_response_error_all.text full_error_message
else
# Clear error messages if "Cancel" was chosen on confirmation alert
@clear_errors()
@@ -381,9 +353,7 @@ class @StudentAdmin
data: send_data
success: @clear_errors_then (data) =>
create_task_list_table @$table_task_history_all, data.tasks
- error: std_ajax_err((=>
- @$request_response_error_all.text gettext("Error listing task history for this student and problem.")
- ), true)
+ error: std_ajax_err => @$request_response_error_all.text gettext("Error listing task history for this student and problem.")
# wraps a function, but first clear the error displays
clear_errors_then: (cb) ->
@@ -401,10 +371,6 @@ class @StudentAdmin
@$request_response_error_ee.empty()
@$request_response_error_all.empty()
-
- scroll_to_section: (element) ->
- $(window).scrollTop(element.offset().top).scrollLeft(element.offset().left)
-
# handler for when the section title is clicked.
onClickTitle: -> @instructor_tasks.task_poller.start()
diff --git a/lms/static/coffee/src/instructor_dashboard/util.coffee b/lms/static/coffee/src/instructor_dashboard/util.coffee
index b1c89f760f..7a9f80b167 100644
--- a/lms/static/coffee/src/instructor_dashboard/util.coffee
+++ b/lms/static/coffee/src/instructor_dashboard/util.coffee
@@ -19,12 +19,10 @@ find_and_assert = ($root, selector) ->
#
# wraps a `handler` function so that first
# it prints basic error information to the console.
-@std_ajax_err = (handler, sudo_reload=false) -> (jqXHR, textStatus, errorThrown) ->
+@std_ajax_err = (handler) -> (jqXHR, textStatus, errorThrown) ->
console.warn """ajax error
textStatus: #{textStatus}
errorThrown: #{errorThrown}"""
- if sudo_reload == true and jqXHR.status == 401
- window.location.reload()
handler.apply this, arguments
@@ -299,10 +297,7 @@ class @PendingInstructorTasks
@$no_tasks_message.empty()
@$no_tasks_message.append $('').text gettext("No tasks currently running.")
@$no_tasks_message.show()
- error: std_ajax_err((=>
- console.error "Error finding pending tasks to display"
- ), true)
-
+ error: std_ajax_err => console.error "Error finding pending tasks to display"
### /Pending Instructor Tasks Section ####
class KeywordValidator
diff --git a/lms/static/js/spec/staff_debug_actions_spec.js b/lms/static/js/spec/staff_debug_actions_spec.js
index 92e8c4d995..11c6e1a64c 100644
--- a/lms/static/js/spec/staff_debug_actions_spec.js
+++ b/lms/static/js/spec/staff_debug_actions_spec.js
@@ -4,7 +4,6 @@ define(['backbone', 'jquery', 'js/staff_debug_actions'],
describe('StaffDebugActions', function () {
var location = 'i4x://edX/Open_DemoX/edx_demo_course/problem/test_loc';
var locationName = 'test_loc';
- var action = {location: location, locationName: locationName};
var fixture_id = 'sd_fu_' + locationName;
var fixture = $('', { id: fixture_id, placeholder: "userman" });
var escapableLocationName = 'test\.\*\+\?\^\:\$\{\}\(\)\|\]\[loc';
@@ -14,11 +13,7 @@ define(['backbone', 'jquery', 'js/staff_debug_actions'],
describe('get_url ', function () {
it('defines url to courseware ajax entry point', function () {
spyOn(StaffDebug, "get_current_url").andReturn("/courses/edX/Open_DemoX/edx_demo_course/courseware/stuff");
- $('body').append(fixture);
- var expected_url = '/courses/edX/Open_DemoX/edx_demo_course/instructor?unique_student_identifier=userman&problem_to_reset=' + encodeURIComponent(action.location);
- expect(StaffDebug.get_url(action)).toBe(expected_url);
-
- $('#' + fixture_id).remove();
+ expect(StaffDebug.get_url('rescore_problem')).toBe('/courses/edX/Open_DemoX/edx_demo_course/instructor/api/rescore_problem');
});
});
@@ -49,20 +44,63 @@ define(['backbone', 'jquery', 'js/staff_debug_actions'],
$('#' + escapableFixture_id).remove();
});
});
- describe('student_grade_adjustemnts', function () {
+ describe('reset', function () {
it('makes an ajax call with the expected parameters', function () {
$('body').append(fixture);
- spyOn(StaffDebug, 'goto_student_admin');
+ spyOn($, 'ajax');
+ StaffDebug.reset(locationName, location);
- StaffDebug.student_grade_adjustemnts(locationName, location);
+ expect($.ajax.mostRecentCall.args[0]['type']).toEqual('GET');
+ expect($.ajax.mostRecentCall.args[0]['data']).toEqual({
+ 'problem_to_reset': location,
+ 'unique_student_identifier': 'userman',
+ 'delete_module': false
+ });
+ expect($.ajax.mostRecentCall.args[0]['url']).toEqual(
+ '/instructor/api/reset_student_attempts'
+ );
+ $('#' + fixture_id).remove();
+ });
+ });
+ describe('sdelete', function () {
+ it('makes an ajax call with the expected parameters', function () {
+ $('body').append(fixture);
- var expected_url = get_url(action) + '#view-student_admin';
+ spyOn($, 'ajax');
+ StaffDebug.sdelete(locationName, location);
- expect(StaffDebug.goto_student_admin).toHaveBeenCalledWith(expected_url);
+ expect($.ajax.mostRecentCall.args[0]['type']).toEqual('GET');
+ expect($.ajax.mostRecentCall.args[0]['data']).toEqual({
+ 'problem_to_reset': location,
+ 'unique_student_identifier': 'userman',
+ 'delete_module': true
+ });
+ expect($.ajax.mostRecentCall.args[0]['url']).toEqual(
+ '/instructor/api/reset_student_attempts'
+ );
$('#' + fixture_id).remove();
});
});
+ describe('rescore', function () {
+ it('makes an ajax call with the expected parameters', function () {
+ $('body').append(fixture);
+
+ spyOn($, 'ajax');
+ StaffDebug.rescore(locationName, location);
+
+ expect($.ajax.mostRecentCall.args[0]['type']).toEqual('GET');
+ expect($.ajax.mostRecentCall.args[0]['data']).toEqual({
+ 'problem_to_reset': location,
+ 'unique_student_identifier': 'userman',
+ 'delete_module': false
+ });
+ expect($.ajax.mostRecentCall.args[0]['url']).toEqual(
+ '/instructor/api/rescore_problem'
+ );
+ $('#' + fixture_id).remove();
+ });
+ });
});
});
\ No newline at end of file
diff --git a/lms/static/js/staff_debug_actions.js b/lms/static/js/staff_debug_actions.js
index 0dab8cacec..35ce0a4048 100644
--- a/lms/static/js/staff_debug_actions.js
+++ b/lms/static/js/staff_debug_actions.js
@@ -3,15 +3,13 @@ var StaffDebug = (function(){
get_current_url = function() {
return window.location.pathname;
- };
+ }
get_url = function(action){
- var problem_to_reset = encodeURIComponent(action.location);
- var unique_student_identifier = get_user(action.locationName);
var pathname = this.get_current_url();
- var url = pathname.substr(0,pathname.indexOf('/courseware')) + '/instructor'+ '?unique_student_identifier=' + unique_student_identifier + '&problem_to_reset=' + problem_to_reset;
+ var url = pathname.substr(0,pathname.indexOf('/courseware')) + '/instructor/api/' + action;
return url;
- };
+ }
sanitized_string = function(string) {
return string.replace(/[.*+?^:${}()|[\]\\]/g, "\\$&");
@@ -24,21 +22,95 @@ var StaffDebug = (function(){
uname = $('#sd_fu_' + locname).attr('placeholder');
}
return uname;
- };
+ }
- goto_student_admin = function(location) {
- window.location = location;
- };
+ do_idash_action = function(action){
+ var pdata = {
+ 'problem_to_reset': action.location,
+ 'unique_student_identifier': get_user(action.locationName),
+ 'delete_module': action.delete_module
+ }
+ $.ajax({
+ type: "GET",
+ url: get_url(action.method),
+ data: pdata,
+ success: function(data){
+ var text = _.template(
+ action.success_msg,
+ {user: data.student},
+ {interpolate: /\{(.+?)\}/g}
+ )
+ var html = _.template(
+ '
{text}
',
+ {text: text},
+ {interpolate: /\{(.+?)\}/g}
+ )
+ $("#result_"+action.locationName).html(html);
+ },
+ error: function(request, status, error) {
+ var response_json;
+ try {
+ response_json = $.parseJSON(request.responseText);
+ } catch(e) {
+ response_json = { error: gettext('Unknown Error Occurred.') };
+ }
+ var text = _.template(
+ '{error_msg} {error}',
+ {
+ error_msg: action.error_msg,
+ error: response_json.error
+ },
+ {interpolate: /\{(.+?)\}/g}
+ )
+ var html = _.template(
+ '{text}
',
+ {text: text},
+ {interpolate: /\{(.+?)\}/g}
+ )
+ $("#result_"+action.locationName).html(html);
+ },
+ dataType: 'json'
+ });
+ }
- student_grade_adjustemnts = function(locname, location){
- var action = {locationName: locname, location: location};
- var instructor_tab_url = get_url(action);
- this.goto_student_admin(instructor_tab_url + '#view-student_admin');
- };
+ reset = function(locname, location){
+ this.do_idash_action({
+ locationName: locname,
+ location: location,
+ method: 'reset_student_attempts',
+ success_msg: gettext('Successfully reset the attempts for user {user}'),
+ error_msg: gettext('Failed to reset attempts.'),
+ delete_module: false
+ });
+ }
+
+ sdelete = function(locname, location){
+ this.do_idash_action({
+ locationName: locname,
+ location: location,
+ method: 'reset_student_attempts',
+ success_msg: gettext('Successfully deleted student state for user {user}'),
+ error_msg: gettext('Failed to delete student state.'),
+ delete_module: true
+ });
+ }
+
+ rescore = function(locname, location){
+ this.do_idash_action({
+ locationName: locname,
+ location: location,
+ method: 'rescore_problem',
+ success_msg: gettext('Successfully rescored problem for user {user}'),
+ error_msg: gettext('Failed to rescore problem.'),
+ delete_module: false
+ });
+ }
return {
- student_grade_adjustemnts: student_grade_adjustemnts,
- goto_student_admin: goto_student_admin,
+ reset: reset,
+ sdelete: sdelete,
+ rescore: rescore,
+ do_idash_action: do_idash_action,
get_current_url: get_current_url,
get_url: get_url,
get_user: get_user,
@@ -49,8 +121,16 @@ var StaffDebug = (function(){
// Register click handlers
$(document).ready(function() {
var $courseContent = $('.course-content');
- $courseContent.on("click", '.staff-debug-grade-adjustments', function() {
- StaffDebug.student_grade_adjustemnts($(this).parent().data('location-name'), $(this).parent().data('location'));
+ $courseContent.on("click", '.staff-debug-reset', function() {
+ StaffDebug.reset($(this).parent().data('location-name'), $(this).parent().data('location'));
+ return false;
+ });
+ $courseContent.on("click", '.staff-debug-sdelete', function() {
+ StaffDebug.sdelete($(this).parent().data('location-name'), $(this).parent().data('location'));
+ return false;
+ });
+ $courseContent.on("click", '.staff-debug-rescore', function() {
+ StaffDebug.rescore($(this).parent().data('location-name'), $(this).parent().data('location'));
return false;
});
});
diff --git a/lms/templates/instructor/instructor_dashboard_2/student_admin.html b/lms/templates/instructor/instructor_dashboard_2/student_admin.html
index afd0037792..a7d3b92279 100644
--- a/lms/templates/instructor/instructor_dashboard_2/student_admin.html
+++ b/lms/templates/instructor/instructor_dashboard_2/student_admin.html
@@ -39,22 +39,17 @@
diff --git a/lms/templates/sudo/sudo.html b/lms/templates/sudo/sudo.html
deleted file mode 100644
index 3dcfe1f0bf..0000000000
--- a/lms/templates/sudo/sudo.html
+++ /dev/null
@@ -1,21 +0,0 @@
-{% extends "main_django.html" %}
-{% load i18n %}
-
-{% block body %}
-
-
-
- {% trans "Confirm Your Password to Access the Instructor Dashboard" %}
-
-
-
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/lms/urls.py b/lms/urls.py
index 575389fe4a..adc0a090c6 100644
--- a/lms/urls.py
+++ b/lms/urls.py
@@ -1,11 +1,11 @@
from django.conf import settings
from django.conf.urls import patterns, include, url
+from ratelimitbackend import admin
from django.conf.urls.static import static
import django.contrib.auth.views
from microsite_configuration import microsite
import auth_exchange.views
-from edx_admin import admin
# Uncomment the next two lines to enable the admin:
if settings.DEBUG or settings.FEATURES.get('ENABLE_DJANGO_ADMIN_SITE'):
@@ -80,8 +80,6 @@ urlpatterns = (
# Course content API
url(r'^api/course_structure/', include('course_structure_api.urls', namespace='course_structure_api')),
- url(r'^sudo/$', 'sudo.views.sudo'),
-
# User API endpoints
url(r'^api/user/', include('openedx.core.djangoapps.user_api.urls')),
diff --git a/openedx/core/djangoapps/content/course_structures/admin.py b/openedx/core/djangoapps/content/course_structures/admin.py
index 759863c390..64bbdad86c 100644
--- a/openedx/core/djangoapps/content/course_structures/admin.py
+++ b/openedx/core/djangoapps/content/course_structures/admin.py
@@ -1,8 +1,4 @@
-"""
-django admin pages for course_structures model
-"""
-
-from django.contrib import admin
+from ratelimitbackend import admin
from .models import CourseStructure
diff --git a/openedx/core/djangoapps/credit/admin.py b/openedx/core/djangoapps/credit/admin.py
index b3c14f556b..5700f0ef73 100644
--- a/openedx/core/djangoapps/credit/admin.py
+++ b/openedx/core/djangoapps/credit/admin.py
@@ -1,12 +1,10 @@
"""
Django admin page for credit eligibility
"""
-
from ratelimitbackend import admin
from openedx.core.djangoapps.credit.models import (
CreditCourse, CreditProvider, CreditEligibility, CreditRequest
)
-from django.contrib import admin
class CreditCourseAdmin(admin.ModelAdmin):
diff --git a/requirements/edx/github.txt b/requirements/edx/github.txt
index 760f5ae3b5..b84022cd4f 100644
--- a/requirements/edx/github.txt
+++ b/requirements/edx/github.txt
@@ -12,7 +12,6 @@
-e git+https://github.com/edx/django-pipeline.git@88ec8a011e481918fdc9d2682d4017c835acd8be#egg=django-pipeline
-e git+https://github.com/edx/django-wiki.git@cd0b2b31997afccde519fe5b3365e61a9edb143f#egg=django-wiki
-e git+https://github.com/edx/django-oauth2-provider.git@0.2.7-fork-edx-5#egg=django-oauth2-provider
--e git+https://github.com/edx/django-sudo.git@5ceb91236b477ce2726c538a2d8631884bda2684#egg=django-sudo
-e git+https://github.com/edx/MongoDBProxy.git@25b99097615bda06bd7cdfe5669ed80dc2a7fed0#egg=mongodb_proxy
git+https://github.com/edx/nltk.git@2.0.6#egg=nltk==2.0.6
-e git+https://github.com/dementrock/pystache_custom.git@776973740bdaad83a3b029f96e415a7d1e8bec2f#egg=pystache_custom-dev