mirror of
https://github.com/moodle/moodle.git
synced 2025-01-19 06:18:28 +01:00
MDL-52767 mod_quiz: New Web Service get_attempt_access_information
This commit is contained in:
parent
a79a63619b
commit
ff99efcd96
@ -1701,4 +1701,111 @@ class mod_quiz_external extends external_api {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the parameters for get_attempt_access_information.
|
||||||
|
*
|
||||||
|
* @return external_external_function_parameters
|
||||||
|
* @since Moodle 3.1
|
||||||
|
*/
|
||||||
|
public static function get_attempt_access_information_parameters() {
|
||||||
|
return new external_function_parameters (
|
||||||
|
array(
|
||||||
|
'quizid' => new external_value(PARAM_INT, 'quiz instance id'),
|
||||||
|
'attemptid' => new external_value(PARAM_INT, 'attempt id, 0 for the user last attempt if exists', VALUE_DEFAULT, 0),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return access information for a given attempt in a quiz.
|
||||||
|
*
|
||||||
|
* @param int $quizid quiz instance id
|
||||||
|
* @param int $attemptid attempt id, 0 for the user last attempt if exists
|
||||||
|
* @return array of warnings and the access information
|
||||||
|
* @since Moodle 3.1
|
||||||
|
* @throws moodle_quiz_exception
|
||||||
|
*/
|
||||||
|
public static function get_attempt_access_information($quizid, $attemptid = 0) {
|
||||||
|
global $DB, $USER;
|
||||||
|
|
||||||
|
$warnings = array();
|
||||||
|
|
||||||
|
$params = array(
|
||||||
|
'quizid' => $quizid,
|
||||||
|
'attemptid' => $attemptid,
|
||||||
|
);
|
||||||
|
$params = self::validate_parameters(self::get_attempt_access_information_parameters(), $params);
|
||||||
|
|
||||||
|
list($quiz, $course, $cm, $context) = self::validate_quiz($params['quizid']);
|
||||||
|
|
||||||
|
$attempttocheck = 0;
|
||||||
|
if (!empty($params['attemptid'])) {
|
||||||
|
$attemptobj = quiz_attempt::create($params['attemptid']);
|
||||||
|
if ($attemptobj->get_userid() != $USER->id) {
|
||||||
|
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'notyourattempt');
|
||||||
|
}
|
||||||
|
$attempttocheck = $attemptobj->get_attempt();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Access manager now.
|
||||||
|
$quizobj = quiz::create($cm->instance, $USER->id);
|
||||||
|
$ignoretimelimits = has_capability('mod/quiz:ignoretimelimits', $context, null, false);
|
||||||
|
$timenow = time();
|
||||||
|
$accessmanager = new quiz_access_manager($quizobj, $timenow, $ignoretimelimits);
|
||||||
|
|
||||||
|
$attempts = quiz_get_user_attempts($quiz->id, $USER->id, 'finished', true);
|
||||||
|
$lastfinishedattempt = end($attempts);
|
||||||
|
if ($unfinishedattempt = quiz_get_user_attempt_unfinished($quiz->id, $USER->id)) {
|
||||||
|
$attempts[] = $unfinishedattempt;
|
||||||
|
|
||||||
|
// Check if the attempt is now overdue. In that case the state will change.
|
||||||
|
$quizobj->create_attempt_object($unfinishedattempt)->handle_if_time_expired(time(), false);
|
||||||
|
|
||||||
|
if ($unfinishedattempt->state != quiz_attempt::IN_PROGRESS and $unfinishedattempt->state != quiz_attempt::OVERDUE) {
|
||||||
|
$lastfinishedattempt = $unfinishedattempt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$numattempts = count($attempts);
|
||||||
|
|
||||||
|
if (!$attempttocheck) {
|
||||||
|
$attempttocheck = $unfinishedattempt ? $unfinishedattempt : $lastfinishedattempt;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
$result['isfinished'] = $accessmanager->is_finished($numattempts, $lastfinishedattempt);
|
||||||
|
$result['preventnewattemptreasons'] = $accessmanager->prevent_new_attempt($numattempts, $lastfinishedattempt);
|
||||||
|
|
||||||
|
if ($attempttocheck) {
|
||||||
|
$endtime = $accessmanager->get_end_time($attempttocheck);
|
||||||
|
$result['endtime'] = ($endtime === false) ? 0 : $endtime;
|
||||||
|
$attemptid = $unfinishedattempt ? $unfinishedattempt->id : null;
|
||||||
|
$result['ispreflightcheckrequired'] = $accessmanager->is_preflight_check_required($attemptid);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result['warnings'] = $warnings;
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the get_attempt_access_information return value.
|
||||||
|
*
|
||||||
|
* @return external_single_structure
|
||||||
|
* @since Moodle 3.1
|
||||||
|
*/
|
||||||
|
public static function get_attempt_access_information_returns() {
|
||||||
|
return new external_single_structure(
|
||||||
|
array(
|
||||||
|
'endtime' => new external_value(PARAM_INT, 'When the attempt must be submitted (determined by rules).',
|
||||||
|
VALUE_OPTIONAL),
|
||||||
|
'isfinished' => new external_value(PARAM_BOOL, 'Whether there is no way the user will ever be allowed to attempt.'),
|
||||||
|
'ispreflightcheckrequired' => new external_value(PARAM_BOOL, 'whether a check is required before the user
|
||||||
|
starts/continues his attempt.', VALUE_OPTIONAL),
|
||||||
|
'preventnewattemptreasons' => new external_multiple_structure(
|
||||||
|
new external_value(PARAM_TEXT, 'access restriction description'),
|
||||||
|
'list of reasons'),
|
||||||
|
'warnings' => new external_warnings(),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -173,4 +173,13 @@ $functions = array(
|
|||||||
'capabilities' => 'mod/quiz:view',
|
'capabilities' => 'mod/quiz:view',
|
||||||
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
|
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
|
||||||
),
|
),
|
||||||
|
|
||||||
|
'mod_quiz_get_attempt_access_information' => array(
|
||||||
|
'classname' => 'mod_quiz_external',
|
||||||
|
'methodname' => 'get_attempt_access_information',
|
||||||
|
'description' => 'Return access information for a given attempt in a quiz.',
|
||||||
|
'type' => 'read',
|
||||||
|
'capabilities' => 'mod/quiz:view',
|
||||||
|
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
@ -1461,4 +1461,89 @@ class mod_quiz_external_testcase extends externallib_advanced_testcase {
|
|||||||
$this->assertCount(1, $result['preventaccessreasons']);
|
$this->assertCount(1, $result['preventaccessreasons']);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test get_attempt_access_information
|
||||||
|
*/
|
||||||
|
public function test_get_attempt_access_information() {
|
||||||
|
global $DB;
|
||||||
|
|
||||||
|
// Create a new quiz with attempts.
|
||||||
|
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
|
||||||
|
$data = array('course' => $this->course->id,
|
||||||
|
'sumgrades' => 2);
|
||||||
|
$quiz = $quizgenerator->create_instance($data);
|
||||||
|
|
||||||
|
// Create some questions.
|
||||||
|
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||||
|
|
||||||
|
$cat = $questiongenerator->create_question_category();
|
||||||
|
$question = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
|
||||||
|
quiz_add_quiz_question($question->id, $quiz);
|
||||||
|
|
||||||
|
$question = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
|
||||||
|
quiz_add_quiz_question($question->id, $quiz);
|
||||||
|
|
||||||
|
// Add new question types in the category (for the random one).
|
||||||
|
$question = $questiongenerator->create_question('truefalse', null, array('category' => $cat->id));
|
||||||
|
$question = $questiongenerator->create_question('essay', null, array('category' => $cat->id));
|
||||||
|
|
||||||
|
$question = $questiongenerator->create_question('random', null, array('category' => $cat->id));
|
||||||
|
quiz_add_quiz_question($question->id, $quiz);
|
||||||
|
|
||||||
|
$quizobj = quiz::create($quiz->id, $this->student->id);
|
||||||
|
|
||||||
|
// Set grade to pass.
|
||||||
|
$item = grade_item::fetch(array('courseid' => $this->course->id, 'itemtype' => 'mod',
|
||||||
|
'itemmodule' => 'quiz', 'iteminstance' => $quiz->id, 'outcomeid' => null));
|
||||||
|
$item->gradepass = 80;
|
||||||
|
$item->update();
|
||||||
|
|
||||||
|
$this->setUser($this->student);
|
||||||
|
|
||||||
|
// Default restrictions (none).
|
||||||
|
$result = mod_quiz_external::get_attempt_access_information($quiz->id);
|
||||||
|
$result = external_api::clean_returnvalue(mod_quiz_external::get_attempt_access_information_returns(), $result);
|
||||||
|
|
||||||
|
$expected = array(
|
||||||
|
'isfinished' => false,
|
||||||
|
'preventnewattemptreasons' => [],
|
||||||
|
'warnings' => []
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $result);
|
||||||
|
|
||||||
|
// Limited attempts.
|
||||||
|
$quiz->attempts = 1;
|
||||||
|
$DB->update_record('quiz', $quiz);
|
||||||
|
|
||||||
|
// Now, do one attempt.
|
||||||
|
$quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
|
||||||
|
$quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
|
||||||
|
|
||||||
|
$timenow = time();
|
||||||
|
$attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $this->student->id);
|
||||||
|
quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
|
||||||
|
quiz_attempt_save_started($quizobj, $quba, $attempt);
|
||||||
|
|
||||||
|
// Process some responses from the student.
|
||||||
|
$attemptobj = quiz_attempt::create($attempt->id);
|
||||||
|
$tosubmit = array(1 => array('answer' => '3.14'));
|
||||||
|
$attemptobj->process_submitted_actions($timenow, false, $tosubmit);
|
||||||
|
|
||||||
|
// Finish the attempt.
|
||||||
|
$attemptobj = quiz_attempt::create($attempt->id);
|
||||||
|
$this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
|
||||||
|
$attemptobj->process_finish($timenow, false);
|
||||||
|
|
||||||
|
// Can we start a new attempt? We shall not!
|
||||||
|
$result = mod_quiz_external::get_attempt_access_information($quiz->id, $attempt->id);
|
||||||
|
$result = external_api::clean_returnvalue(mod_quiz_external::get_attempt_access_information_returns(), $result);
|
||||||
|
|
||||||
|
// Now new attemps allowed.
|
||||||
|
$this->assertCount(1, $result['preventnewattemptreasons']);
|
||||||
|
$this->assertFalse($result['ispreflightcheckrequired']);
|
||||||
|
$this->assertEquals(get_string('nomoreattempts', 'quiz'), $result['preventnewattemptreasons'][0]);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user