MDL-60882 mod_choice: Avoid teacher delete all responses

Teachers should be able to delete all responses but when indicating the
response ids.
When the response ids are not passed, only their own responses should
be deleted (as the function documentation said).
This commit is contained in:
Juan Leyva 2018-01-11 14:31:29 +01:00
parent 6fa694bef0
commit 10b67ef9f1
2 changed files with 58 additions and 23 deletions

View File

@ -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;

View File

@ -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);