mirror of
https://github.com/moodle/moodle.git
synced 2025-04-15 05:25:08 +02:00
Merge branch 'MDL-68381-master' of git://github.com/ferranrecio/moodle
This commit is contained in:
commit
773e46c808
@ -47,7 +47,8 @@ class backup_h5pactivity_activity_structure_step extends backup_activity_structu
|
||||
$attempts = new backup_nested_element('attempts');
|
||||
|
||||
$attempt = new backup_nested_element('attempt', ['id'],
|
||||
['h5pactivityid', 'userid', 'timecreated', 'timemodified', 'attempt', 'rawscore', 'maxscore']
|
||||
['h5pactivityid', 'userid', 'timecreated', 'timemodified', 'attempt', 'rawscore', 'maxscore',
|
||||
'duration', 'completion', 'success']
|
||||
);
|
||||
|
||||
$results = new backup_nested_element('results');
|
||||
@ -55,7 +56,8 @@ class backup_h5pactivity_activity_structure_step extends backup_activity_structu
|
||||
$result = new backup_nested_element('result', ['id'],
|
||||
[
|
||||
'attemptid', 'subcontent', 'timecreated', 'interactiontype', 'description',
|
||||
'correctpattern', 'response', 'additionals', 'rawscore', 'maxscore'
|
||||
'correctpattern', 'response', 'additionals', 'rawscore', 'maxscore',
|
||||
'duration', 'completion', 'success'
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -68,6 +68,9 @@ class attempt {
|
||||
$record->timemodified = $record->timecreated;
|
||||
$record->rawscore = 0;
|
||||
$record->maxscore = 0;
|
||||
$record->duration = 0;
|
||||
$record->completion = null;
|
||||
$record->success = null;
|
||||
|
||||
// Get last attempt number.
|
||||
$conditions = ['h5pactivityid' => $cm->instance, 'userid' => $user->id];
|
||||
@ -166,6 +169,7 @@ class attempt {
|
||||
}
|
||||
$definition = $xapidefinition->get_data();
|
||||
$result = $xapiresult->get_data();
|
||||
$duration = $xapiresult->get_duration();
|
||||
|
||||
// Insert attempt_results record.
|
||||
$record = new stdClass();
|
||||
@ -183,6 +187,13 @@ class attempt {
|
||||
$record->rawscore = $result->score->raw ?? 0;
|
||||
$record->maxscore = $result->score->max ?? 0;
|
||||
}
|
||||
$record->duration = $duration;
|
||||
if (isset($result->completion)) {
|
||||
$record->completion = ($result->completion) ? 1 : 0;
|
||||
}
|
||||
if (isset($result->success)) {
|
||||
$record->success = ($result->success) ? 1 : 0;
|
||||
}
|
||||
if (!$DB->insert_record('h5pactivity_attempts_results', $record)) {
|
||||
return false;
|
||||
}
|
||||
@ -191,6 +202,9 @@ class attempt {
|
||||
if (empty($subcontent) && $record->rawscore) {
|
||||
$this->record->rawscore = $record->rawscore;
|
||||
$this->record->maxscore = $record->maxscore;
|
||||
$this->record->duration = $record->duration;
|
||||
$this->record->completion = $record->completion ?? null;
|
||||
$this->record->success = $record->success ?? null;
|
||||
}
|
||||
// Refresh current attempt.
|
||||
return $this->save();
|
||||
@ -364,4 +378,31 @@ class attempt {
|
||||
public function get_rawscore(): int {
|
||||
return $this->record->maxscore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the attempt duration.
|
||||
*
|
||||
* @return int the duration value
|
||||
*/
|
||||
public function get_duration(): int {
|
||||
return $this->record->duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the attempt completion.
|
||||
*
|
||||
* @return int|null the completion value
|
||||
*/
|
||||
public function get_completion(): ?int {
|
||||
return $this->record->completion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the attempt success.
|
||||
*
|
||||
* @return int|null the success value
|
||||
*/
|
||||
public function get_success(): ?int {
|
||||
return $this->record->success;
|
||||
}
|
||||
}
|
||||
|
@ -177,6 +177,7 @@ class provider implements
|
||||
har.additionals,
|
||||
har.rawscore,
|
||||
har.maxscore,
|
||||
har.duration,
|
||||
har.timecreated,
|
||||
ctx.id as contextid
|
||||
FROM {h5pactivity_attempts_results} har
|
||||
@ -200,6 +201,7 @@ class provider implements
|
||||
'additionals' => $track->additionals,
|
||||
'rawscore' => $track->rawscore,
|
||||
'maxscore' => $track->maxscore,
|
||||
'duration' => $track->duration,
|
||||
'timecreated' => transform::datetime($track->timecreated),
|
||||
];
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="mod/h5pactivity/db" VERSION="20200410" COMMENT="XMLDB file for Moodle mod_h5pactivity"
|
||||
<XMLDB PATH="mod/h5pactivity/db" VERSION="20200414" COMMENT="XMLDB file for Moodle mod_h5pactivity"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
@ -31,6 +31,9 @@
|
||||
<FIELD NAME="attempt" TYPE="int" LENGTH="6" NOTNULL="true" DEFAULT="1" SEQUENCE="false" COMMENT="Attempt number"/>
|
||||
<FIELD NAME="rawscore" TYPE="int" LENGTH="10" NOTNULL="false" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="maxscore" TYPE="int" LENGTH="10" NOTNULL="false" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="duration" TYPE="int" LENGTH="10" NOTNULL="false" DEFAULT="0" SEQUENCE="false" COMMENT="Number of second inverted in that attempt (provided by the statement)"/>
|
||||
<FIELD NAME="completion" TYPE="int" LENGTH="1" NOTNULL="false" SEQUENCE="false" COMMENT="Store the xAPI tracking completion result."/>
|
||||
<FIELD NAME="success" TYPE="int" LENGTH="1" NOTNULL="false" SEQUENCE="false" COMMENT="Store the xAPI tracking success result."/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
@ -56,6 +59,9 @@
|
||||
<FIELD NAME="additionals" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Extra subcontent information in JSON format"/>
|
||||
<FIELD NAME="rawscore" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="maxscore" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="duration" TYPE="int" LENGTH="10" NOTNULL="false" DEFAULT="0" SEQUENCE="false" COMMENT="Seconds inverted in this result (exctracted directly from statement)"/>
|
||||
<FIELD NAME="completion" TYPE="int" LENGTH="1" NOTNULL="false" SEQUENCE="false" COMMENT="Store the xAPI tracking completion result."/>
|
||||
<FIELD NAME="success" TYPE="int" LENGTH="1" NOTNULL="false" SEQUENCE="false" COMMENT="Store the xAPI tracking success result."/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
|
@ -134,5 +134,61 @@ function xmldb_h5pactivity_upgrade($oldversion) {
|
||||
upgrade_mod_savepoint(true, 2020032300, 'h5pactivity');
|
||||
}
|
||||
|
||||
if ($oldversion < 2020041400) {
|
||||
|
||||
// Define field duration to be added to h5pactivity_attempts.
|
||||
$table = new xmldb_table('h5pactivity_attempts');
|
||||
$field = new xmldb_field('duration', XMLDB_TYPE_INTEGER, '10', null, null, null, '0', 'maxscore');
|
||||
|
||||
// Conditionally launch add field duration.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Define field completion to be added to h5pactivity_attempts.
|
||||
$field = new xmldb_field('completion', XMLDB_TYPE_INTEGER, '1', null, null, null, null, 'duration');
|
||||
|
||||
// Conditionally launch add field completion.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Define field success to be added to h5pactivity_attempts.
|
||||
$field = new xmldb_field('success', XMLDB_TYPE_INTEGER, '1', null, null, null, null, 'completion');
|
||||
|
||||
// Conditionally launch add field success.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Define field duration to be added to h5pactivity_attempts_results.
|
||||
$table = new xmldb_table('h5pactivity_attempts_results');
|
||||
$field = new xmldb_field('duration', XMLDB_TYPE_INTEGER, '10', null, null, null, '0', 'maxscore');
|
||||
|
||||
// Conditionally launch add field duration.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Define field completion to be added to h5pactivity_attempts_results.
|
||||
$field = new xmldb_field('completion', XMLDB_TYPE_INTEGER, '1', null, null, null, null, 'duration');
|
||||
|
||||
// Conditionally launch add field completion.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Define field success to be added to h5pactivity_attempts_results.
|
||||
$field = new xmldb_field('success', XMLDB_TYPE_INTEGER, '1', null, null, null, null, 'completion');
|
||||
|
||||
// Conditionally launch add field success.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// H5pactivity savepoint reached.
|
||||
upgrade_mod_savepoint(true, 2020041400, 'h5pactivity');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -135,6 +135,9 @@ class attempt_testcase extends \advanced_testcase {
|
||||
$this->assertEquals(0, $attempt->get_maxscore());
|
||||
$this->assertEquals(0, $attempt->get_rawscore());
|
||||
$this->assertEquals(0, $attempt->count_results());
|
||||
$this->assertEquals(0, $attempt->get_duration());
|
||||
$this->assertNull($attempt->get_completion());
|
||||
$this->assertNull($attempt->get_success());
|
||||
|
||||
$statement = $this->generate_statement($hasdefinition, $hasresult);
|
||||
$result = $attempt->save_statement($statement, $subcontent);
|
||||
@ -142,6 +145,9 @@ class attempt_testcase extends \advanced_testcase {
|
||||
$this->assertEquals($results[1], $attempt->get_maxscore());
|
||||
$this->assertEquals($results[2], $attempt->get_rawscore());
|
||||
$this->assertEquals($results[3], $attempt->count_results());
|
||||
$this->assertEquals($results[4], $attempt->get_duration());
|
||||
$this->assertEquals($results[5], $attempt->get_completion());
|
||||
$this->assertEquals($results[6], $attempt->get_success());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -152,28 +158,28 @@ class attempt_testcase extends \advanced_testcase {
|
||||
public function save_statement_data(): array {
|
||||
return [
|
||||
'Statement without definition and result' => [
|
||||
'', false, false, [false, 0, 0, 0]
|
||||
'', false, false, [false, 0, 0, 0, 0, null, null]
|
||||
],
|
||||
'Statement with definition but no result' => [
|
||||
'', true, false, [false, 0, 0, 0]
|
||||
'', true, false, [false, 0, 0, 0, 0, null, null]
|
||||
],
|
||||
'Statement with result but no definition' => [
|
||||
'', true, false, [false, 0, 0, 0]
|
||||
'', true, false, [false, 0, 0, 0, 0, null, null]
|
||||
],
|
||||
'Statement subcontent without definition and result' => [
|
||||
'111-222-333', false, false, [false, 0, 0, 0]
|
||||
'111-222-333', false, false, [false, 0, 0, 0, 0, null, null]
|
||||
],
|
||||
'Statement subcontent with definition but no result' => [
|
||||
'111-222-333', true, false, [false, 0, 0, 0]
|
||||
'111-222-333', true, false, [false, 0, 0, 0, 0, null, null]
|
||||
],
|
||||
'Statement subcontent with result but no definition' => [
|
||||
'111-222-333', true, false, [false, 0, 0, 0]
|
||||
'111-222-333', true, false, [false, 0, 0, 0, 0, null, null]
|
||||
],
|
||||
'Statement with definition, result but no subcontent' => [
|
||||
'', true, true, [true, 2, 2, 1]
|
||||
'', true, true, [true, 2, 2, 1, 25, 1, 1]
|
||||
],
|
||||
'Statement with definition, result and subcontent' => [
|
||||
'111-222-333', true, true, [true, 0, 0, 1]
|
||||
'111-222-333', true, true, [true, 0, 0, 1, 0, null, null]
|
||||
],
|
||||
];
|
||||
}
|
||||
@ -340,6 +346,7 @@ class attempt_testcase extends \advanced_testcase {
|
||||
'completion' => true,
|
||||
'success' => true,
|
||||
'score' => (object) ['min' => 0, 'max' => 2, 'raw' => 2, 'scaled' => 1],
|
||||
'duration' => 'PT25S',
|
||||
]));
|
||||
}
|
||||
return $statement;
|
||||
|
@ -121,6 +121,9 @@ class mod_h5pactivity_restore_testcase extends advanced_testcase {
|
||||
$this->assertEquals($attempt->attempt, $attempt2->attempt);
|
||||
$this->assertEquals($attempt->rawscore, $attempt2->rawscore);
|
||||
$this->assertEquals($attempt->maxscore, $attempt2->maxscore);
|
||||
$this->assertEquals($attempt->duration, $attempt2->duration);
|
||||
$this->assertEquals($attempt->completion, $attempt2->completion);
|
||||
$this->assertEquals($attempt->success, $attempt2->success);
|
||||
|
||||
// Compare results.
|
||||
$results = $DB->get_records('h5pactivity_attempts_results', ['attemptid' => $attempt->id]);
|
||||
@ -137,6 +140,9 @@ class mod_h5pactivity_restore_testcase extends advanced_testcase {
|
||||
$this->assertEquals($result->additionals, $result2->additionals);
|
||||
$this->assertEquals($result->rawscore, $result2->rawscore);
|
||||
$this->assertEquals($result->maxscore, $result2->maxscore);
|
||||
$this->assertEquals($result->duration, $result2->duration);
|
||||
$this->assertEquals($result->completion, $result2->completion);
|
||||
$this->assertEquals($result->success, $result2->success);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -285,6 +285,66 @@ class handler_testcase extends \advanced_testcase {
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test xapi_handler stored statements.
|
||||
*/
|
||||
public function test_stored_statements() {
|
||||
global $DB;
|
||||
|
||||
$data = $this->generate_testing_scenario();
|
||||
$xapihandler = $data->xapihandler;
|
||||
$context = $data->context;
|
||||
$student = $data->student;
|
||||
$otheruser = $data->otheruser;
|
||||
$activity = $data->activity;
|
||||
|
||||
// Check we have 0 entries in the attempts tables.
|
||||
$count = $DB->count_records('h5pactivity_attempts');
|
||||
$this->assertEquals(0, $count);
|
||||
$count = $DB->count_records('h5pactivity_attempts_results');
|
||||
$this->assertEquals(0, $count);
|
||||
|
||||
$statements = $this->generate_statements($context, $student);
|
||||
|
||||
// Insert statements.
|
||||
$stored = $xapihandler->process_statements($statements);
|
||||
$this->assertCount(2, $stored);
|
||||
$this->assertEquals(true, $stored[0]);
|
||||
$this->assertEquals(true, $stored[1]);
|
||||
$count = $DB->count_records('h5pactivity_attempts');
|
||||
$this->assertEquals(1, $count);
|
||||
$count = $DB->count_records('h5pactivity_attempts_results');
|
||||
$this->assertEquals(2, $count);
|
||||
|
||||
// Validate stored data.
|
||||
$attempts = $DB->get_records('h5pactivity_attempts');
|
||||
$attempt = array_shift($attempts);
|
||||
$statement = $statements[0];
|
||||
$data = $statement->get_result()->get_data();
|
||||
$this->assertEquals(1, $attempt->attempt);
|
||||
$this->assertEquals($student->id, $attempt->userid);
|
||||
$this->assertEquals($activity->id, $attempt->h5pactivityid);
|
||||
$this->assertEquals($data->score->raw, $attempt->rawscore);
|
||||
$this->assertEquals($data->score->max, $attempt->maxscore);
|
||||
$this->assertEquals($statement->get_result()->get_duration(), $attempt->duration);
|
||||
$this->assertEquals($data->completion, $attempt->completion);
|
||||
$this->assertEquals($data->success, $attempt->success);
|
||||
|
||||
$results = $DB->get_records('h5pactivity_attempts_results');
|
||||
foreach ($results as $result) {
|
||||
$statement = (empty($result->subcontent)) ? $statements[0] : $statements[1];
|
||||
$xapiresult = $statement->get_result()->get_data();
|
||||
$xapiobject = $statement->get_object()->get_data();
|
||||
$this->assertEquals($attempt->id, $result->attemptid);
|
||||
$this->assertEquals($xapiobject->definition->interactionType, $result->interactiontype);
|
||||
$this->assertEquals($xapiresult->score->raw, $result->rawscore);
|
||||
$this->assertEquals($xapiresult->score->max, $result->maxscore);
|
||||
$this->assertEquals($statement->get_result()->get_duration(), $result->duration);
|
||||
$this->assertEquals($xapiresult->completion, $result->completion);
|
||||
$this->assertEquals($xapiresult->success, $result->success);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a basic xAPI statements simulating a H5P content.
|
||||
*
|
||||
@ -307,6 +367,7 @@ class handler_testcase extends \advanced_testcase {
|
||||
'completion' => true,
|
||||
'success' => true,
|
||||
'score' => (object) ['min' => 0, 'max' => 2, 'raw' => 2, 'scaled' => 1],
|
||||
'duration' => 'PT25S',
|
||||
]));
|
||||
$statements[] = $statement;
|
||||
|
||||
@ -322,6 +383,7 @@ class handler_testcase extends \advanced_testcase {
|
||||
'completion' => true,
|
||||
'success' => true,
|
||||
'score' => (object) ['min' => 0, 'max' => 1, 'raw' => 0, 'scaled' => 0],
|
||||
'duration' => 'PT20S',
|
||||
]));
|
||||
$statements[] = $statement;
|
||||
|
||||
|
@ -25,5 +25,5 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->component = 'mod_h5pactivity';
|
||||
$plugin->version = 2020032300;
|
||||
$plugin->version = 2020041400;
|
||||
$plugin->requires = 2020013000;
|
||||
|
Loading…
x
Reference in New Issue
Block a user