Merge branch 'MDL-68381-master' of git://github.com/ferranrecio/moodle

This commit is contained in:
Sara Arjona 2020-05-06 17:43:53 +02:00
commit 773e46c808
9 changed files with 194 additions and 12 deletions

View File

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

View File

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

View File

@ -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),
];
}

View File

@ -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"/>

View File

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

View File

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

View File

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

View File

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

View File

@ -25,5 +25,5 @@
defined('MOODLE_INTERNAL') || die();
$plugin->component = 'mod_h5pactivity';
$plugin->version = 2020032300;
$plugin->version = 2020041400;
$plugin->requires = 2020013000;