Commit 3278fcf1 by sanfordstudent Committed by GitHub

Merge pull request #15045 from edx/neem/handle_unrescorable

400 for non-rescorable blocks
parents 5314784a 8cfff9a8
...@@ -101,6 +101,11 @@ class InstructorDashboardPage(CoursePage): ...@@ -101,6 +101,11 @@ class InstructorDashboardPage(CoursePage):
ecommerce_section.wait_for_page() ecommerce_section.wait_for_page()
return ecommerce_section return ecommerce_section
def is_rescore_unsupported_message_visible(self):
return u'This component cannot be rescored.' in unicode(
self.q(css='.request-response-error').html
)
@staticmethod @staticmethod
def get_asset_path(file_name): def get_asset_path(file_name):
""" """
......
...@@ -15,14 +15,18 @@ from common.test.acceptance.pages.lms.auto_auth import AutoAuthPage ...@@ -15,14 +15,18 @@ from common.test.acceptance.pages.lms.auto_auth import AutoAuthPage
from common.test.acceptance.pages.studio.overview import CourseOutlinePage as StudioCourseOutlinePage from common.test.acceptance.pages.studio.overview import CourseOutlinePage as StudioCourseOutlinePage
from common.test.acceptance.pages.lms.create_mode import ModeCreationPage from common.test.acceptance.pages.lms.create_mode import ModeCreationPage
from common.test.acceptance.pages.lms.courseware import CoursewarePage from common.test.acceptance.pages.lms.courseware import CoursewarePage
from common.test.acceptance.pages.lms.instructor_dashboard import InstructorDashboardPage, EntranceExamAdmin from common.test.acceptance.pages.lms.instructor_dashboard import (
InstructorDashboardPage,
EntranceExamAdmin,
StudentSpecificAdmin,
)
from common.test.acceptance.fixtures.course import CourseFixture, XBlockFixtureDesc from common.test.acceptance.fixtures.course import CourseFixture, XBlockFixtureDesc
from common.test.acceptance.pages.lms.dashboard import DashboardPage from common.test.acceptance.pages.lms.dashboard import DashboardPage
from common.test.acceptance.pages.lms.problem import ProblemPage from common.test.acceptance.pages.lms.problem import ProblemPage
from common.test.acceptance.pages.lms.pay_and_verify import PaymentAndVerificationFlow from common.test.acceptance.pages.lms.pay_and_verify import PaymentAndVerificationFlow
from common.test.acceptance.pages.lms.login_and_register import CombinedLoginAndRegisterPage from common.test.acceptance.pages.lms.login_and_register import CombinedLoginAndRegisterPage
from common.test.acceptance.pages.common.utils import enroll_user_track from common.test.acceptance.pages.common.utils import enroll_user_track
from common.test.acceptance.tests.helpers import disable_animations from common.test.acceptance.tests.helpers import disable_animations, create_multiple_choice_problem
from common.test.acceptance.fixtures.certificates import CertificateConfigFixture from common.test.acceptance.fixtures.certificates import CertificateConfigFixture
...@@ -1337,3 +1341,50 @@ class EcommerceTest(BaseInstructorDashboardTest): ...@@ -1337,3 +1341,50 @@ class EcommerceTest(BaseInstructorDashboardTest):
# Log in and visit E-commerce section under Instructor dashboard # Log in and visit E-commerce section under Instructor dashboard
self.assertNotIn(u'Coupon Code List', self.visit_ecommerce_section().get_sections_header_values()) self.assertNotIn(u'Coupon Code List', self.visit_ecommerce_section().get_sections_header_values())
class StudentAdminTest(BaseInstructorDashboardTest):
SECTION_NAME = 'Test Section 1'
SUBSECTION_NAME = 'Test Subsection 1'
UNIT_NAME = 'Test Unit 1'
PROBLEM_NAME = 'Test Problem 1'
def setUp(self):
super(StudentAdminTest, self).setUp()
self.course_fix = CourseFixture(
self.course_info['org'],
self.course_info['number'],
self.course_info['run'],
self.course_info['display_name']
)
self.problem = create_multiple_choice_problem(self.PROBLEM_NAME)
self.vertical = XBlockFixtureDesc('vertical', "Lab Unit")
self.course_fix.add_children(
XBlockFixtureDesc('chapter', self.SECTION_NAME).add_children(
XBlockFixtureDesc('sequential', self.SUBSECTION_NAME).add_children(
self.vertical.add_children(self.problem)
)
),
).install()
self.username, _ = self.log_in_as_instructor()
self.instructor_dashboard_page = self.visit_instructor_dashboard()
def test_rescore_nonrescorable(self):
student_admin_section = self.instructor_dashboard_page.select_student_admin(StudentSpecificAdmin)
student_admin_section.set_student_email_or_username(self.username)
# not a rescorable block
student_admin_section.set_problem_location(self.vertical.locator)
getattr(student_admin_section, 'rescore_button').click()
self.assertTrue(self.instructor_dashboard_page.is_rescore_unsupported_message_visible())
def test_rescore_rescorable(self):
student_admin_section = self.instructor_dashboard_page.select_student_admin(StudentSpecificAdmin)
student_admin_section.set_student_email_or_username(self.username)
student_admin_section.set_problem_location(self.problem.locator)
getattr(student_admin_section, 'rescore_button').click()
alert = get_modal_alert(student_admin_section.browser)
alert.dismiss()
self.assertFalse(self.instructor_dashboard_page.is_rescore_unsupported_message_visible())
...@@ -2118,18 +2118,24 @@ def rescore_problem(request, course_id): ...@@ -2118,18 +2118,24 @@ def rescore_problem(request, course_id):
if student: if student:
response_payload['student'] = student_identifier response_payload['student'] = student_identifier
try:
lms.djangoapps.instructor_task.api.submit_rescore_problem_for_student( lms.djangoapps.instructor_task.api.submit_rescore_problem_for_student(
request, request,
module_state_key, module_state_key,
student, student,
only_if_higher, only_if_higher,
) )
except NotImplementedError as exc:
return HttpResponseBadRequest(exc.message)
elif all_students: elif all_students:
try:
lms.djangoapps.instructor_task.api.submit_rescore_problem_for_all_students( lms.djangoapps.instructor_task.api.submit_rescore_problem_for_all_students(
request, request,
module_state_key, module_state_key,
only_if_higher, only_if_higher,
) )
except NotImplementedError as exc:
return HttpResponseBadRequest(exc.message)
else: else:
return HttpResponseBadRequest() return HttpResponseBadRequest()
......
...@@ -255,10 +255,14 @@ def check_arguments_for_rescoring(usage_key): ...@@ -255,10 +255,14 @@ def check_arguments_for_rescoring(usage_key):
in). An ItemNotFoundException is raised if the corresponding module in). An ItemNotFoundException is raised if the corresponding module
descriptor doesn't exist. NotImplementedError is raised if the descriptor doesn't exist. NotImplementedError is raised if the
corresponding module doesn't support rescoring calls. corresponding module doesn't support rescoring calls.
Note: the string returned here is surfaced as the error
message on the instructor dashboard when a rescore is
submitted for a non-rescorable block.
""" """
descriptor = modulestore().get_item(usage_key) descriptor = modulestore().get_item(usage_key)
if not _supports_rescore(descriptor): if not _supports_rescore(descriptor):
msg = "Specified module does not support rescoring." msg = _("This component cannot be rescored.")
raise NotImplementedError(msg) raise NotImplementedError(msg)
......
...@@ -436,7 +436,7 @@ ...@@ -436,7 +436,7 @@
} }
StudentAdmin.prototype.rescore_problem_single = function(onlyIfHigher) { StudentAdmin.prototype.rescore_problem_single = function(onlyIfHigher) {
var errorMessage, fullErrorMessage, fullSuccessMessage, var defaultErrorMessage, fullDefaultErrorMessage, fullSuccessMessage,
problemToReset, sendData, successMessage, uniqStudentIdentifier, problemToReset, sendData, successMessage, uniqStudentIdentifier,
that = this; that = this;
uniqStudentIdentifier = this.$field_student_select_grade.val(); uniqStudentIdentifier = this.$field_student_select_grade.val();
...@@ -461,8 +461,8 @@ ...@@ -461,8 +461,8 @@
student_id: uniqStudentIdentifier, student_id: uniqStudentIdentifier,
problem_id: problemToReset problem_id: problemToReset
}); });
errorMessage = 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."); // eslint-disable-line max-len defaultErrorMessage = 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."); // eslint-disable-line max-len
fullErrorMessage = _.template(errorMessage)({ fullDefaultErrorMessage = _.template(defaultErrorMessage)({
student_id: uniqStudentIdentifier, student_id: uniqStudentIdentifier,
problem_id: problemToReset problem_id: problemToReset
}); });
...@@ -474,8 +474,11 @@ ...@@ -474,8 +474,11 @@
success: this.clear_errors_then(function() { success: this.clear_errors_then(function() {
return alert(fullSuccessMessage); // eslint-disable-line no-alert return alert(fullSuccessMessage); // eslint-disable-line no-alert
}), }),
error: statusAjaxError(function() { error: statusAjaxError(function(response) {
return that.$request_err_grade.text(fullErrorMessage); if (response.responseText) {
return that.$request_err_grade.text(response.responseText);
}
return that.$request_err_grade.text(fullDefaultErrorMessage);
}) })
}); });
}; };
...@@ -518,8 +521,9 @@ ...@@ -518,8 +521,9 @@
}; };
StudentAdmin.prototype.rescore_problem_all = function(onlyIfHigher) { StudentAdmin.prototype.rescore_problem_all = function(onlyIfHigher) {
var confirmMessage, errorMessage, fullConfirmMessage, var confirmMessage, defaultErrorMessage, fullConfirmMessage,
fullErrorMessage, fullSuccessMessage, problemToReset, sendData, successMessage, fullDefaultErrorMessage, fullSuccessMessage, problemToReset,
sendData, successMessage,
that = this; that = this;
problemToReset = this.$field_problem_select_all.val(); problemToReset = this.$field_problem_select_all.val();
if (!problemToReset) { if (!problemToReset) {
...@@ -541,8 +545,8 @@ ...@@ -541,8 +545,8 @@
fullSuccessMessage = _.template(successMessage)({ fullSuccessMessage = _.template(successMessage)({
problem_id: problemToReset problem_id: problemToReset
}); });
errorMessage = gettext("Error starting a task to rescore problem '<%- problem_id %>'. Make sure that the problem identifier is complete and correct."); // eslint-disable-line max-len defaultErrorMessage = gettext("Error starting a task to rescore problem '<%- problem_id %>'. Make sure that the problem identifier is complete and correct."); // eslint-disable-line max-len
fullErrorMessage = _.template(errorMessage)({ fullDefaultErrorMessage = _.template(defaultErrorMessage)({
problem_id: problemToReset problem_id: problemToReset
}); });
return $.ajax({ return $.ajax({
...@@ -553,8 +557,11 @@ ...@@ -553,8 +557,11 @@
success: this.clear_errors_then(function() { success: this.clear_errors_then(function() {
return alert(fullSuccessMessage); // eslint-disable-line no-alert return alert(fullSuccessMessage); // eslint-disable-line no-alert
}), }),
error: statusAjaxError(function() { error: statusAjaxError(function(response) {
return that.$request_response_error_all.text(fullErrorMessage); if (response.responseText) {
return that.$request_response_error_all.text(response.responseText);
}
return that.$request_response_error_all.text(fullDefaultErrorMessage);
}) })
}); });
} else { } else {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment