diff --git a/mod/choice/classes/external.php b/mod/choice/classes/external.php index 06d30ebbf81..8fc4e4cdde0 100644 --- a/mod/choice/classes/external.php +++ b/mod/choice/classes/external.php @@ -596,7 +596,7 @@ class mod_choice_external extends external_api { 'choiceid' => new external_value(PARAM_INT, 'choice instance id'), 'responses' => new external_multiple_structure( new external_value(PARAM_INT, 'response id'), - 'Array of response ids, empty for deleting all the user responses', + 'Array of response ids, empty for deleting all the current user responses.', VALUE_DEFAULT, array() ), @@ -608,7 +608,7 @@ class mod_choice_external extends external_api { * Delete the given submitted responses in a choice * * @param int $choiceid the choice instance id - * @param array $responses the response ids, empty for deleting all the user responses + * @param array $responses the response ids, empty for deleting all the current user responses * @return array status information and warnings * @throws moodle_exception * @since Moodle 3.0 @@ -633,33 +633,38 @@ class mod_choice_external extends external_api { require_capability('mod/choice:choose', $context); - // If we have the capability, delete all the passed responses. - if (has_capability('mod/choice:deleteresponses', $context)) { - if (empty($params['responses'])) { - // Get all the responses for the choice. - $params['responses'] = array_keys(choice_get_all_responses($choice)); + $candeleteall = has_capability('mod/choice:deleteresponses', $context); + if ($candeleteall || $choice->allowupdate) { + + // Check if we can delete our own responses. + if (!$candeleteall) { + $timenow = time(); + if (!empty($choice->timeclose) && ($timenow > $choice->timeclose)) { + throw new moodle_exception("expired", "choice", '', userdate($choice->timeclose)); + } } - $status = choice_delete_responses($params['responses'], $choice, $cm, $course); - } else if ($choice->allowupdate) { - // Check if we can delate our own responses. - $timenow = time(); - if (!empty($choice->timeclose) && ($timenow > $choice->timeclose)) { - throw new moodle_exception("expired", "choice", '', userdate($choice->timeclose)); - } - // Delete only our responses. - $myresponses = array_keys(choice_get_my_response($choice)); if (empty($params['responses'])) { - $todelete = $myresponses; + // No responses indicated so delete only my responses. + $todelete = array_keys(choice_get_my_response($choice)); } else { + // Fill an array with the responses that can be deleted for this choice. + if ($candeleteall) { + // Teacher/managers can delete any. + $allowedresponses = array_keys(choice_get_all_responses($choice)); + } else { + // Students can delete only their own responses. + $allowedresponses = array_keys(choice_get_my_response($choice)); + } + $todelete = array(); foreach ($params['responses'] as $response) { - if (!in_array($response, $myresponses)) { + if (!in_array($response, $allowedresponses)) { $warnings[] = array( 'item' => 'response', 'itemid' => $response, 'warningcode' => 'nopermissions', - 'message' => 'No permission to delete this response' + 'message' => 'Invalid response id, the response does not exist or you are not allowed to delete it.' ); } else { $todelete[] = $response; diff --git a/mod/choice/tests/externallib_test.php b/mod/choice/tests/externallib_test.php index 4902a563ebd..2919495e87f 100644 --- a/mod/choice/tests/externallib_test.php +++ b/mod/choice/tests/externallib_test.php @@ -502,6 +502,7 @@ class mod_choice_externallib_testcase extends externallib_advanced_testcase { $this->assertCount(0, choice_get_my_response($choice)); // Now, as an admin we must be able to delete all the responses under any condition. + $this->setUser($student); // Submit again the responses. $results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2])); $results = external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results); @@ -518,19 +519,48 @@ class mod_choice_externallib_testcase extends externallib_advanced_testcase { $this->assertCount(0, $results['warnings']); // Submit again the responses. + $this->setUser($student); $DB->set_field('choice', 'timeclose', 0, array('id' => $choice->id)); $results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2])); $results = external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results); - // With other user account too, so we can test all the responses are deleted. - choice_user_submit_response( array($options[1], $options[2]), $choice, $student->id, $course, $cm); - // Test deleting all (not passing the answers ids), event not only mine. + // Test admin try to delete his own responses (he didn't respond so nothing should be deleted). + $this->setAdminUser(); $results = mod_choice_external::delete_choice_responses($choice->id); $results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results); + $this->assertFalse($results['status']); + $this->assertCount(0, $results['warnings']); + $allresponses = choice_get_all_responses($choice); + $this->assertCount(2, $allresponses); // No responses deleted (admin didn't submit any). + + // Now admin submit a couple of responses more. + $results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2])); + $results = external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results); + $allresponses = choice_get_all_responses($choice); + $this->assertCount(4, $allresponses); + // Admin responses are deleted when passing an empty array. + $results = mod_choice_external::delete_choice_responses($choice->id); + $results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results); + $this->assertTrue($results['status']); + $this->assertCount(0, $results['warnings']); + $allresponses = choice_get_all_responses($choice); + $this->assertCount(2, $allresponses); + + // Now admin will delete all the other users responses. + $results = mod_choice_external::delete_choice_responses($choice->id, array_keys($allresponses)); + $results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results); $this->assertTrue($results['status']); $this->assertCount(0, $results['warnings']); - $this->assertCount(0, choice_get_all_responses($choice)); + $allresponses = choice_get_all_responses($choice); + $this->assertCount(0, $allresponses); // Now all the responses were deleted. + + // Admin try do delete an invalid response. + $results = mod_choice_external::delete_choice_responses($choice->id, array(-1)); + $results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results); + + $this->assertFalse($results['status']); + $this->assertCount(1, $results['warnings']); // Now, in the DB 0 responses. $this->setUser($student);