Commit 25e67370 by Eric Fischer

Unbound xblock method requires user id

clear_student_state(), a method defined by ORA, requires information
about the user making the request. Since this xblock is not bound,
we must provide that information explicitly.
parent a647169a
......@@ -202,7 +202,7 @@ def send_beta_role_email(action, user, email_params):
send_mail_to_student(user.email, email_params, language=get_user_email_language(user))
def reset_student_attempts(course_id, student, module_state_key, delete_module=False):
def reset_student_attempts(course_id, student, module_state_key, requesting_user, delete_module=False):
"""
Reset student attempts for a problem. Optionally deletes all student state for the specified problem.
......@@ -219,26 +219,42 @@ def reset_student_attempts(course_id, student, module_state_key, delete_module=F
submissions.SubmissionError: unexpected error occurred while resetting the score in the submissions API.
"""
user_id = anonymous_id_for_user(student, course_id)
requesting_user_id = anonymous_id_for_user(requesting_user, course_id)
submission_cleared = False
try:
# A block may have children. Clear state on children first.
block = modulestore().get_item(module_state_key)
if block.has_children:
for child in block.children:
try:
reset_student_attempts(course_id, student, child, delete_module=delete_module)
reset_student_attempts(course_id, student, child, requesting_user, delete_module=delete_module)
except StudentModule.DoesNotExist:
# If a particular child doesn't have any state, no big deal, as long as the parent does.
pass
if delete_module:
# Some blocks (openassessment) use StudentModule data as a key for internal submission data.
# Inform these blocks of the reset and allow them to handle their data.
clear_student_state = getattr(block, "clear_student_state", None)
if callable(clear_student_state):
clear_student_state(
user_id=user_id,
course_id=unicode(course_id),
item_id=unicode(module_state_key),
requesting_user_id=requesting_user_id
)
submission_cleared = True
except ItemNotFoundError:
log.warning("Could not find %s in modulestore when attempting to reset attempts.", module_state_key)
# Reset the student's score in the submissions API
# Currently this is used only by open assessment (ORA 2)
# We need to do this *before* retrieving the `StudentModule` model,
# because it's possible for a score to exist even if no student module exists.
if delete_module:
# Reset the student's score in the submissions API, if xblock.clear_student_state has not done so already.
# We need to do this before retrieving the `StudentModule` model, because a score may exist with no student module.
# TODO: Should the LMS know about sub_api and call this reset, or should it generically call it on all of its
# xblock services as well? See JIRA ARCH-26.
if delete_module and not submission_cleared:
sub_api.reset_score(
anonymous_id_for_user(student, course_id),
user_id,
course_id.to_deprecated_string(),
module_state_key.to_deprecated_string(),
)
......
......@@ -27,9 +27,9 @@ class InstructorService(object):
and attempt counts if there had been an earlier attempt.
"""
def delete_student_attempt(self, student_identifier, course_id, content_id):
def delete_student_attempt(self, student_identifier, course_id, content_id, requesting_user):
"""
Deletes student state for a problem.
Deletes student state for a problem. requesting_user may be kept as an audit trail.
Takes some of the following query parameters
- student_identifier is an email or username
......@@ -63,7 +63,13 @@ class InstructorService(object):
if student:
try:
enrollment.reset_student_attempts(course_id, student, module_state_key, delete_module=True)
enrollment.reset_student_attempts(
course_id,
student,
module_state_key,
requesting_user=requesting_user,
delete_module=True,
)
except (StudentModule.DoesNotExist, enrollment.sub_api.SubmissionError):
err_msg = (
'Error occurred while attempting to reset student attempts for user '
......
......@@ -371,7 +371,7 @@ class TestInstructorEnrollmentStudentModule(SharedModuleStoreTestCase):
# lambda to reload the module state from the database
module = lambda: StudentModule.objects.get(student=self.user, course_id=self.course_key, module_state_key=msk)
self.assertEqual(json.loads(module().state)['attempts'], 32)
reset_student_attempts(self.course_key, self.user, msk)
reset_student_attempts(self.course_key, self.user, msk, requesting_user=self.user)
self.assertEqual(json.loads(module().state)['attempts'], 0)
def test_delete_student_attempts(self):
......@@ -389,7 +389,7 @@ class TestInstructorEnrollmentStudentModule(SharedModuleStoreTestCase):
course_id=self.course_key,
module_state_key=msk
).count(), 1)
reset_student_attempts(self.course_key, self.user, msk, delete_module=True)
reset_student_attempts(self.course_key, self.user, msk, requesting_user=self.user, delete_module=True)
self.assertEqual(
StudentModule.objects.filter(
student=self.user,
......@@ -425,7 +425,8 @@ class TestInstructorEnrollmentStudentModule(SharedModuleStoreTestCase):
# Delete student state using the instructor dash
reset_student_attempts(
self.course_key, user, problem_location,
delete_module=True
requesting_user=user,
delete_module=True,
)
# Verify that the student's scores have been reset in the submissions API
......@@ -451,7 +452,7 @@ class TestInstructorEnrollmentStudentModule(SharedModuleStoreTestCase):
self.assertEqual(unrelated_state['attempts'], 12)
self.assertEqual(unrelated_state['brains'], 'zombie')
reset_student_attempts(self.course_key, self.user, self.parent.location)
reset_student_attempts(self.course_key, self.user, self.parent.location, requesting_user=self.user)
parent_state = json.loads(self.get_state(self.parent.location))
self.assertEqual(json.loads(self.get_state(self.parent.location))['attempts'], 0)
......@@ -478,7 +479,13 @@ class TestInstructorEnrollmentStudentModule(SharedModuleStoreTestCase):
self.assertEqual(unrelated_state['attempts'], 12)
self.assertEqual(unrelated_state['brains'], 'zombie')
reset_student_attempts(self.course_key, self.user, self.parent.location, delete_module=True)
reset_student_attempts(
self.course_key,
self.user,
self.parent.location,
requesting_user=self.user,
delete_module=True,
)
self.assertRaises(StudentModule.DoesNotExist, self.get_state, self.parent.location)
self.assertRaises(StudentModule.DoesNotExist, self.get_state, self.child.location)
......
......@@ -67,7 +67,8 @@ class InstructorServiceTests(SharedModuleStoreTestCase):
self.service.delete_student_attempt(
self.student.username,
unicode(self.course.id),
self.problem_urlname
self.problem_urlname,
requesting_user=self.student,
)
# make sure the module has been deleted
......@@ -88,7 +89,8 @@ class InstructorServiceTests(SharedModuleStoreTestCase):
result = self.service.delete_student_attempt(
self.student.username,
unicode(self.course.id),
'foo/bar/baz'
'foo/bar/baz',
requesting_user=self.student,
)
self.assertIsNone(result)
......@@ -100,7 +102,8 @@ class InstructorServiceTests(SharedModuleStoreTestCase):
result = self.service.delete_student_attempt(
'bad_student',
unicode(self.course.id),
'foo/bar/baz'
'foo/bar/baz',
requesting_user=self.student,
)
self.assertIsNone(result)
......@@ -112,7 +115,8 @@ class InstructorServiceTests(SharedModuleStoreTestCase):
result = self.service.delete_student_attempt(
self.student.username,
unicode(self.course.id),
self.other_problem_urlname
self.other_problem_urlname,
requesting_user=self.student,
)
self.assertIsNone(result)
......
......@@ -1980,7 +1980,13 @@ def reset_student_attempts(request, course_id):
if student:
try:
enrollment.reset_student_attempts(course_id, student, module_state_key, delete_module=delete_module)
enrollment.reset_student_attempts(
course_id,
student,
module_state_key,
requesting_user=request.user,
delete_module=delete_module
)
except StudentModule.DoesNotExist:
return HttpResponseBadRequest(_("Module does not exist."))
except sub_api.SubmissionError:
......
......@@ -90,7 +90,7 @@ git+https://github.com/edx/xblock-utils.git@v1.0.2#egg=xblock-utils==1.0.2
-e git+https://github.com/edx-solutions/xblock-google-drive.git@138e6fa0bf3a2013e904a085b9fed77dab7f3f21#egg=xblock-google-drive
-e git+https://github.com/edx/edx-reverification-block.git@0.0.5#egg=edx-reverification-block==0.0.5
git+https://github.com/edx/edx-user-state-client.git@1.0.1#egg=edx-user-state-client==1.0.1
git+https://github.com/edx/edx-proctoring.git@0.12.13#egg=edx-proctoring==0.12.13
git+https://github.com/edx/edx-proctoring.git@0.12.14#egg=edx-proctoring==0.12.14
git+https://github.com/edx/xblock-lti-consumer.git@v1.0.3#egg=xblock-lti-consumer==1.0.3
# Third Party XBlocks
......
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