MDL-52888 mod_quiz: New Web Service mod_quiz_view_attempt
This commit is contained in:
+4
-19
@@ -95,18 +95,7 @@ if ($autosaveperiod) {
|
||||
}
|
||||
|
||||
// Log this page view.
|
||||
$params = array(
|
||||
'objectid' => $attemptid,
|
||||
'relateduserid' => $attemptobj->get_userid(),
|
||||
'courseid' => $attemptobj->get_courseid(),
|
||||
'context' => context_module::instance($attemptobj->get_cmid()),
|
||||
'other' => array(
|
||||
'quizid' => $attemptobj->get_quizid()
|
||||
)
|
||||
);
|
||||
$event = \mod_quiz\event\attempt_viewed::create($params);
|
||||
$event->add_record_snapshot('quiz_attempts', $attemptobj->get_attempt());
|
||||
$event->trigger();
|
||||
$attemptobj->fire_attempt_viewed_event();
|
||||
|
||||
// Get the list of questions needed by this page.
|
||||
$slots = $attemptobj->get_slots($page);
|
||||
@@ -116,13 +105,9 @@ if (empty($slots)) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'noquestionsfound');
|
||||
}
|
||||
|
||||
// Update attempt page.
|
||||
if ($attemptobj->get_currentpage() != $page) {
|
||||
if ($attemptobj->get_navigation_method() == QUIZ_NAVMETHOD_SEQ && $attemptobj->get_currentpage() > $page) {
|
||||
// Prevent out of sequence access.
|
||||
redirect($attemptobj->start_attempt_url(null, $attemptobj->get_currentpage()));
|
||||
}
|
||||
$DB->set_field('quiz_attempts', 'currentpage', $page, array('id' => $attemptid));
|
||||
// Update attempt page, redirecting the user if $page is not valid.
|
||||
if (!$attemptobj->set_currentpage($page)) {
|
||||
redirect($attemptobj->start_attempt_url(null, $attemptobj->get_currentpage()));
|
||||
}
|
||||
|
||||
// Initialise the JavaScript.
|
||||
|
||||
@@ -2170,6 +2170,61 @@ class quiz_attempt {
|
||||
return $becomingabandoned ? self::ABANDONED : self::FINISHED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a page access to see if is an out of sequence access.
|
||||
*
|
||||
* @param int $page page number
|
||||
* @return boolean false is is an out of sequence access, true otherwise.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
public function check_page_access($page) {
|
||||
global $DB;
|
||||
|
||||
if ($this->get_currentpage() != $page) {
|
||||
if ($this->get_navigation_method() == QUIZ_NAVMETHOD_SEQ && $this->get_currentpage() > $page) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update attempt page.
|
||||
*
|
||||
* @param int $page page number
|
||||
* @return boolean true if everything was ok, false otherwise (out of sequence access).
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
public function set_currentpage($page) {
|
||||
global $DB;
|
||||
|
||||
if ($this->check_page_access($page)) {
|
||||
$DB->set_field('quiz_attempts', 'currentpage', $page, array('id' => $this->get_attemptid()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger the attempt_viewed event.
|
||||
*
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
public function fire_attempt_viewed_event() {
|
||||
$params = array(
|
||||
'objectid' => $this->get_attemptid(),
|
||||
'relateduserid' => $this->get_userid(),
|
||||
'courseid' => $this->get_courseid(),
|
||||
'context' => context_module::instance($this->get_cmid()),
|
||||
'other' => array(
|
||||
'quizid' => $this->get_quizid()
|
||||
)
|
||||
);
|
||||
$event = \mod_quiz\event\attempt_viewed::create($params);
|
||||
$event->add_record_snapshot('quiz_attempts', $this->get_attempt());
|
||||
$event->trigger();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -845,12 +845,8 @@ class mod_quiz_external extends external_api {
|
||||
}
|
||||
|
||||
// Prevent out of sequence access.
|
||||
if ($attemptobj->get_currentpage() != $params['page']) {
|
||||
if ($attemptobj->get_navigation_method() == QUIZ_NAVMETHOD_SEQ &&
|
||||
$attemptobj->get_currentpage() > $params['page']) {
|
||||
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'Out of sequence access');
|
||||
}
|
||||
if (!$attemptobj->check_page_access($params['page'])) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'Out of sequence access');
|
||||
}
|
||||
|
||||
// Check slots.
|
||||
@@ -1386,4 +1382,67 @@ class mod_quiz_external extends external_api {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the parameters for view_attempt.
|
||||
*
|
||||
* @return external_external_function_parameters
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
public static function view_attempt_parameters() {
|
||||
return new external_function_parameters (
|
||||
array(
|
||||
'attemptid' => new external_value(PARAM_INT, 'attempt id'),
|
||||
'page' => new external_value(PARAM_INT, 'page number'),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger the attempt viewed event.
|
||||
*
|
||||
* @param int $attemptid attempt id
|
||||
* @param int $page page number
|
||||
* @return array of warnings and status result
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
public static function view_attempt($attemptid, $page) {
|
||||
|
||||
$warnings = array();
|
||||
|
||||
$params = array(
|
||||
'attemptid' => $attemptid,
|
||||
'page' => $page,
|
||||
);
|
||||
$params = self::validate_parameters(self::view_attempt_parameters(), $params);
|
||||
list($attemptobj, $messages) = self::validate_attempt($params);
|
||||
|
||||
// Log action.
|
||||
$attemptobj->fire_attempt_viewed_event();
|
||||
|
||||
// Update attempt page, throwing an exception if $page is not valid.
|
||||
if (!$attemptobj->set_currentpage($params['page'])) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'Out of sequence access');
|
||||
}
|
||||
|
||||
$result = array();
|
||||
$result['status'] = true;
|
||||
$result['warnings'] = $warnings;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the view_attempt return value.
|
||||
*
|
||||
* @return external_single_structure
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
public static function view_attempt_returns() {
|
||||
return new external_single_structure(
|
||||
array(
|
||||
'status' => new external_value(PARAM_BOOL, 'status: true if success'),
|
||||
'warnings' => new external_warnings(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -128,4 +128,13 @@ $functions = array(
|
||||
'capabilities' => 'mod/quiz:reviewmyattempts',
|
||||
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
|
||||
),
|
||||
|
||||
'mod_quiz_view_attempt' => array(
|
||||
'classname' => 'mod_quiz_external',
|
||||
'methodname' => 'view_attempt',
|
||||
'description' => 'Trigger the attempt viewed event.',
|
||||
'type' => 'write',
|
||||
'capabilities' => 'mod/quiz:attempt',
|
||||
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1247,4 +1247,53 @@ class mod_quiz_external_testcase extends externallib_advanced_testcase {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test test_view_attempt
|
||||
*/
|
||||
public function test_view_attempt() {
|
||||
global $DB;
|
||||
|
||||
// Create a new quiz with two questions and one attempt started.
|
||||
list($quiz, $context, $quizobj, $attempt, $attemptobj, $quba) = $this->create_quiz_with_questions(true, false);
|
||||
|
||||
// Test user with full capabilities.
|
||||
$this->setUser($this->student);
|
||||
|
||||
// Trigger and capture the event.
|
||||
$sink = $this->redirectEvents();
|
||||
|
||||
$result = mod_quiz_external::view_attempt($attempt->id, 0);
|
||||
$result = external_api::clean_returnvalue(mod_quiz_external::view_attempt_returns(), $result);
|
||||
$this->assertTrue($result['status']);
|
||||
|
||||
$events = $sink->get_events();
|
||||
$this->assertCount(1, $events);
|
||||
$event = array_shift($events);
|
||||
|
||||
// Checking that the event contains the expected values.
|
||||
$this->assertInstanceOf('\mod_quiz\event\attempt_viewed', $event);
|
||||
$this->assertEquals($context, $event->get_context());
|
||||
$this->assertEventContextNotUsed($event);
|
||||
$this->assertNotEmpty($event->get_name());
|
||||
|
||||
// Now, force the quiz with QUIZ_NAVMETHOD_SEQ (sequencial) navigation method.
|
||||
$DB->set_field('quiz', 'navmethod', QUIZ_NAVMETHOD_SEQ, array('id' => $quiz->id));
|
||||
// See next page.
|
||||
$result = mod_quiz_external::view_attempt($attempt->id, 1);
|
||||
$result = external_api::clean_returnvalue(mod_quiz_external::view_attempt_returns(), $result);
|
||||
$this->assertTrue($result['status']);
|
||||
|
||||
$events = $sink->get_events();
|
||||
$this->assertCount(2, $events);
|
||||
|
||||
// Try to go to previous page.
|
||||
try {
|
||||
mod_quiz_external::view_attempt($attempt->id, 0);
|
||||
$this->fail('Exception expected due to try to see a previous page.');
|
||||
} catch (moodle_quiz_exception $e) {
|
||||
$this->assertEquals('Out of sequence access', $e->errorcode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2015111612;
|
||||
$plugin->version = 2015111613;
|
||||
$plugin->requires = 2015111000;
|
||||
$plugin->component = 'mod_quiz';
|
||||
$plugin->cron = 60;
|
||||
|
||||
Reference in New Issue
Block a user