mirror of
https://github.com/moodle/moodle.git
synced 2025-03-22 00:20:37 +01:00
Merge branch 'MDL-67791-master' of git://github.com/ferranrecio/moodle
This commit is contained in:
commit
410cec0d40
@ -41,14 +41,14 @@ class backup_h5pactivity_activity_structure_step extends backup_activity_structu
|
||||
// Replace with the attributes and final elements that the element will handle.
|
||||
$attributes = ['id'];
|
||||
$finalelements = ['name', 'timecreated', 'timemodified', 'intro',
|
||||
'introformat', 'grade', 'displayoptions', 'enabletracking', 'grademethod'];
|
||||
'introformat', 'grade', 'displayoptions', 'enabletracking', 'grademethod', 'reviewmode'];
|
||||
$root = new backup_nested_element('h5pactivity', $attributes, $finalelements);
|
||||
|
||||
$attempts = new backup_nested_element('attempts');
|
||||
|
||||
$attempt = new backup_nested_element('attempt', ['id'],
|
||||
['h5pactivityid', 'userid', 'timecreated', 'timemodified', 'attempt', 'rawscore', 'maxscore',
|
||||
'duration', 'completion', 'success']
|
||||
'duration', 'completion', 'success', 'scaled']
|
||||
);
|
||||
|
||||
$results = new backup_nested_element('results');
|
||||
|
131
mod/h5pactivity/classes/event/report_viewed.php
Normal file
131
mod/h5pactivity/classes/event/report_viewed.php
Normal file
@ -0,0 +1,131 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* H5P activity report viewed.
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The report_viewed event class.
|
||||
*
|
||||
* @property-read array $other {
|
||||
* Extra information about the event.
|
||||
*
|
||||
* - int instanceid: The instance ID
|
||||
* - int userid: The optional user ID
|
||||
* - int attemptid: The optional attempt ID
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @since Moodle 3.9
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class report_viewed extends \core\event\base {
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init(): void {
|
||||
$this->data['objecttable'] = 'h5pactivity';
|
||||
$this->data['crud'] = 'r';
|
||||
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns localised general event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('report_viewed', 'mod_h5pactivity');
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom validation.
|
||||
*
|
||||
* @throws \coding_exception
|
||||
* @return void
|
||||
*/
|
||||
protected function validate_data() {
|
||||
parent::validate_data();
|
||||
|
||||
if (empty($this->other['instanceid'])) {
|
||||
throw new \coding_exception('The \'instanceid\' value must be set in other.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns non-localised description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "The user with id '$this->userid' viewed the H5P report for the H5P with " .
|
||||
"course module id '$this->contextinstanceid'.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL related to the action
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
$params = ['a' => $this->other['instanceid']];
|
||||
|
||||
if (!empty($this->other['userid'])) {
|
||||
$params['userid'] = $this->other['userid'];
|
||||
}
|
||||
|
||||
if (!empty($this->other['attemptid'])) {
|
||||
$params['attemptid'] = $this->other['attemptid'];
|
||||
}
|
||||
|
||||
return new \moodle_url('/mod/h5pactivity/report.php', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used when restoring course logs where it is required that we
|
||||
* map the objectid to it's new value in the new course.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_objectid_mapping() {
|
||||
return ['db' => 'h5pactivity', 'restore' => 'h5pactivity'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the other field mapping.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_other_mapping() {
|
||||
$othermapped = array();
|
||||
$othermapped['attemptid'] = array('db' => 'h5pactivity_attempts', 'restore' => 'h5pactivity_attempts');
|
||||
$othermapped['userid'] = array('db' => 'user', 'restore' => 'user');
|
||||
return $othermapped;
|
||||
}
|
||||
|
||||
}
|
@ -293,6 +293,17 @@ class attempt {
|
||||
return $DB->count_records('h5pactivity_attempts_results', $conditions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all results stored in this attempt.
|
||||
*
|
||||
* @return stdClass[] results records.
|
||||
*/
|
||||
public function get_results(): array {
|
||||
global $DB;
|
||||
$conditions = ['attemptid' => $this->record->id];
|
||||
return $DB->get_records('h5pactivity_attempts_results', $conditions, 'id ASC');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get additional data for some interaction types.
|
||||
*
|
||||
@ -404,6 +415,24 @@ class attempt {
|
||||
return $this->record->userid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the attempt H5P timecreated.
|
||||
*
|
||||
* @return int the attempt timecreated
|
||||
*/
|
||||
public function get_timecreated(): int {
|
||||
return $this->record->timecreated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the attempt H5P timemodified.
|
||||
*
|
||||
* @return int the attempt timemodified
|
||||
*/
|
||||
public function get_timemodified(): int {
|
||||
return $this->record->timemodified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the attempt H5P activity ID.
|
||||
*
|
||||
@ -458,6 +487,15 @@ class attempt {
|
||||
return $this->record->success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the attempt scaled.
|
||||
*
|
||||
* @return int|null the scaled value
|
||||
*/
|
||||
public function get_scaled(): ?int {
|
||||
return $this->record->scaled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the attempt has been modified.
|
||||
*
|
||||
|
@ -25,9 +25,13 @@
|
||||
|
||||
namespace mod_h5pactivity\local;
|
||||
|
||||
use mod_h5pactivity\local\report\participants;
|
||||
use mod_h5pactivity\local\report\attempts;
|
||||
use mod_h5pactivity\local\report\results;
|
||||
use context_module;
|
||||
use cm_info;
|
||||
use moodle_recordset;
|
||||
use core_user;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
@ -55,6 +59,12 @@ class manager {
|
||||
/** Use first attempt results for grading. */
|
||||
const GRADEFIRSTATTEMPT = 4;
|
||||
|
||||
/** Participants cannot review their own attempts. */
|
||||
const REVIEWNONE = 0;
|
||||
|
||||
/** Participants can review their own attempts when have one attempt completed. */
|
||||
const REVIEWCOMPLETION = 1;
|
||||
|
||||
/** @var stdClass course_module record. */
|
||||
private $instance;
|
||||
|
||||
@ -118,6 +128,38 @@ class manager {
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the selected attempt criteria.
|
||||
* @return string[] an array "grademethod value", "attempt description"
|
||||
*/
|
||||
public function get_selected_attempt(): array {
|
||||
$types = [
|
||||
self::GRADEHIGHESTATTEMPT => get_string('attempt_highest', 'mod_h5pactivity'),
|
||||
self::GRADEAVERAGEATTEMPT => get_string('attempt_average', 'mod_h5pactivity'),
|
||||
self::GRADELASTATTEMPT => get_string('attempt_last', 'mod_h5pactivity'),
|
||||
self::GRADEFIRSTATTEMPT => get_string('attempt_first', 'mod_h5pactivity'),
|
||||
self::GRADEMANUAL => get_string('attempt_none', 'mod_h5pactivity'),
|
||||
];
|
||||
if ($this->instance->enabletracking) {
|
||||
$key = $this->instance->grademethod;
|
||||
} else {
|
||||
$key = self::GRADEMANUAL;
|
||||
}
|
||||
return [$key, $types[$key]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the available review modes.
|
||||
*
|
||||
* @return string[] an array "option value" => "option description"
|
||||
*/
|
||||
public static function get_review_modes(): array {
|
||||
return [
|
||||
self::REVIEWCOMPLETION => get_string('review_on_completion', 'mod_h5pactivity'),
|
||||
self::REVIEWNONE => get_string('review_none', 'mod_h5pactivity'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tracking is enabled in a particular h5pactivity for a specific user.
|
||||
*
|
||||
@ -135,6 +177,50 @@ class manager {
|
||||
return has_capability('mod/h5pactivity:submit', $this->context, $user, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user can see the activity attempts list.
|
||||
*
|
||||
* @param stdClass|null $user user record (default $USER)
|
||||
* @return bool if the user can see the attempts link
|
||||
*/
|
||||
public function can_view_all_attempts (stdClass $user = null): bool {
|
||||
global $USER;
|
||||
if (!$this->instance->enabletracking) {
|
||||
return false;
|
||||
}
|
||||
if (empty($user)) {
|
||||
$user = $USER;
|
||||
}
|
||||
return has_capability('mod/h5pactivity:reviewattempts', $this->context, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user can see own attempts.
|
||||
*
|
||||
* @param stdClass|null $user user record (default $USER)
|
||||
* @return bool if the user can see the own attempts link
|
||||
*/
|
||||
public function can_view_own_attempts (stdClass $user = null): bool {
|
||||
global $USER;
|
||||
if (!$this->instance->enabletracking) {
|
||||
return false;
|
||||
}
|
||||
if (empty($user)) {
|
||||
$user = $USER;
|
||||
}
|
||||
if (has_capability('mod/h5pactivity:reviewattempts', $this->context, $user, false)) {
|
||||
return true;
|
||||
}
|
||||
if ($this->instance->reviewmode == self::REVIEWNONE) {
|
||||
return false;
|
||||
}
|
||||
if ($this->instance->reviewmode == self::REVIEWCOMPLETION) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a relation of userid and the valid attempt's scaled score.
|
||||
*
|
||||
@ -198,6 +284,46 @@ class manager {
|
||||
return $DB->get_records_sql($sql, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the activity completed attempts.
|
||||
*
|
||||
* If no user is provided will count all activity attempts.
|
||||
*
|
||||
* @param int|null $userid optional user id (default null)
|
||||
* @return int the total amount of attempts
|
||||
*/
|
||||
public function count_attempts(int $userid = null): int {
|
||||
global $DB;
|
||||
$params = [
|
||||
'h5pactivityid' => $this->instance->id,
|
||||
'completion' => 1
|
||||
];
|
||||
if ($userid) {
|
||||
$params['userid'] = $userid;
|
||||
}
|
||||
return $DB->count_records('h5pactivity_attempts', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of all users and it's total attempts.
|
||||
*
|
||||
* Note: this funciton only returns the list of users with attempts,
|
||||
* it does not check all participants.
|
||||
*
|
||||
* @return array indexed count userid => total number of attempts
|
||||
*/
|
||||
public function count_users_attempts(): array {
|
||||
global $DB;
|
||||
$params = [
|
||||
'h5pactivityid' => $this->instance->id,
|
||||
];
|
||||
$sql = "SELECT userid, count(*)
|
||||
FROM {h5pactivity_attempts}
|
||||
WHERE h5pactivityid = :h5pactivityid
|
||||
GROUP BY userid";
|
||||
return $DB->get_records_sql_menu($sql, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current context.
|
||||
*
|
||||
@ -208,7 +334,7 @@ class manager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current context.
|
||||
* Return the current instance.
|
||||
*
|
||||
* @return stdClass the instance record
|
||||
*/
|
||||
@ -234,4 +360,89 @@ class manager {
|
||||
$idnumber = $this->coursemodule->idnumber ?? '';
|
||||
return new grader($this->instance, $idnumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the suitable report to show the attempts.
|
||||
*
|
||||
* This method controls the access to the different reports
|
||||
* the activity have.
|
||||
*
|
||||
* @param int $userid an opional userid to show
|
||||
* @param int $attemptid an optional $attemptid to show
|
||||
* @return report|null available report (or null if no report available)
|
||||
*/
|
||||
public function get_report(int $userid = null, int $attemptid = null): ?report {
|
||||
global $USER;
|
||||
$attempt = null;
|
||||
if ($attemptid) {
|
||||
$attempt = $this->get_attempt($attemptid);
|
||||
if (!$attempt) {
|
||||
return null;
|
||||
}
|
||||
// If we have and attempt we can ignore the provided $userid.
|
||||
$userid = $attempt->get_userid();
|
||||
}
|
||||
|
||||
if ($this->can_view_all_attempts()) {
|
||||
$user = core_user::get_user($userid);
|
||||
} else if ($this->can_view_own_attempts()) {
|
||||
$user = $USER;
|
||||
if ($userid && $user->id != $userid) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if that user can be tracked.
|
||||
if ($user && !$this->is_tracking_enabled($user)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create the proper report.
|
||||
if ($user && $attempt) {
|
||||
return new results($this, $user, $attempt);
|
||||
} else if ($user) {
|
||||
return new attempts($this, $user);
|
||||
}
|
||||
return new participants($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a single attempt.
|
||||
*
|
||||
* @param int $attemptid the attempt id
|
||||
* @return attempt
|
||||
*/
|
||||
public function get_attempt(int $attemptid): ?attempt {
|
||||
global $DB;
|
||||
$record = $DB->get_record('h5pactivity_attempts', ['id' => $attemptid]);
|
||||
if (!$record) {
|
||||
return null;
|
||||
}
|
||||
return new attempt($record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of all user attempts (including incompleted)
|
||||
*
|
||||
* @param int $userid the user id
|
||||
* @return attempt[]
|
||||
*/
|
||||
public function get_user_attempts(int $userid): array {
|
||||
global $DB;
|
||||
$records = $DB->get_records(
|
||||
'h5pactivity_attempts',
|
||||
['userid' => $userid, 'h5pactivityid' => $this->instance->id],
|
||||
'id ASC'
|
||||
);
|
||||
if (!$records) {
|
||||
return [];
|
||||
}
|
||||
$result = [];
|
||||
foreach ($records as $record) {
|
||||
$result[] = new attempt($record);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
58
mod/h5pactivity/classes/local/report.php
Normal file
58
mod/h5pactivity/classes/local/report.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* H5P activity report interface
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @since Moodle 3.9
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\local;
|
||||
|
||||
use templatable;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Interface for any mod_h5pactivity report.
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @since Moodle 3.9
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
*/
|
||||
interface report {
|
||||
|
||||
/**
|
||||
* Return the report user record.
|
||||
*
|
||||
* @return stdClass|null a user or null
|
||||
*/
|
||||
public function get_user(): ?stdClass;
|
||||
|
||||
/**
|
||||
* Return the report attempt object.
|
||||
*
|
||||
* @return attempt|null the attempt object or null
|
||||
*/
|
||||
public function get_attempt(): ?attempt;
|
||||
|
||||
/**
|
||||
* Print the report visualization.
|
||||
*/
|
||||
public function print(): void;
|
||||
}
|
139
mod/h5pactivity/classes/local/report/attempts.php
Normal file
139
mod/h5pactivity/classes/local/report/attempts.php
Normal file
@ -0,0 +1,139 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* H5P activity attempts report
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @since Moodle 3.9
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\local\report;
|
||||
|
||||
use mod_h5pactivity\local\report;
|
||||
use mod_h5pactivity\local\manager;
|
||||
use mod_h5pactivity\local\attempt;
|
||||
use mod_h5pactivity\output\reportattempts;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Class H5P activity attempts report.
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @since Moodle 3.9
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
*/
|
||||
class attempts implements report {
|
||||
|
||||
/** @var manager the H5P activity manager instance. */
|
||||
private $manager;
|
||||
|
||||
/** @var stdClass the user record. */
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* Create a new participants report.
|
||||
*
|
||||
* @param manager $manager h5pactivity manager object
|
||||
* @param stdClass $user user record
|
||||
*/
|
||||
public function __construct(manager $manager, stdClass $user) {
|
||||
$this->manager = $manager;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the report user record.
|
||||
*
|
||||
* @return stdClass|null a user or null
|
||||
*/
|
||||
public function get_user(): ?stdClass {
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the report attempt object.
|
||||
*
|
||||
* Attempts report has no specific attempt.
|
||||
*
|
||||
* @return attempt|null the attempt object or null
|
||||
*/
|
||||
public function get_attempt(): ?attempt {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the report.
|
||||
*/
|
||||
public function print(): void {
|
||||
global $OUTPUT;
|
||||
|
||||
$manager = $this->manager;
|
||||
$cm = $manager->get_coursemodule();
|
||||
|
||||
$scored = $this->get_scored();
|
||||
$title = $scored->title ?? null;
|
||||
$scoredattempt = $scored->attempt ?? null;
|
||||
|
||||
$attempts = $this->get_attempts();
|
||||
|
||||
$widget = new reportattempts($attempts, $this->user, $cm->course, $title, $scoredattempt);
|
||||
echo $OUTPUT->render($widget);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current report attempts.
|
||||
*
|
||||
* This method is used to render the report in both browser and mobile.
|
||||
*
|
||||
* @return attempts[]
|
||||
*/
|
||||
public function get_attempts(): array {
|
||||
return $this->manager->get_user_attempts($this->user->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current report attempts.
|
||||
*
|
||||
* This method is used to render the report in both browser and mobile.
|
||||
*
|
||||
* @return stdClass|null a structure with
|
||||
* - title => name of the selected attempt (or null)
|
||||
* - attempt => the selected attempt object (or null)
|
||||
* - gradingmethos => the activity grading method (or null)
|
||||
*/
|
||||
public function get_scored(): ?stdClass {
|
||||
$manager = $this->manager;
|
||||
$scores = $manager->get_users_scaled_score($this->user->id);
|
||||
$score = $scores[$this->user->id] ?? null;
|
||||
|
||||
if (empty($score->attemptid)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
list($grademethod, $title) = $manager->get_selected_attempt();
|
||||
$scoredattempt = $manager->get_attempt($score->attemptid);
|
||||
|
||||
$result = (object)[
|
||||
'title' => $title,
|
||||
'attempt' => $scoredattempt,
|
||||
'grademethod' => $grademethod,
|
||||
];
|
||||
return $result;
|
||||
}
|
||||
}
|
204
mod/h5pactivity/classes/local/report/participants.php
Normal file
204
mod/h5pactivity/classes/local/report/participants.php
Normal file
@ -0,0 +1,204 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* H5P activity participants report
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @since Moodle 3.9
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\local\report;
|
||||
|
||||
use mod_h5pactivity\local\report;
|
||||
use mod_h5pactivity\local\manager;
|
||||
use mod_h5pactivity\local\attempt;
|
||||
use table_sql;
|
||||
use moodle_url;
|
||||
use html_writer;
|
||||
use stdClass;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->libdir.'/tablelib.php');
|
||||
|
||||
/**
|
||||
* Class H5P activity participants report.
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @since Moodle 3.9
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
*/
|
||||
class participants extends table_sql implements report {
|
||||
|
||||
/** @var manager the H5P activity manager instance. */
|
||||
private $manager;
|
||||
|
||||
/** @var array the users scored attempts. */
|
||||
private $scores;
|
||||
|
||||
/** @var array the user attempts count. */
|
||||
private $count;
|
||||
|
||||
/**
|
||||
* Create a new participants report.
|
||||
*
|
||||
* @param manager $manager h5pactivitymanager object
|
||||
*/
|
||||
public function __construct(manager $manager) {
|
||||
parent::__construct('mod_h5pactivity-participants');
|
||||
$this->manager = $manager;
|
||||
$this->scores = $manager->get_users_scaled_score();
|
||||
$this->count = $manager->count_users_attempts();
|
||||
|
||||
// Setup table_sql.
|
||||
$columns = ['fullname', 'timemodified', 'score', 'attempts'];
|
||||
$headers = [
|
||||
get_string('fullname'), get_string('date'),
|
||||
get_string('score', 'mod_h5pactivity'), get_string('attempts', 'mod_h5pactivity'),
|
||||
];
|
||||
$this->define_columns($columns);
|
||||
$this->define_headers($headers);
|
||||
$this->set_attribute('class', 'generaltable generalbox boxaligncenter boxwidthwide');
|
||||
$this->sortable(true);
|
||||
$this->no_sorting('score');
|
||||
$this->no_sorting('timemodified');
|
||||
$this->no_sorting('attempts');
|
||||
$this->pageable(true);
|
||||
|
||||
// Set query SQL.
|
||||
$capjoin = get_enrolled_with_capabilities_join($this->manager->get_context(), '', 'mod/h5pactivity:submit');
|
||||
$this->set_sql(
|
||||
'u.*',
|
||||
"{user} u $capjoin->joins",
|
||||
$capjoin->wheres,
|
||||
$capjoin->params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the report user record.
|
||||
*
|
||||
* Participants report has no specific user.
|
||||
*
|
||||
* @return stdClass|null a user or null
|
||||
*/
|
||||
public function get_user(): ?stdClass {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the report attempt object.
|
||||
*
|
||||
* Participants report has no specific attempt.
|
||||
*
|
||||
* @return attempt|null the attempt object or null
|
||||
*/
|
||||
public function get_attempt(): ?attempt {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the report.
|
||||
*/
|
||||
public function print(): void {
|
||||
global $PAGE, $OUTPUT;
|
||||
|
||||
$this->define_baseurl($PAGE->url);
|
||||
|
||||
echo $OUTPUT->heading(get_string('attempts_report', 'mod_h5pactivity'));
|
||||
|
||||
$this->out($this->get_page_size(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning in case no user has the selected initials letters.
|
||||
*
|
||||
*/
|
||||
public function print_nothing_to_display() {
|
||||
global $OUTPUT;
|
||||
echo $this->render_reset_button();
|
||||
$this->print_initials_bar();
|
||||
echo $OUTPUT->notification(get_string('noparticipants', 'mod_h5pactivity'), 'warning');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the fullname column.
|
||||
*
|
||||
* @param stdClass $user
|
||||
* @return string
|
||||
*/
|
||||
public function col_fullname($user): string {
|
||||
global $OUTPUT;
|
||||
$cm = $this->manager->get_coursemodule();
|
||||
return $OUTPUT->user_picture($user, ['size' => 35, 'courseid' => $cm->course, 'includefullname' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate score column.
|
||||
*
|
||||
* @param stdClass $user the user record
|
||||
* @return string
|
||||
*/
|
||||
public function col_score(stdClass $user): string {
|
||||
$cm = $this->manager->get_coursemodule();
|
||||
if (isset($this->scores[$user->id])) {
|
||||
$score = $this->scores[$user->id];
|
||||
$maxgrade = floatval(100);
|
||||
$scaled = round($maxgrade * $score->scaled).'%';
|
||||
if (empty($score->attemptid)) {
|
||||
return $scaled;
|
||||
} else {
|
||||
$url = new moodle_url('/mod/h5pactivity/report.php', ['a' => $cm->instance, 'attemptid' => $score->attemptid]);
|
||||
return html_writer::link($url, $scaled);
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate attempts count column, if any.
|
||||
*
|
||||
* @param stdClass $user the user record
|
||||
* @return string
|
||||
*/
|
||||
public function col_attempts(stdClass $user): string {
|
||||
$cm = $this->manager->get_coursemodule();
|
||||
if (isset($this->count[$user->id])) {
|
||||
$msg = get_string('review_user_attempts', 'mod_h5pactivity', $this->count[$user->id]);
|
||||
$url = new moodle_url('/mod/h5pactivity/report.php', ['a' => $cm->instance, 'userid' => $user->id]);
|
||||
return html_writer::link($url, $msg);
|
||||
}
|
||||
return '';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate attempt timemodified column, if any.
|
||||
*
|
||||
* @param stdClass $user the user record
|
||||
* @return string
|
||||
*/
|
||||
public function col_timemodified(stdClass $user): string {
|
||||
if (isset($this->scores[$user->id])) {
|
||||
$score = $this->scores[$user->id];
|
||||
return userdate($score->timemodified);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
98
mod/h5pactivity/classes/local/report/results.php
Normal file
98
mod/h5pactivity/classes/local/report/results.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* H5P activity results report.
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @since Moodle 3.9
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\local\report;
|
||||
|
||||
use mod_h5pactivity\local\report;
|
||||
use mod_h5pactivity\local\manager;
|
||||
use mod_h5pactivity\local\attempt;
|
||||
use mod_h5pactivity\output\reportresults;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Class H5P activity results report.
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @since Moodle 3.9
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
*/
|
||||
class results implements report {
|
||||
|
||||
/** @var manager the H5P activity manager instance. */
|
||||
private $manager;
|
||||
|
||||
/** @var stdClass the user record. */
|
||||
private $user;
|
||||
|
||||
/** @var attempt the h5pactivity attempt to show. */
|
||||
private $attempt;
|
||||
|
||||
/**
|
||||
* Create a new participants report.
|
||||
*
|
||||
* @param manager $manager h5pactivity manager object
|
||||
* @param stdClass $user user record
|
||||
* @param attempt $attempt attempt object
|
||||
*/
|
||||
public function __construct(manager $manager, stdClass $user, attempt $attempt) {
|
||||
$this->manager = $manager;
|
||||
$this->user = $user;
|
||||
$this->attempt = $attempt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the report user record.
|
||||
*
|
||||
* @return stdClass|null a user or null
|
||||
*/
|
||||
public function get_user(): ?stdClass {
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the report attempt object.
|
||||
*
|
||||
* Attempts report has no specific attempt.
|
||||
*
|
||||
* @return attempt|null the attempt object or null
|
||||
*/
|
||||
public function get_attempt(): ?attempt {
|
||||
return $this->attempt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the report.
|
||||
*/
|
||||
public function print(): void {
|
||||
global $OUTPUT;
|
||||
|
||||
$manager = $this->manager;
|
||||
$attempt = $this->attempt;
|
||||
$cm = $manager->get_coursemodule();
|
||||
|
||||
$widget = new reportresults($attempt, $this->user, $cm->course);
|
||||
echo $OUTPUT->render($widget);
|
||||
}
|
||||
}
|
227
mod/h5pactivity/classes/output/attempt.php
Normal file
227
mod/h5pactivity/classes/output/attempt.php
Normal file
@ -0,0 +1,227 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class mod_h5pactivity\output\reportlink
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\output;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_h5pactivity\local\attempt as activity_attempt;
|
||||
use renderable;
|
||||
use templatable;
|
||||
use renderer_base;
|
||||
use moodle_url;
|
||||
use user_picture;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Class to help display report link in mod_h5pactivity.
|
||||
*
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class attempt implements renderable, templatable {
|
||||
|
||||
/** @var activity_attempt attempt */
|
||||
public $attempt;
|
||||
|
||||
/** @var stdClass user record */
|
||||
public $user;
|
||||
|
||||
/** @var int courseid necesary to present user picture */
|
||||
public $courseid;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param activity_attempt $attempt the attempt object
|
||||
* @param stdClass $user a user record (default null).
|
||||
* @param int $courseid optional course id (default null).
|
||||
*/
|
||||
public function __construct(activity_attempt $attempt, stdClass $user = null, int $courseid = null) {
|
||||
$this->attempt = $attempt;
|
||||
$this->user = $user;
|
||||
$this->courseid = $courseid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export this data so it can be used as the context for a mustache template.
|
||||
*
|
||||
* @param renderer_base $output
|
||||
* @return stdClass
|
||||
*/
|
||||
public function export_for_template(renderer_base $output) {
|
||||
$attempt = $this->attempt;
|
||||
|
||||
$data = (object)[
|
||||
'id' => $attempt->get_id(),
|
||||
'h5pactivityid' => $attempt->get_h5pactivityid(),
|
||||
'userid' => $attempt->get_userid(),
|
||||
'timecreated' => $attempt->get_timecreated(),
|
||||
'timemodified' => $attempt->get_timemodified(),
|
||||
'attempt' => $attempt->get_attempt(),
|
||||
'rawscore' => $attempt->get_rawscore(),
|
||||
'maxscore' => $attempt->get_maxscore(),
|
||||
'duration' => '-',
|
||||
'durationcompact' => '-',
|
||||
'completion' => $attempt->get_completion(),
|
||||
'completionicon' => $this->completion_icon($output, $attempt->get_completion()),
|
||||
'completiontext' => $this->completion_icon($output, $attempt->get_completion(), true),
|
||||
'success' => $attempt->get_success(),
|
||||
'successicon' => $this->success_icon($output, $attempt->get_success()),
|
||||
'successtext' => $this->success_icon($output, $attempt->get_success(), true),
|
||||
'scaled' => $attempt->get_scaled(),
|
||||
'reporturl' => new moodle_url('/mod/h5pactivity/report.php', [
|
||||
'a' => $attempt->get_h5pactivityid(), 'attemptid' => $attempt->get_id()
|
||||
]),
|
||||
];
|
||||
if ($attempt->get_duration() !== null) {
|
||||
$duration = $this->extract_duration($attempt->get_duration());
|
||||
$data->duration = $this->format_duration($duration);
|
||||
$data->durationcompact = $this->format_duration_short($duration);
|
||||
}
|
||||
|
||||
if (!empty($data->maxscore)) {
|
||||
$data->score = get_string('score_out_of', 'mod_h5pactivity', $data);
|
||||
}
|
||||
if ($this->user) {
|
||||
$data->user = $this->user;
|
||||
$userpicture = new user_picture($this->user);
|
||||
$userpicture->courseid = $this->courseid;
|
||||
$data->user->picture = $output->render($userpicture);
|
||||
$data->user->fullname = fullname($this->user);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a completion icon HTML.
|
||||
*
|
||||
* @param renderer_base $output the renderer base object
|
||||
* @param int|null $completion the current completion value
|
||||
* @param bool $showtext if the icon must have a text or only icon
|
||||
* @return string icon HTML
|
||||
*/
|
||||
private function completion_icon(renderer_base $output, int $completion = null, bool $showtext = false): string {
|
||||
if ($completion === null) {
|
||||
return '';
|
||||
}
|
||||
if ($completion) {
|
||||
$alt = get_string('attempt_completion_yes', 'mod_h5pactivity');
|
||||
$icon = 'i/completion-auto-y';
|
||||
} else {
|
||||
$alt = get_string('attempt_completion_no', 'mod_h5pactivity');
|
||||
$icon = 'i/completion-auto-n';
|
||||
}
|
||||
$text = '';
|
||||
if ($showtext) {
|
||||
$text = $alt;
|
||||
$alt = '';
|
||||
}
|
||||
return $output->pix_icon($icon, $alt).$text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a success icon
|
||||
* @param renderer_base $output the renderer base object
|
||||
* @param int|null $success the current success value
|
||||
* @param bool $showtext if the icon must have a text or only icon
|
||||
* @return string icon HTML
|
||||
*/
|
||||
private function success_icon(renderer_base $output, int $success = null, bool $showtext = false): string {
|
||||
if ($success === null) {
|
||||
$alt = get_string('attempt_success_unknown', 'mod_h5pactivity');
|
||||
if ($showtext) {
|
||||
return $alt;
|
||||
}
|
||||
$icon = 'i/empty';
|
||||
} else if ($success) {
|
||||
$alt = get_string('attempt_success_pass', 'mod_h5pactivity');
|
||||
$icon = 'i/checkedcircle';
|
||||
} else {
|
||||
$alt = get_string('attempt_success_fail', 'mod_h5pactivity');
|
||||
$icon = 'i/uncheckedcircle';
|
||||
}
|
||||
$text = '';
|
||||
if ($showtext) {
|
||||
$text = $alt;
|
||||
$alt = '';
|
||||
}
|
||||
return $output->pix_icon($icon, $alt).$text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the duration in long format (localized)
|
||||
*
|
||||
* @param stdClass $duration object with (h)hours, (m)minutes and (s)seconds
|
||||
* @return string the long format duration
|
||||
*/
|
||||
private function format_duration (stdClass $duration): string {
|
||||
$result = [];
|
||||
if ($duration->h) {
|
||||
$result[] = get_string('numhours', 'moodle', $duration->h);
|
||||
}
|
||||
if ($duration->m) {
|
||||
$result[] = get_string('numminutes', 'moodle', $duration->m);
|
||||
}
|
||||
if ($duration->s) {
|
||||
$result[] = get_string('numseconds', 'moodle', $duration->s);
|
||||
}
|
||||
return implode(' ', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the duration en short format (for example: 145' 43'')
|
||||
*
|
||||
* Note: this method is used to make duration responsive.
|
||||
*
|
||||
* @param stdClass $duration object with (h)hours, (m)minutes and (s)seconds
|
||||
* @return string the short format duration
|
||||
*/
|
||||
private function format_duration_short (stdClass $duration): string {
|
||||
$result = [];
|
||||
if ($duration->h || $duration->m) {
|
||||
$result[] = ($duration->h * 60 + $duration->m)."'";
|
||||
}
|
||||
if ($duration->s) {
|
||||
$result[] = $duration->s."''";
|
||||
}
|
||||
return implode(' ', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract hours and minutes from second duration.
|
||||
*
|
||||
* Note: this function is used to generate the param for format_duration
|
||||
* and format_duration_short
|
||||
*
|
||||
* @param int $seconds number of second
|
||||
* @return stdClass with (h)hours, (m)minutes and (s)seconds
|
||||
*/
|
||||
private function extract_duration (int $seconds): stdClass {
|
||||
$h = floor($seconds / 3600);
|
||||
$m = floor(($seconds - $h * 3600) / 60);
|
||||
$s = $seconds - ($h * 3600 + $m * 60);
|
||||
return (object)['h' => $h, 'm' => $m, 's' => $s];
|
||||
}
|
||||
}
|
118
mod/h5pactivity/classes/output/reportattempts.php
Normal file
118
mod/h5pactivity/classes/output/reportattempts.php
Normal file
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class mod_h5pactivity\output\report\attempts
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\output;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_h5pactivity\local\attempt;
|
||||
use mod_h5pactivity\output\attempt as output_attempt;
|
||||
use renderable;
|
||||
use templatable;
|
||||
use renderer_base;
|
||||
use user_picture;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Class to output an attempts report on mod_h5pactivity.
|
||||
*
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class reportattempts implements renderable, templatable {
|
||||
|
||||
/** @var attempt[] attempts */
|
||||
public $attempts;
|
||||
|
||||
/** @var stdClass user record */
|
||||
public $user;
|
||||
|
||||
/** @var int courseid necesary to present user picture */
|
||||
public $courseid;
|
||||
|
||||
/** @var attempt scored attempt */
|
||||
public $scored;
|
||||
|
||||
/** @var string scored attempt title */
|
||||
public $title;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* The "scored attempt" is the attempt used for grading. By default it is the max score attempt
|
||||
* but this could be defined in the activity settings. In some cases this scored attempts does not
|
||||
* exists at all, this is the reason why it's an optional param.
|
||||
*
|
||||
* @param array $attempts an array of attempts
|
||||
* @param stdClass $user a user record
|
||||
* @param int $courseid course id
|
||||
* @param string|null $title title to display on the scored attempt (null if none attempt is the scored one)
|
||||
* @param attempt|null $scored the scored attempt (null if none)
|
||||
*/
|
||||
public function __construct(array $attempts, stdClass $user, int $courseid, string $title = null, attempt $scored = null) {
|
||||
$this->attempts = $attempts;
|
||||
$this->user = $user;
|
||||
$this->courseid = $courseid;
|
||||
$this->title = $title;
|
||||
$this->scored = $scored;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export this data so it can be used as the context for a mustache template.
|
||||
*
|
||||
* @param renderer_base $output
|
||||
* @return stdClass
|
||||
*/
|
||||
public function export_for_template(renderer_base $output) {
|
||||
global $USER;
|
||||
|
||||
$data = (object)['attempts' => [], 'user' => $this->user];
|
||||
foreach ($this->attempts as $attempt) {
|
||||
$outputattempt = new output_attempt($attempt);
|
||||
$data->attempts[] = $outputattempt->export_for_template($output);
|
||||
}
|
||||
$data->attemptscount = count($data->attempts);
|
||||
|
||||
$userpicture = new user_picture($this->user);
|
||||
$userpicture->courseid = $this->courseid;
|
||||
$data->user->fullname = fullname($this->user);
|
||||
$data->user->picture = $output->render($userpicture);
|
||||
|
||||
if ($USER->id == $this->user->id) {
|
||||
$data->title = get_string('myattempts', 'mod_h5pactivity');
|
||||
}
|
||||
|
||||
if (!empty($this->title)) {
|
||||
$scored = (object)[
|
||||
'title' => $this->title,
|
||||
'attempts' => [],
|
||||
];
|
||||
$outputattempt = new output_attempt($this->scored);
|
||||
$scored->attempts[] = $outputattempt->export_for_template($output);
|
||||
$data->scored = $scored;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
68
mod/h5pactivity/classes/output/reportlink.php
Normal file
68
mod/h5pactivity/classes/output/reportlink.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class mod_h5pactivity\output\reportlink
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\output;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use renderable;
|
||||
use templatable;
|
||||
use renderer_base;
|
||||
use moodle_url;
|
||||
|
||||
/**
|
||||
* Class to help display report link in mod_h5pactivity.
|
||||
*
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class reportlink implements renderable, templatable {
|
||||
|
||||
/** @var H5P factory */
|
||||
public $url;
|
||||
|
||||
/** @var H5P library list */
|
||||
public $message;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param moodle_url $url the destination url
|
||||
* @param string $message the link message
|
||||
*/
|
||||
public function __construct(moodle_url $url, string $message) {
|
||||
$this->url = $url;
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export this data so it can be used as the context for a mustache template.
|
||||
*
|
||||
* @param renderer_base $output
|
||||
* @return stdClass
|
||||
*/
|
||||
public function export_for_template(renderer_base $output) {
|
||||
return $this;
|
||||
}
|
||||
}
|
92
mod/h5pactivity/classes/output/reportresults.php
Normal file
92
mod/h5pactivity/classes/output/reportresults.php
Normal file
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class mod_h5pactivity\output\reportresults
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\output;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_h5pactivity\local\attempt;
|
||||
use mod_h5pactivity\output\attempt as output_attempt;
|
||||
use mod_h5pactivity\output\result as output_result;
|
||||
use renderable;
|
||||
use templatable;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Class to display the result report in mod_h5pactivity.
|
||||
*
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class reportresults implements renderable, templatable {
|
||||
|
||||
/** @var attempt the header attempt */
|
||||
public $attempt;
|
||||
|
||||
/** @var stdClass user record */
|
||||
public $user;
|
||||
|
||||
/** @var int courseid necesary to present user picture */
|
||||
public $courseid;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param attempt $attempt the current attempt
|
||||
* @param stdClass $user a user record
|
||||
* @param int $courseid course id
|
||||
*/
|
||||
public function __construct(attempt $attempt, stdClass $user, int $courseid) {
|
||||
$this->attempt = $attempt;
|
||||
$this->user = $user;
|
||||
$this->courseid = $courseid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export this data so it can be used as the context for a mustache template.
|
||||
*
|
||||
* @param renderer_base $output
|
||||
* @return stdClass
|
||||
*/
|
||||
public function export_for_template(renderer_base $output) {
|
||||
|
||||
$outputattempt = new output_attempt($this->attempt, $this->user, $this->courseid);
|
||||
|
||||
$data = (object)[
|
||||
'attempt' => $outputattempt->export_for_template($output),
|
||||
];
|
||||
|
||||
$results = $this->attempt->get_results();
|
||||
$data->results = [];
|
||||
foreach ($results as $key => $result) {
|
||||
$outputresult = output_result::create_from_record($result);
|
||||
if ($outputresult) {
|
||||
$data->results[] = $outputresult->export_for_template($output);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
300
mod/h5pactivity/classes/output/result.php
Normal file
300
mod/h5pactivity/classes/output/result.php
Normal file
@ -0,0 +1,300 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class mod_h5pactivity\output\result
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\output;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use renderable;
|
||||
use templatable;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Class to display an attempt tesult in mod_h5pactivity.
|
||||
*
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class result implements renderable, templatable {
|
||||
|
||||
/** Correct answer state. */
|
||||
const CORRECT = 1;
|
||||
|
||||
/** Incorrect answer state. */
|
||||
const INCORRECT = 2;
|
||||
|
||||
/** Checked answer state. */
|
||||
const CHECKED = 3;
|
||||
|
||||
/** Unchecked answer state. */
|
||||
const UNCHECKED = 4;
|
||||
|
||||
/** Pass answer state. */
|
||||
const PASS = 5;
|
||||
|
||||
/** Pass answer state. */
|
||||
const FAIL = 6;
|
||||
|
||||
/** Unkown answer state. */
|
||||
const UNKNOWN = 7;
|
||||
|
||||
/** Text answer state. */
|
||||
const TEXT = 8;
|
||||
|
||||
/** @var stdClass result record */
|
||||
protected $result;
|
||||
|
||||
/** @var mixed additional decoded data */
|
||||
protected $additionals;
|
||||
|
||||
/** @var mixed response decoded data */
|
||||
protected $response;
|
||||
|
||||
/** @var mixed correctpattern decoded data */
|
||||
protected $correctpattern = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param stdClass $result a h5pactivity_attempts_results record
|
||||
*/
|
||||
protected function __construct(stdClass $result) {
|
||||
$this->result = $result;
|
||||
if (empty($result->additionals)) {
|
||||
$this->additionals = new stdClass();
|
||||
} else {
|
||||
$this->additionals = json_decode($result->additionals);
|
||||
}
|
||||
$this->response = $this->decode_response($result->response);
|
||||
if (!empty($result->correctpattern)) {
|
||||
$correctpattern = json_decode($result->correctpattern);
|
||||
foreach ($correctpattern as $pattern) {
|
||||
$this->correctpattern[] = $this->decode_response($pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the correct result output depending on the interactiontype
|
||||
*
|
||||
* @param stdClass $result h5pactivity_attempts_results record
|
||||
* @return result|null the result output class if any
|
||||
*/
|
||||
public static function create_from_record(stdClass $result): ?self {
|
||||
// Compound result track is omitted from the report.
|
||||
if ($result->interactiontype == 'compound') {
|
||||
return null;
|
||||
}
|
||||
$classname = "mod_h5pactivity\\output\\result\\{$result->interactiontype}";
|
||||
$classname = str_replace('-', '', $classname);
|
||||
if (class_exists($classname)) {
|
||||
return new $classname($result);
|
||||
}
|
||||
return new self($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a decoded response structure.
|
||||
*
|
||||
* @param string $value the current response structure
|
||||
* @return array an array of reponses
|
||||
*/
|
||||
private function decode_response(string $value): array {
|
||||
// If [,] means a list of elements.
|
||||
$list = explode('[,]', $value);
|
||||
// Inside a list element [.] means sublist (pair) and [:] a range.
|
||||
foreach ($list as $key => $item) {
|
||||
if (strpos($item, '[.]') !== false) {
|
||||
$list[$key] = explode('[.]', $item);
|
||||
} else if (strpos($item, '[:]') !== false) {
|
||||
$list[$key] = explode('[:]', $item);
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export this data so it can be used as the context for a mustache template.
|
||||
*
|
||||
* @param renderer_base $output
|
||||
* @return stdClass
|
||||
*/
|
||||
public function export_for_template(renderer_base $output): stdClass {
|
||||
$result = $this->result;
|
||||
|
||||
$data = (object)[
|
||||
'id' => $result->id,
|
||||
'attemptid' => $result->attemptid,
|
||||
'subcontent' => $result->subcontent,
|
||||
'timecreated' => $result->timecreated,
|
||||
'interactiontype' => $result->interactiontype,
|
||||
'description' => format_string($result->description),
|
||||
'rawscore' => $result->rawscore,
|
||||
'maxscore' => $result->maxscore,
|
||||
'duration' => $result->duration,
|
||||
'completion' => $result->completion,
|
||||
'success' => $result->success,
|
||||
];
|
||||
$result;
|
||||
|
||||
$options = $this->export_options();
|
||||
|
||||
if (!empty($options)) {
|
||||
$data->hasoptions = true;
|
||||
$data->optionslabel = $this->get_optionslabel();
|
||||
$data->correctlabel = $this->get_correctlabel();
|
||||
$data->answerlabel = $this->get_answerlabel();
|
||||
$data->options = array_values($options);
|
||||
$data->track = true;
|
||||
}
|
||||
|
||||
if (!empty($result->maxscore)) {
|
||||
$data->score = get_string('score_out_of', 'mod_h5pactivity', $result);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the options data structure.
|
||||
*
|
||||
* Result types have to override this method generate a specific options report.
|
||||
*
|
||||
* An option is an object with:
|
||||
* - id: the option ID
|
||||
* - description: option description text
|
||||
* - useranswer (optional): what the user answer (see get_answer method)
|
||||
* - correctanswer (optional): the correct answer (see get_answer method)
|
||||
*
|
||||
* @return array of options
|
||||
*/
|
||||
protected function export_options(): ?array {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a label for result user options/choices.
|
||||
*
|
||||
* Specific result types can override this method to customize
|
||||
* the result options table header.
|
||||
*
|
||||
* @return string to use in options table
|
||||
*/
|
||||
protected function get_optionslabel(): string {
|
||||
return get_string('choice', 'mod_h5pactivity');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a label for result user correct answer.
|
||||
*
|
||||
* Specific result types can override this method to customize
|
||||
* the result options table header.
|
||||
*
|
||||
* @return string to use in options table
|
||||
*/
|
||||
protected function get_correctlabel(): string {
|
||||
return get_string('correct_answer', 'mod_h5pactivity');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a label for result user attempt answer.
|
||||
*
|
||||
* Specific result types can override this method to customize
|
||||
* the result options table header.
|
||||
*
|
||||
* @return string to use in options table
|
||||
*/
|
||||
protected function get_answerlabel(): string {
|
||||
return get_string('attempt_answer', 'mod_h5pactivity');
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract descriptions from array.
|
||||
*
|
||||
* @param array $data additional attribute to parse
|
||||
* @return string[] the resulting strings
|
||||
*/
|
||||
protected function get_descriptions(array $data): array {
|
||||
$result = [];
|
||||
foreach ($data as $key => $value) {
|
||||
$description = $this->get_description($value);
|
||||
$index = $value->id ?? $key;
|
||||
$index = trim($index);
|
||||
if (is_numeric($index)) {
|
||||
$index = intval($index);
|
||||
}
|
||||
$result[$index] = (object)['description' => $description, 'id' => $index];
|
||||
}
|
||||
ksort($result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract description from data element.
|
||||
*
|
||||
* @param stdClass $data additional attribute to parse
|
||||
* @return string the resulting string
|
||||
*/
|
||||
protected function get_description(stdClass $data): string {
|
||||
if (!isset($data->description)) {
|
||||
return '';
|
||||
}
|
||||
$translations = (array) $data->description;
|
||||
if (empty($translations)) {
|
||||
return '';
|
||||
}
|
||||
// By default, H5P packages only send "en-US" descriptions.
|
||||
$result = $translations['en-US'] ?? array_shift($translations);
|
||||
return trim($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an answer data to show results.
|
||||
*
|
||||
* @param int $state the answer state
|
||||
* @param string $answer the extra text to display (default null)
|
||||
* @return stdClass with "answer" text and the state attribute to be displayed
|
||||
*/
|
||||
protected function get_answer(int $state, string $answer = null): stdClass {
|
||||
$states = [
|
||||
self::CORRECT => 'correct',
|
||||
self::INCORRECT => 'incorrect',
|
||||
self::CHECKED => 'checked',
|
||||
self::UNCHECKED => 'unchecked',
|
||||
self::PASS => 'pass',
|
||||
self::FAIL => 'fail',
|
||||
self::UNKNOWN => 'unkown',
|
||||
self::TEXT => 'text',
|
||||
];
|
||||
$state = $states[$state] ?? self::UNKNOWN;
|
||||
if ($answer === null) {
|
||||
$answer = get_string('answer_'.$state, 'mod_h5pactivity');
|
||||
}
|
||||
$result = (object)[
|
||||
'answer' => $answer,
|
||||
$state => true,
|
||||
];
|
||||
return $result;
|
||||
}
|
||||
}
|
101
mod/h5pactivity/classes/output/result/choice.php
Normal file
101
mod/h5pactivity/classes/output/result/choice.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class mod_h5pactivity\output\result\choice
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\output\result;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_h5pactivity\output\result;
|
||||
use renderer_base;
|
||||
|
||||
/**
|
||||
* Class to display H5P choice result.
|
||||
*
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class choice extends result {
|
||||
|
||||
/**
|
||||
* Return the options data structure.
|
||||
*
|
||||
* @return array of options
|
||||
*/
|
||||
protected function export_options(): ?array {
|
||||
|
||||
// Suppose H5P choices have only a single list of valid answers.
|
||||
$correctpattern = reset($this->correctpattern);
|
||||
if (empty($correctpattern)) {
|
||||
$correctpattern = [];
|
||||
}
|
||||
|
||||
$additionals = $this->additionals;
|
||||
|
||||
// H5P has a special extension for long choices.
|
||||
$extensions = (array) $additionals->extensions ?? [];
|
||||
$filter = isset($extensions['https://h5p.org/x-api/line-breaks']) ? true : false;
|
||||
|
||||
if (isset($additionals->choices)) {
|
||||
$options = $this->get_descriptions($additionals->choices);
|
||||
} else {
|
||||
$options = [];
|
||||
}
|
||||
|
||||
// Some H5P activities like Find the Words don't user the standard CMI format delimiter
|
||||
// and don't use propper choice additionals. In those cases the report needs to fix this
|
||||
// using the correct pattern as choices and using a non standard delimiter.
|
||||
if (empty($options)) {
|
||||
if (count($correctpattern) == 1) {
|
||||
$correctpattern = explode(',', reset($correctpattern));
|
||||
}
|
||||
foreach ($correctpattern as $value) {
|
||||
$option = (object)[
|
||||
'id' => $value,
|
||||
'description' => $value,
|
||||
];
|
||||
$options[$value] = $option;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($options as $key => $value) {
|
||||
$correctstate = (in_array($key, $correctpattern)) ? parent::CHECKED : parent::UNCHECKED;
|
||||
if (in_array($key, $this->response)) {
|
||||
$answerstate = ($correctstate == parent::CHECKED) ? parent::PASS : parent::FAIL;
|
||||
// In some cases, like Branching scenario H5P activity, no correct Pattern is provided
|
||||
// so any answer is just a check.
|
||||
if (empty($correctpattern)) {
|
||||
$answerstate = parent::CHECKED;
|
||||
}
|
||||
$value->useranswer = $this->get_answer($answerstate);
|
||||
}
|
||||
$value->correctanswer = $this->get_answer($correctstate);
|
||||
|
||||
if ($filter && $correctstate == parent::UNCHECKED && !isset($value->useranswer)) {
|
||||
unset($options[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
139
mod/h5pactivity/classes/output/result/fillin.php
Normal file
139
mod/h5pactivity/classes/output/result/fillin.php
Normal file
@ -0,0 +1,139 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class mod_h5pactivity\output\result\fillin
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\output\result;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_h5pactivity\output\result;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Class to display H5P fill-in result.
|
||||
*
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class fillin extends result {
|
||||
|
||||
/**
|
||||
* Export this data so it can be used as the context for a mustache template.
|
||||
*
|
||||
* @param renderer_base $output
|
||||
* @return stdClass
|
||||
*/
|
||||
public function export_for_template(renderer_base $output): stdClass {
|
||||
$data = parent::export_for_template($output);
|
||||
$data->content = $this->result->description;
|
||||
$data->description = get_string('result_fill-in', 'mod_h5pactivity');
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the options data structure.
|
||||
*
|
||||
* @return array of options
|
||||
*/
|
||||
protected function export_options(): ?array {
|
||||
|
||||
$correctpatterns = $this->correctpattern;
|
||||
|
||||
$additionals = $this->additionals;
|
||||
|
||||
$extensions = (array) $additionals->extensions ?? [];
|
||||
|
||||
// There are two way in which H5P could force case sensitivity, with extensions
|
||||
// or using options in the correctpatterns. By default it is case sensible.
|
||||
$casesensitive = $extensions['https://h5p.org/x-api/case-sensitivity'] ?? true;
|
||||
if (!empty($this->result->correctpattern) && strpos($this->result->correctpattern, '{case_matters=false}') !== null) {
|
||||
$casesensitive = false;
|
||||
}
|
||||
|
||||
$values = [];
|
||||
// Add all possibilities from $additionals.
|
||||
if (isset($extensions['https://h5p.org/x-api/alternatives'])) {
|
||||
foreach ($extensions['https://h5p.org/x-api/alternatives'] as $key => $value) {
|
||||
if (!is_array($value)) {
|
||||
$value = [$value];
|
||||
}
|
||||
$values[$key] = ($casesensitive) ? $value : array_change_key_case($value);
|
||||
}
|
||||
}
|
||||
// Add possibilities from correctpattern.
|
||||
foreach ($correctpatterns as $correctpattern) {
|
||||
foreach ($correctpattern as $key => $pattern) {
|
||||
// The xAPI admits more params a part form values.
|
||||
// For now this extra information is not used in reporting
|
||||
// but it is posible future H5P types need them.
|
||||
$value = preg_replace('/\{.+=.*\}/', '', $pattern);
|
||||
$value = ($casesensitive) ? $value : strtolower($value);
|
||||
if (!isset($values[$key])) {
|
||||
$values[$key] = [];
|
||||
}
|
||||
if (!in_array($value, $values[$key])) {
|
||||
array_unshift($values[$key], $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate options.
|
||||
$options = [];
|
||||
$num = 1;
|
||||
foreach ($values as $key => $value) {
|
||||
$option = (object)[
|
||||
'id' => $key,
|
||||
'description' => get_string('result_fill-in_gap', 'mod_h5pactivity', $num),
|
||||
];
|
||||
|
||||
$gapresponse = $this->response[$key] ?? null;
|
||||
$gapresponse = ($casesensitive) ? $gapresponse : strtolower($gapresponse);
|
||||
if ($gapresponse !== null && in_array($gapresponse, $value)) {
|
||||
$state = parent::CORRECT;
|
||||
} else {
|
||||
$state = parent::INCORRECT;
|
||||
}
|
||||
$option->useranswer = $this->get_answer($state, $gapresponse);
|
||||
|
||||
$option->correctanswer = $this->get_answer(parent::TEXT, implode(' / ', $value));
|
||||
|
||||
$options[] = $option;
|
||||
$num++;
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a label for result user options/choices
|
||||
*
|
||||
* Specific result types can override this method to customize
|
||||
* the result options table header.
|
||||
*
|
||||
* @return string to use in options table
|
||||
*/
|
||||
protected function get_optionslabel(): string {
|
||||
return get_string('result_matching', 'mod_h5pactivity');
|
||||
}
|
||||
}
|
53
mod/h5pactivity/classes/output/result/longfillin.php
Normal file
53
mod/h5pactivity/classes/output/result/longfillin.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class mod_h5pactivity\output\result\longfillin
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\output\result;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_h5pactivity\output\result;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Class to display H5P long fill in result.
|
||||
*
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class longfillin extends result {
|
||||
|
||||
/**
|
||||
* Export this data so it can be used as the context for a mustache template.
|
||||
*
|
||||
* @param renderer_base $output
|
||||
* @return stdClass
|
||||
*/
|
||||
public function export_for_template(renderer_base $output): stdClass {
|
||||
$data = parent::export_for_template($output);
|
||||
$data->content = reset($this->response);
|
||||
$data->track = true;
|
||||
return $data;
|
||||
}
|
||||
}
|
126
mod/h5pactivity/classes/output/result/matching.php
Normal file
126
mod/h5pactivity/classes/output/result/matching.php
Normal file
@ -0,0 +1,126 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class mod_h5pactivity\output\result\matching
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\output\result;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_h5pactivity\output\result;
|
||||
use renderer_base;
|
||||
|
||||
/**
|
||||
* Class to display H5P matching result.
|
||||
*
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class matching extends result {
|
||||
|
||||
/**
|
||||
* Return the options data structure.
|
||||
*
|
||||
* @return array of options
|
||||
*/
|
||||
protected function export_options(): ?array {
|
||||
// Suppose H5P choices have only list of valid answers.
|
||||
$correctpattern = reset($this->correctpattern);
|
||||
|
||||
$additionals = $this->additionals;
|
||||
|
||||
// Get sources (options).
|
||||
if (isset($additionals->source)) {
|
||||
$options = $this->get_descriptions($additionals->source);
|
||||
} else {
|
||||
$options = [];
|
||||
}
|
||||
|
||||
// Get targets.
|
||||
if (isset($additionals->target)) {
|
||||
$targets = $this->get_descriptions($additionals->target);
|
||||
} else {
|
||||
$targets = [];
|
||||
}
|
||||
|
||||
// Correct answers.
|
||||
foreach ($correctpattern as $pattern) {
|
||||
if (!is_array($pattern) || count($pattern) != 2) {
|
||||
continue;
|
||||
}
|
||||
// One pattern must be from options and the other from targets.
|
||||
if (isset($options[$pattern[0]]) && isset($targets[$pattern[1]])) {
|
||||
$option = $options[$pattern[0]];
|
||||
$target = $targets[$pattern[1]];
|
||||
} else if (isset($targets[$pattern[0]]) && isset($options[$pattern[1]])) {
|
||||
$option = $options[$pattern[1]];
|
||||
$target = $targets[$pattern[0]];
|
||||
} else {
|
||||
$option = null;
|
||||
}
|
||||
if ($option) {
|
||||
$option->correctanswer = $this->get_answer(parent::TEXT, $target->description);
|
||||
$option->correctanswerid = $target->id;
|
||||
}
|
||||
}
|
||||
|
||||
// User responses.
|
||||
foreach ($this->response as $response) {
|
||||
if (!is_array($response) || count($response) != 2) {
|
||||
continue;
|
||||
}
|
||||
// One repsonse must be from options and the other from targets.
|
||||
if (isset($options[$response[0]]) && isset($targets[$response[1]])) {
|
||||
$option = $options[$response[0]];
|
||||
$target = $targets[$response[1]];
|
||||
$answer = $response[1];
|
||||
} else if (isset($targets[$response[0]]) && isset($options[$response[1]])) {
|
||||
$option = $options[$response[1]];
|
||||
$target = $targets[$response[0]];
|
||||
$answer = $response[0];
|
||||
} else {
|
||||
$option = null;
|
||||
}
|
||||
if ($option) {
|
||||
if (isset($option->correctanswerid) && $option->correctanswerid == $answer) {
|
||||
$state = parent::CORRECT;
|
||||
} else {
|
||||
$state = parent::INCORRECT;
|
||||
}
|
||||
$option->useranswer = $this->get_answer($state, $target->description);
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a label for result user options/choices
|
||||
*
|
||||
* Specific result types can override this method to customize
|
||||
* the result options table header.
|
||||
*
|
||||
* @return string to use in options table
|
||||
*/
|
||||
protected function get_optionslabel(): string {
|
||||
return get_string('result_matching', 'mod_h5pactivity');
|
||||
}
|
||||
}
|
54
mod/h5pactivity/classes/output/result/other.php
Normal file
54
mod/h5pactivity/classes/output/result/other.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class mod_h5pactivity\output\result\other
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\output\result;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_h5pactivity\output\result;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Class to display H5P other result.
|
||||
*
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class other extends result {
|
||||
|
||||
/**
|
||||
* Export this data so it can be used as the context for a mustache template.
|
||||
*
|
||||
* @param renderer_base $output
|
||||
* @return stdClass
|
||||
*/
|
||||
public function export_for_template(renderer_base $output): stdClass {
|
||||
$data = parent::export_for_template($output);
|
||||
if (empty($data->description)) {
|
||||
$data->description = get_string('result_other', 'mod_h5pactivity');
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
101
mod/h5pactivity/classes/output/result/sequencing.php
Normal file
101
mod/h5pactivity/classes/output/result/sequencing.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class mod_h5pactivity\output\result\sequencing
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\output\result;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_h5pactivity\output\result;
|
||||
use renderer_base;
|
||||
|
||||
/**
|
||||
* Class to display H5P sequencing result.
|
||||
*
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class sequencing extends result {
|
||||
|
||||
/**
|
||||
* Return the options data structure.
|
||||
*
|
||||
* @return array of options
|
||||
*/
|
||||
protected function export_options(): ?array {
|
||||
|
||||
$correctpattern = reset($this->correctpattern);
|
||||
|
||||
$additionals = $this->additionals;
|
||||
|
||||
$response = $this->response;
|
||||
|
||||
if (isset($additionals->choices)) {
|
||||
$choices = $this->get_descriptions($additionals->choices);
|
||||
} else {
|
||||
$choices = [];
|
||||
}
|
||||
|
||||
$options = [];
|
||||
$num = 1;
|
||||
foreach ($correctpattern as $key => $pattern) {
|
||||
if (!isset($choices[$pattern])) {
|
||||
continue;
|
||||
}
|
||||
$option = (object)[
|
||||
'id' => true,
|
||||
'description' => get_string('result_sequencing_position', 'mod_h5pactivity', $num),
|
||||
'correctanswer' => $this->get_answer(parent::TEXT, $choices[$pattern]->description),
|
||||
'correctanswerid' => 'item_'.$key,
|
||||
];
|
||||
if (isset($response[$key])) {
|
||||
$answerstate = ($response[$key] == $option->correctanswerid) ? parent::PASS : parent::FAIL;
|
||||
} else {
|
||||
$answerstate = parent::FAIL;
|
||||
}
|
||||
$option->useranswer = $this->get_answer($answerstate);
|
||||
|
||||
$options[$key] = $option;
|
||||
$num ++;
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a label for result user options/choices.
|
||||
*
|
||||
* @return string to use in options table
|
||||
*/
|
||||
protected function get_optionslabel(): string {
|
||||
return get_string('result_sequencing_choice', 'mod_h5pactivity');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a label for result user correct answer.
|
||||
*
|
||||
* @return string to use in options table
|
||||
*/
|
||||
protected function get_correctlabel(): string {
|
||||
return get_string('result_sequencing_answer', 'mod_h5pactivity');
|
||||
}
|
||||
}
|
76
mod/h5pactivity/classes/output/result/truefalse.php
Normal file
76
mod/h5pactivity/classes/output/result/truefalse.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Contains class mod_h5pactivity\output\result\truefalse
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\output\result;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use mod_h5pactivity\output\result;
|
||||
use renderer_base;
|
||||
|
||||
/**
|
||||
* Class to display H5P choice result.
|
||||
*
|
||||
* @copyright 2020 Ferran Recio
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class truefalse extends result {
|
||||
|
||||
/**
|
||||
* Return the options data structure.
|
||||
*
|
||||
* @return array of options
|
||||
*/
|
||||
protected function export_options(): ?array {
|
||||
|
||||
// This interaction type have only one entry which is the correct option.
|
||||
$correctpattern = reset($this->correctpattern);
|
||||
$correctpattern = filter_var(reset($correctpattern), FILTER_VALIDATE_BOOLEAN);
|
||||
|
||||
$response = filter_var(reset($this->response), FILTER_VALIDATE_BOOLEAN);
|
||||
|
||||
$options = [
|
||||
(object)[
|
||||
'id' => true,
|
||||
'description' => get_string('true', 'mod_h5pactivity'),
|
||||
],
|
||||
(object)[
|
||||
'id' => false,
|
||||
'description' => get_string('false', 'mod_h5pactivity'),
|
||||
],
|
||||
];
|
||||
foreach ($options as $value) {
|
||||
$correctstate = ($value->id == $correctpattern) ? parent::CHECKED : parent::UNCHECKED;
|
||||
|
||||
if ($value->id == $response) {
|
||||
$answerstate = ($correctstate == parent::CHECKED) ? parent::PASS : parent::FAIL;
|
||||
$value->useranswer = $this->get_answer($answerstate);
|
||||
}
|
||||
|
||||
$value->correctanswer = $this->get_answer($correctstate);
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
@ -56,4 +56,15 @@ $capabilities = [
|
||||
'student' => CAP_ALLOW
|
||||
],
|
||||
],
|
||||
|
||||
'mod/h5pactivity:reviewattempts' => array(
|
||||
'captype' => 'read',
|
||||
'contextlevel' => CONTEXT_MODULE,
|
||||
'archetypes' => array(
|
||||
'teacher' => CAP_ALLOW,
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'manager' => CAP_ALLOW
|
||||
),
|
||||
'clonepermissionsfrom' => 'moodle/grade:manage'
|
||||
),
|
||||
];
|
||||
|
@ -17,6 +17,7 @@
|
||||
<FIELD NAME="displayoptions" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="H5P Button display options"/>
|
||||
<FIELD NAME="enabletracking" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="1" SEQUENCE="false" COMMENT="Enable xAPI tracking"/>
|
||||
<FIELD NAME="grademethod" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="1" SEQUENCE="false" COMMENT="Which H5P attempt is used for grading"/>
|
||||
<FIELD NAME="reviewmode" TYPE="int" LENGTH="4" NOTNULL="false" DEFAULT="1" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
|
@ -225,5 +225,20 @@ function xmldb_h5pactivity_upgrade($oldversion) {
|
||||
upgrade_mod_savepoint(true, 2020041401, 'h5pactivity');
|
||||
}
|
||||
|
||||
if ($oldversion < 2020042202) {
|
||||
|
||||
// Define field reviewmode to be added to h5pactivity.
|
||||
$table = new xmldb_table('h5pactivity');
|
||||
$field = new xmldb_field('reviewmode', XMLDB_TYPE_INTEGER, '4', null, null, null, '1', 'grademethod');
|
||||
|
||||
// Conditionally launch add field reviewmode.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// H5pactivity savepoint reached.
|
||||
upgrade_mod_savepoint(true, 2020042202, 'h5pactivity');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -23,6 +23,8 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use mod_h5pactivity\local\manager;
|
||||
|
||||
require(__DIR__.'/../../config.php');
|
||||
|
||||
// Course module ID.
|
||||
@ -34,9 +36,27 @@ $itemnumber = optional_param('itemnumber', 0, PARAM_INT);
|
||||
// Graded user ID (optional).
|
||||
$userid = optional_param('userid', 0, PARAM_INT);
|
||||
|
||||
require_login();
|
||||
list ($course, $cm) = get_course_and_cm_from_cmid($id, 'h5pactivity');
|
||||
|
||||
// TODO: in the near future this file will redirect to a specific user H5P attempts page.
|
||||
require_login($course, true, $cm);
|
||||
|
||||
// In the simplest case just redirect to the view page.
|
||||
redirect('view.php?id='.$id);
|
||||
$manager = manager::create_from_coursemodule($cm);
|
||||
|
||||
if (!$manager->can_view_all_attempts() && !$manager->can_view_own_attempts()) {
|
||||
redirect(new moodle_url('/mod/h5pactivity/view.php', ['id' => $id]));
|
||||
}
|
||||
|
||||
$moduleinstance = $manager->get_instance();
|
||||
|
||||
$params = [
|
||||
'a' => $moduleinstance->id,
|
||||
'userid' => $userid,
|
||||
];
|
||||
|
||||
$scores = $manager->get_users_scaled_score($userid);
|
||||
$score = $scores[$userid] ?? null;
|
||||
if (!empty($score->attemptid)) {
|
||||
$params['attemptid'] = $score->attemptid;
|
||||
}
|
||||
|
||||
redirect(new moodle_url('/mod/h5pactivity/report.php', $params));
|
||||
|
@ -25,14 +25,42 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['all_attempts'] = 'All user attempts';
|
||||
$string['answer_checked'] = 'Answer checked';
|
||||
$string['answer_correct'] = 'Your answer is correct';
|
||||
$string['answer_fail'] = 'Incorrect answer';
|
||||
$string['answer_incorrect'] = 'Your answer is incorrect';
|
||||
$string['answer_pass'] = 'Correct answer';
|
||||
$string['answer_unchecked'] = 'Answer unchecked';
|
||||
$string['answer_unknown'] = 'Unkown answer';
|
||||
$string['answer_text'] = 'Answer text';
|
||||
$string['areapackage'] = 'Package file';
|
||||
$string['attempt'] = 'Attempt';
|
||||
$string['attempt_average'] = 'Attempts average scored';
|
||||
$string['attempt_answer'] = 'Attempt answer';
|
||||
$string['attempt_completion_no'] = 'This attempt is not marked as completed';
|
||||
$string['attempt_completion_yes'] = 'This attempt is completed';
|
||||
$string['attempt_first'] = 'First attempt';
|
||||
$string['attempt_highest'] = 'Highest score attempt';
|
||||
$string['attempt_last'] = 'Last attempt';
|
||||
$string['attempt_none'] = 'No attempts are used for grading';
|
||||
$string['attempt_number'] = 'Attempt #{$a}';
|
||||
$string['attempt_success_fail'] = 'Fail';
|
||||
$string['attempt_success_pass'] = 'Pass';
|
||||
$string['attempt_success_unknown'] = 'Not reported';
|
||||
$string['attempts'] = 'Attempts';
|
||||
$string['attempts_report'] = 'Attempts report';
|
||||
$string['attempts_none'] = 'This user has no attempts to display.';
|
||||
$string['choice'] = 'Choice';
|
||||
$string['completion'] = 'Completion';
|
||||
$string['correct_answer'] = 'Correct answer';
|
||||
$string['deleteallattempts'] = 'Delete all H5P attempts';
|
||||
$string['displayexport'] = 'Allow download';
|
||||
$string['displayembed'] = 'Embed button';
|
||||
$string['displaycopyright'] = 'Copyright button';
|
||||
$string['duration'] = 'Duration';
|
||||
$string['enabletracking'] = 'Enable attempt tracking';
|
||||
$string['false'] = 'False';
|
||||
$string['grade_grademethod'] = 'Grading method';
|
||||
$string['grade_grademethod_help'] = 'When using point grading, the following methods are available for calculating the final grade:
|
||||
|
||||
@ -47,6 +75,7 @@ $string['grade_average_attempt'] = 'Average grade';
|
||||
$string['grade_last_attempt'] = 'Last attempt';
|
||||
$string['grade_first_attempt'] = 'First attempt';
|
||||
$string['h5pactivity:addinstance'] = 'Add a new H5P';
|
||||
$string['h5pactivity:reviewattempts'] = 'Review H5P attempts';
|
||||
$string['h5pactivity:submit'] = 'Submit H5P attempts';
|
||||
$string['h5pactivity:view'] = 'View H5P';
|
||||
$string['h5pactivityfieldset'] = 'H5P settings';
|
||||
@ -54,6 +83,7 @@ $string['h5pactivityname'] = 'H5P';
|
||||
$string['h5pactivitysettings'] = 'Settings';
|
||||
$string['h5pattempts'] = 'Attempt options';
|
||||
$string['h5pdisplay'] = 'H5P options';
|
||||
$string['maxscore'] = 'Max score';
|
||||
$string['modulename'] = 'H5P';
|
||||
$string['modulename_help'] = 'H5P is an abbreviation for HTML5 Package - interactive content such as presentations, videos and other multimedia, questions, quizzes, games and more. The H5P activity enables H5P to be uploaded and added to a course.
|
||||
|
||||
@ -61,6 +91,10 @@ Any question attempts are marked automatically, and the grade is recorded in the
|
||||
$string['modulename_link'] = 'mod/h5pactivity/view';
|
||||
$string['modulenameplural'] = 'H5P';
|
||||
$string['myattempts'] = 'My attempts';
|
||||
$string['no_compatible_track'] = 'This interaction ({$a}) does not provide tracking information or the tracking
|
||||
provided is not compatible with the current activity version.';
|
||||
$string['noparticipants'] = 'No participants to display';
|
||||
$string['outcome'] = 'Outcome';
|
||||
$string['package'] = 'Package file';
|
||||
$string['package_help'] = 'The package file is a h5p file containing H5P interactive content.';
|
||||
$string['page-mod-h5pactivity-x'] = 'Any H5P module page';
|
||||
@ -74,6 +108,27 @@ $string['privacy:metadata:timemodified'] = 'The last time element was tracked';
|
||||
$string['privacy:metadata:userid'] = 'The ID of the user who accessed the H5P activity';
|
||||
$string['privacy:metadata:xapi_track'] = 'Attempt tracking information';
|
||||
$string['privacy:metadata:xapi_track_results'] = 'Attempt results tracking information';
|
||||
$string['report_viewed'] = 'Report viewed';
|
||||
$string['result_compound'] = 'Combined partial score';
|
||||
$string['result_fill-in'] = 'Fill-in text';
|
||||
$string['result_fill-in_gap'] = 'Gap #{$a}';
|
||||
$string['result_matching'] = 'Matching choice';
|
||||
$string['result_other'] = 'Unkown interaction type';
|
||||
$string['result_sequencing_choice'] = 'Positions';
|
||||
$string['result_sequencing_answer'] = 'Position value';
|
||||
$string['result_sequencing_position'] = '#{$a}';
|
||||
$string['review_all_attempts'] = 'View all attempts ({$a} submitted)';
|
||||
$string['review_mode'] = 'Review attempts';
|
||||
$string['review_my_attempts'] = 'View my attempts';
|
||||
$string['review_user_attempts'] = 'View user attempts ({$a})';
|
||||
$string['review_none'] = 'Participants cannot review their own attempts';
|
||||
$string['review_on_completion'] = 'Participants can review their own attempts';
|
||||
$string['score'] = 'Score';
|
||||
$string['score_out_of'] = '{$a->rawscore} out of {$a->maxscore}';
|
||||
$string['startdate'] = 'Start date';
|
||||
$string['statement_received'] = 'xAPI statement received';
|
||||
$string['totalscore'] = 'Total score';
|
||||
$string['tracking_messages'] = 'Some H5P provide attempt tracking data for advanced reporting such as number of attempts, responses and grades. Note: Some H5P don\'t provide attempt tracking data. In such cases, the following settings will have no effect.';
|
||||
$string['true'] = 'True';
|
||||
$string['view'] = 'View';
|
||||
$string['view_report'] = 'View report';
|
||||
|
@ -104,6 +104,11 @@ class mod_h5pactivity_mod_form extends moodleform_mod {
|
||||
$mform->disabledIf('grademethod', 'grade[modgrade_type]', 'neq', 'point');
|
||||
$mform->addHelpButton('grademethod', 'grade_grademethod', 'mod_h5pactivity');
|
||||
|
||||
$options = manager::get_review_modes();
|
||||
$mform->addElement('select', 'reviewmode', get_string('review_mode', 'mod_h5pactivity'), $options);
|
||||
$mform->setType('reviewmode', PARAM_INT);
|
||||
$mform->hideIf('reviewmode', 'enabletracking', 'notchecked');
|
||||
|
||||
// Add standard elements.
|
||||
$this->standard_coursemodule_elements();
|
||||
|
||||
|
130
mod/h5pactivity/report.php
Normal file
130
mod/h5pactivity/report.php
Normal file
@ -0,0 +1,130 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Prints an instance of mod_h5pactivity.
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use mod_h5pactivity\local\manager;
|
||||
use mod_h5pactivity\event\report_viewed;
|
||||
|
||||
require(__DIR__.'/../../config.php');
|
||||
require_once(__DIR__.'/lib.php');
|
||||
|
||||
$userid = optional_param('userid', null, PARAM_INT);
|
||||
$attemptid = optional_param('attemptid', null, PARAM_INT);
|
||||
|
||||
// Attempts have only the instance id information but system events
|
||||
// have only cmid. To prevent unnecesary db queries, this page accept both.
|
||||
$id = optional_param('id', null, PARAM_INT);
|
||||
if (empty($id)) {
|
||||
$a = required_param('a', PARAM_INT);
|
||||
list ($course, $cm) = get_course_and_cm_from_instance($a, 'h5pactivity');
|
||||
} else {
|
||||
list ($course, $cm) = get_course_and_cm_from_cmid($id, 'h5pactivity');
|
||||
}
|
||||
|
||||
require_login($course, true, $cm);
|
||||
|
||||
$manager = manager::create_from_coursemodule($cm);
|
||||
|
||||
$report = $manager->get_report($userid, $attemptid);
|
||||
if (!$report) {
|
||||
print_error('permissiondenied');
|
||||
}
|
||||
|
||||
$user = $report->get_user();
|
||||
$attempt = $report->get_attempt();
|
||||
|
||||
$moduleinstance = $manager->get_instance();
|
||||
|
||||
$context = $manager->get_context();
|
||||
|
||||
$params = ['a' => $cm->instance];
|
||||
if ($user) {
|
||||
$params['userid'] = $user->id;
|
||||
}
|
||||
if ($attempt) {
|
||||
$params['attemptid'] = $attempt->get_id();
|
||||
}
|
||||
$PAGE->set_url('/mod/h5pactivity/report.php', $params);
|
||||
|
||||
// Trigger event.
|
||||
$other = [
|
||||
'instanceid' => $params['a'],
|
||||
'userid' => $params['userid'] ?? null,
|
||||
'attemptid' => $params['attemptid'] ?? null,
|
||||
];
|
||||
$event = report_viewed::create([
|
||||
'objectid' => $moduleinstance->id,
|
||||
'context' => $context,
|
||||
'other' => $other,
|
||||
]);
|
||||
$event->add_record_snapshot('course', $course);
|
||||
$event->add_record_snapshot('h5pactivity', $moduleinstance);
|
||||
$event->trigger();
|
||||
|
||||
$shortname = format_string($course->shortname, true, ['context' => $context]);
|
||||
$pagetitle = strip_tags($shortname.': '.format_string($moduleinstance->name));
|
||||
$PAGE->set_title(format_string($pagetitle));
|
||||
|
||||
$navbar = [];
|
||||
if ($manager->can_view_all_attempts()) {
|
||||
// Report navbar have 3 levels for teachers:
|
||||
// - Participants list
|
||||
// - Participant attempts list
|
||||
// - Individual attempt details.
|
||||
$nav = [get_string('attempts', 'mod_h5pactivity'), null];
|
||||
if ($user) {
|
||||
$nav[1] = new moodle_url('/mod/h5pactivity/report.php', ['a' => $cm->instance]);
|
||||
$navbar[] = $nav;
|
||||
|
||||
$nav = [fullname($user), null];
|
||||
if ($attempt) {
|
||||
$nav[1] = new moodle_url('/mod/h5pactivity/report.php', ['a' => $cm->instance, 'userid' => $user->id]);
|
||||
}
|
||||
}
|
||||
$navbar[] = $nav;
|
||||
} else {
|
||||
// Report navbar have 2 levels for a regular participant:
|
||||
// - My attempts
|
||||
// - Individual attempt details.
|
||||
$nav = [get_string('myattempts', 'mod_h5pactivity'), null];
|
||||
if ($attempt) {
|
||||
$nav[1] = new moodle_url('/mod/h5pactivity/report.php', ['a' => $cm->instance]);
|
||||
}
|
||||
$navbar[] = $nav;
|
||||
|
||||
}
|
||||
if ($attempt) {
|
||||
$navbar[] = [get_string('attempt_number', 'mod_h5pactivity', $attempt->get_attempt()), null];
|
||||
}
|
||||
foreach ($navbar as $nav) {
|
||||
$PAGE->navbar->add($nav[0], $nav[1]);
|
||||
}
|
||||
|
||||
$PAGE->set_heading(format_string($course->fullname));
|
||||
$PAGE->set_context($context);
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
echo $report->print();
|
||||
|
||||
echo $OUTPUT->footer();
|
96
mod/h5pactivity/templates/attempt.mustache
Normal file
96
mod/h5pactivity/templates/attempt.mustache
Normal file
@ -0,0 +1,96 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_h5pactivity/attempt
|
||||
|
||||
This template will render an attempt basic information inside a H5P activity results report.
|
||||
|
||||
Variables required for this template:
|
||||
* timemodified - Full attempts list
|
||||
* attempt - Full attempts list
|
||||
* rawscore - Full attempts list
|
||||
* maxscore - Full attempts list
|
||||
* duration - Full attempts list
|
||||
* completionicon - Full attempts list
|
||||
* successicon - Full attempts list
|
||||
* reporturl - Full attempts list
|
||||
|
||||
Variables optional for this template:
|
||||
* user - optional user record
|
||||
* scored - The scored attempt
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"id": 11,
|
||||
"h5pactivityid": 1,
|
||||
"userid": 3,
|
||||
"timecreated": 1587655101,
|
||||
"timemodified": 1587655101,
|
||||
"attempt": 2,
|
||||
"rawscore": 6,
|
||||
"maxscore": 6,
|
||||
"duration": "2 minutes 10 seconds",
|
||||
"completion": 1,
|
||||
"completionicon": "<i class=\"icon fa fa-check-circle fa-fw \" title=\"Attempt completed\" aria-label=\"Attempt completed\"><\/i>",
|
||||
"success": 1,
|
||||
"successicon": "<i class=\"icon fa fa-check-circle fa-fw \" title=\"Attempt completed successfully\" aria-label=\"Attempt completed successfully\"><\/i>",
|
||||
"scaled": 1,
|
||||
"reporturl": {},
|
||||
"score": "6 out of 6",
|
||||
"user": {
|
||||
"id": "3",
|
||||
"idnumber": "",
|
||||
"firstname": "John",
|
||||
"lastname": "Doe",
|
||||
"email": "s1@example.com",
|
||||
"institution": "Moodle HQ",
|
||||
"department": "Business",
|
||||
"address": "",
|
||||
"city": "Barcelona",
|
||||
"country": "Spain",
|
||||
"lang": "en",
|
||||
"picture": "[userpic]",
|
||||
"fullname": "User Fullname"
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
<h2 class="px-0 px-md-3">
|
||||
{{#user}}
|
||||
{{{picture}}}
|
||||
{{#str}}attempt, mod_h5pactivity{{/str}} #{{attempt}}: {{fullname}}
|
||||
{{/user}}
|
||||
{{^user}}
|
||||
{{#str}}attempt, mod_h5pactivity{{/str}} #{{attempt}}
|
||||
{{/user}}
|
||||
</h2>
|
||||
<div class="container-fluid mt-4 mb-5 px-0 px-md-3">
|
||||
<dl class="row">
|
||||
<dt class="col-12">{{#str}} startdate, mod_h5pactivity {{/str}}</dt>
|
||||
<dd class="col-12">{{#userdate}} {{timemodified}}, {{#str}} strftimedatetime, core_langconfig {{/str}} {{/userdate}}</dd>
|
||||
<dt class="col-12">{{#str}} completion, mod_h5pactivity {{/str}}</dt>
|
||||
<dd class="col-12">{{{completiontext}}}</dd>
|
||||
<dt class="col-12 text-truncate">{{#str}} duration, mod_h5pactivity {{/str}}</dt>
|
||||
<dd class="col-12">{{duration}}</dd>
|
||||
<dt class="col-12">{{#str}} outcome, mod_h5pactivity {{/str}}</dt>
|
||||
<dd class="col-12">{{{successtext}}}</dd>
|
||||
{{#score}}
|
||||
<dt class="col-12">{{#str}} totalscore, mod_h5pactivity {{/str}}</dt>
|
||||
<dd class="col-12">{{score}}</dd>
|
||||
{{/score}}
|
||||
</dl>
|
||||
</div>
|
145
mod/h5pactivity/templates/attempts.mustache
Normal file
145
mod/h5pactivity/templates/attempts.mustache
Normal file
@ -0,0 +1,145 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_h5pactivity/attempts
|
||||
|
||||
This template will render the report link inside a H5P activity.
|
||||
|
||||
Variables required for this template:
|
||||
* attempts - Full attempts list with:
|
||||
* timemodified - Attempt timemodified
|
||||
* attempt - Attempt number
|
||||
* rawscore - Attempt rawscore
|
||||
* maxscore - Attempt maxscore
|
||||
* duration - Attempt duration
|
||||
* completionicon - Completion icon HTML
|
||||
* successicon - Success icon HTML
|
||||
* reporturl - Attempt report URL
|
||||
|
||||
Variables optional for this template:
|
||||
* title - optional selected attempt name
|
||||
* scored - The scored attempt
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"attempts": [
|
||||
{
|
||||
"id": 7,
|
||||
"h5pactivityid": 1,
|
||||
"userid": 5,
|
||||
"timecreated": 1587654916,
|
||||
"timemodified": 1587654916,
|
||||
"attempt": 1,
|
||||
"rawscore": 6,
|
||||
"maxscore": 6,
|
||||
"duration": "14 seconds",
|
||||
"durationcompact": "14''",
|
||||
"completion": 1,
|
||||
"completionicon": "<i class=\"icon fa fa-check-circle fa-fw \"><\/i>",
|
||||
"success": 1,
|
||||
"successicon": "<i class=\"icon fa fa-check-circle fa-fw \"><\/i>",
|
||||
"scaled": 1,
|
||||
"reporturl": {},
|
||||
"score": "6 out of 6"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"h5pactivityid": 1,
|
||||
"userid": 5,
|
||||
"timecreated": 1587654927,
|
||||
"timemodified": 1587654927,
|
||||
"attempt": 2,
|
||||
"rawscore": 1,
|
||||
"maxscore": 6,
|
||||
"duration": "25 seconds",
|
||||
"durationcompact": "25''",
|
||||
"completion": 1,
|
||||
"completionicon": "<i class=\"icon fa fa-check-circle fa-fw \"><\/i>",
|
||||
"success": 0,
|
||||
"successicon": "<i class=\"icon fa fa-circle-o fa-fw \"><\/i>",
|
||||
"scaled": 0,
|
||||
"reporturl": {},
|
||||
"score": "1 out of 6"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"h5pactivityid": 1,
|
||||
"userid": 5,
|
||||
"timecreated": 1587654942,
|
||||
"timemodified": 1587654942,
|
||||
"attempt": 3,
|
||||
"rawscore": 3,
|
||||
"maxscore": 6,
|
||||
"duration": "40 seconds",
|
||||
"durationcompact": "40''",
|
||||
"completion": 1,
|
||||
"completionicon": "<i class=\"icon fa fa-check-circle fa-fw \"><\/i>",
|
||||
"success": 0,
|
||||
"successicon": "<i class=\"icon fa fa-circle-o fa-fw \"><\/i>",
|
||||
"scaled": 0,
|
||||
"reporturl": {},
|
||||
"score": "3 out of 6"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}}
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col">{{#str}} date {{/str}}</th>
|
||||
<th scope="col">{{#str}} score, mod_h5pactivity {{/str}}</th>
|
||||
<th scope="col" class="d-none d-md-table-cell">{{#str}} maxscore, mod_h5pactivity {{/str}}</th>
|
||||
<th scope="col" class="d-none d-sm-table-cell">{{#str}} duration, mod_h5pactivity {{/str}}</th>
|
||||
<th scope="col" class="d-none d-sm-table-cell" class="text-center">{{#str}} completion, mod_h5pactivity {{/str}}</th>
|
||||
<th scope="col" class="text-center">{{#str}} success {{/str}}</th>
|
||||
<th scope="col">{{#str}} report {{/str}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#attempts}}
|
||||
<tr>
|
||||
<th scope="row">{{attempt}}</th>
|
||||
<td>
|
||||
<span class="d-none d-lg-inline">
|
||||
{{#userdate}} {{timemodified}}, {{#str}} strftimedatetime, core_langconfig {{/str}} {{/userdate}}
|
||||
</span>
|
||||
<span class="d-inline d-lg-none">
|
||||
{{#userdate}} {{timemodified}}, {{#str}} strftimedatetimeshort, core_langconfig {{/str}} {{/userdate}}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{rawscore}}<span class="d-inline d-md-none"> / {{maxscore}}</span></td>
|
||||
<td class="d-none d-md-table-cell">{{maxscore}}</td>
|
||||
<td class="d-none d-sm-table-cell">
|
||||
<span class="d-none d-md-inline">{{duration}}</span>
|
||||
<span class="d-inline d-md-none">{{durationcompact}}</span>
|
||||
</td>
|
||||
<td class="text-center d-none d-sm-table-cell">{{{completionicon}}}</td>
|
||||
<td class="text-center">{{{successicon}}}</td>
|
||||
<td>
|
||||
<span class="d-none d-md-inline">
|
||||
<a href="{{{reporturl}}}">{{#str}} view_report, mod_h5pactivity {{/str}}</a>
|
||||
</span>
|
||||
<span class="d-inline d-md-none">
|
||||
<a href="{{{reporturl}}}">{{#str}} view {{/str}}</a>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
{{/attempts}}
|
||||
</tbody>
|
||||
</table>
|
156
mod/h5pactivity/templates/reportattempts.mustache
Normal file
156
mod/h5pactivity/templates/reportattempts.mustache
Normal file
@ -0,0 +1,156 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_h5pactivity/reportattempts
|
||||
|
||||
This template will render the report link inside a H5P activity.
|
||||
|
||||
Variables required for this template:
|
||||
* attempts - Full attempts list
|
||||
|
||||
Variables optional for this template:
|
||||
* title - optional selected attempt name
|
||||
* scored - The scored attempt
|
||||
* attemptscount - The current number of attempts
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"attempts": [
|
||||
{
|
||||
"id": 7,
|
||||
"h5pactivityid": 1,
|
||||
"userid": 5,
|
||||
"timecreated": 1587654916,
|
||||
"timemodified": 1587654916,
|
||||
"attempt": 1,
|
||||
"rawscore": 6,
|
||||
"maxscore": 6,
|
||||
"duration": "14 seconds",
|
||||
"durationcompact": "14''",
|
||||
"completion": 1,
|
||||
"completionicon": "<i class=\"icon fa fa-check-circle fa-fw \"><\/i>",
|
||||
"success": 1,
|
||||
"successicon": "<i class=\"icon fa fa-check-circle fa-fw \"><\/i>",
|
||||
"scaled": 1,
|
||||
"reporturl": {},
|
||||
"score": "6 out of 6"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"h5pactivityid": 1,
|
||||
"userid": 5,
|
||||
"timecreated": 1587654927,
|
||||
"timemodified": 1587654927,
|
||||
"attempt": 2,
|
||||
"rawscore": 1,
|
||||
"maxscore": 6,
|
||||
"duration": "25 seconds",
|
||||
"durationcompact": "25''",
|
||||
"completion": 1,
|
||||
"completionicon": "<i class=\"icon fa fa-check-circle fa-fw \"><\/i>",
|
||||
"success": 0,
|
||||
"successicon": "<i class=\"icon fa fa-circle-o fa-fw \"><\/i>",
|
||||
"scaled": 0,
|
||||
"reporturl": {},
|
||||
"score": "1 out of 6"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"h5pactivityid": 1,
|
||||
"userid": 5,
|
||||
"timecreated": 1587654942,
|
||||
"timemodified": 1587654942,
|
||||
"attempt": 3,
|
||||
"rawscore": 3,
|
||||
"maxscore": 6,
|
||||
"duration": "40 seconds",
|
||||
"durationcompact": "40''",
|
||||
"completion": 1,
|
||||
"completionicon": "<i class=\"icon fa fa-check-circle fa-fw \"><\/i>",
|
||||
"success": 0,
|
||||
"successicon": "<i class=\"icon fa fa-circle-o fa-fw \"><\/i>",
|
||||
"scaled": 0,
|
||||
"reporturl": {},
|
||||
"score": "3 out of 6"
|
||||
}
|
||||
],
|
||||
"user": {
|
||||
"id": "5",
|
||||
"auth": "manual",
|
||||
"idnumber": "",
|
||||
"firstname": "Miguel",
|
||||
"lastname": "Alonso",
|
||||
"email": "s3@example.com",
|
||||
"institution": "Moodle HQ",
|
||||
"department": "Development",
|
||||
"address": "",
|
||||
"city": "Barcelona",
|
||||
"country": "ES",
|
||||
"lang": "en",
|
||||
"picture": "[USERPIC]",
|
||||
"fullname": "Miguel Alonso"
|
||||
},
|
||||
"scored": {
|
||||
"title": "Highest score attempt",
|
||||
"attempts": [
|
||||
{
|
||||
"id": 7,
|
||||
"h5pactivityid": 1,
|
||||
"userid": 5,
|
||||
"timecreated": 1587654916,
|
||||
"timemodified": 1587654916,
|
||||
"attempt": 1,
|
||||
"rawscore": 6,
|
||||
"maxscore": 6,
|
||||
"duration": "14 seconds",
|
||||
"durationcompact": "14''",
|
||||
"completion": 1,
|
||||
"completionicon": "<i class=\"icon fa fa-check-circle fa-fw \"><\/i>",
|
||||
"success": 1,
|
||||
"successicon": "<i class=\"icon fa fa-check-circle fa-fw \"><\/i>",
|
||||
"scaled": 1,
|
||||
"reporturl": {},
|
||||
"score": "6 out of 6"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
{{#user}}
|
||||
<h2 class="mb-4">
|
||||
{{{picture}}}
|
||||
{{#title}}{{title}}{{/title}}
|
||||
{{^title}}{{#str}} attempts, mod_h5pactivity {{/str}}: {{fullname}}{{/title}}
|
||||
</h2>
|
||||
{{/user}}
|
||||
|
||||
{{#scored}}
|
||||
<h3>{{title}}</h3>
|
||||
{{>mod_h5pactivity/attempts}}
|
||||
{{/scored}}
|
||||
|
||||
<h3>{{#str}}all_attempts, mod_h5pactivity{{/str}}</h3>
|
||||
|
||||
{{^attemptscount}}
|
||||
<div class="alert alert-warning">
|
||||
{{#str}} attempts_none, mod_h5pactivity {{/str}}
|
||||
</div>
|
||||
{{/attemptscount}}
|
||||
{{#attemptscount}}
|
||||
{{>mod_h5pactivity/attempts}}
|
||||
{{/attemptscount}}
|
35
mod/h5pactivity/templates/reportlink.mustache
Normal file
35
mod/h5pactivity/templates/reportlink.mustache
Normal file
@ -0,0 +1,35 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_h5pactivity/reportlink
|
||||
|
||||
This template will render the report link inside a H5P activity.
|
||||
|
||||
Variables required for this template:
|
||||
* url - The URL to the report page
|
||||
* message - The link message
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"url": "#",
|
||||
"message": "View attempts list (3 submitted)"
|
||||
}
|
||||
|
||||
}}
|
||||
<div class="reportlink mb-3">
|
||||
<a href="{{{url}}}">{{message}}</a>
|
||||
</div>
|
85
mod/h5pactivity/templates/reportresults.mustache
Normal file
85
mod/h5pactivity/templates/reportresults.mustache
Normal file
@ -0,0 +1,85 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_h5pactivity/reportresults
|
||||
|
||||
This template will render the report results inside a H5P activity.
|
||||
|
||||
Variables required for this template:
|
||||
* attempts - Full attempts list
|
||||
|
||||
Variables optional for this template:
|
||||
* title - optional selected attempt name
|
||||
* scored - The scored attempt
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"attempt": {
|
||||
"id": 11,
|
||||
"h5pactivityid": 1,
|
||||
"userid": 3,
|
||||
"timecreated": 1587655101,
|
||||
"timemodified": 1587655101,
|
||||
"attempt": 2,
|
||||
"rawscore": 6,
|
||||
"maxscore": 6,
|
||||
"duration": "2 minutes 10 seconds",
|
||||
"completion": 1,
|
||||
"completionicon": "<i class=\"icon fa fa-check-circle fa-fw \"><\/i>",
|
||||
"success": 1,
|
||||
"successicon": "<i class=\"icon fa fa-check-circle fa-fw \"><\/i>",
|
||||
"scaled": 1,
|
||||
"reporturl": {},
|
||||
"score": "6 out of 6",
|
||||
"user": {
|
||||
"id": "3",
|
||||
"username": "s1",
|
||||
"idnumber": "",
|
||||
"firstname": "John",
|
||||
"lastname": "Doe",
|
||||
"email": "s1@example.com",
|
||||
"phone2": "",
|
||||
"institution": "Moodle HQ",
|
||||
"department": "Business",
|
||||
"picture": "[USERPIC]",
|
||||
"fullname": "John Doe"
|
||||
}
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"timecreated": "1587655101",
|
||||
"interactiontype": "other",
|
||||
"description": "Example of some results",
|
||||
"rawscore": "6",
|
||||
"maxscore": "6",
|
||||
"duration": "130",
|
||||
"completion": "1",
|
||||
"success": "1",
|
||||
"optionslabel": "Example result",
|
||||
"score": "6 out of 6",
|
||||
"content": "<p>See mod_h5pactivity result template for more examples.</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}}
|
||||
{{#attempt}}
|
||||
{{>mod_h5pactivity/attempt}}
|
||||
{{/attempt}}
|
||||
{{#results}}
|
||||
{{>mod_h5pactivity/result}}
|
||||
{{/results}}
|
119
mod/h5pactivity/templates/result.mustache
Normal file
119
mod/h5pactivity/templates/result.mustache
Normal file
@ -0,0 +1,119 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_h5pactivity/result
|
||||
|
||||
This template will render a result choices inside a H5P activity results report.
|
||||
|
||||
Variables required for this template:
|
||||
* description - Result description text
|
||||
* score - Score string (for example: 2 out of 4)
|
||||
|
||||
Variables optional for this template:
|
||||
* hasoptions - If an option table must be present
|
||||
* optionslabel - The right label for available options on this result type
|
||||
* options - An array of mod_h5pactivity/result/options compatible array
|
||||
* content - Extra content in HTML
|
||||
* track - Indicate if the result has displayable tracking
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"timecreated": "1587655101",
|
||||
"interactiontype": "choice",
|
||||
"description": "Example of some results",
|
||||
"rawscore": "4",
|
||||
"maxscore": "4",
|
||||
"duration": "130",
|
||||
"completion": "1",
|
||||
"success": "1",
|
||||
"hasoptions": true,
|
||||
"optionslabel": "Choice",
|
||||
"options": [
|
||||
{
|
||||
"description": "Choice 1 text",
|
||||
"id": 0,
|
||||
"useranswer": {
|
||||
"answer": "Correct answer",
|
||||
"pass": true
|
||||
},
|
||||
"correctanswer": {
|
||||
"answer": "Answer checked",
|
||||
"checked": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Choice 2 text",
|
||||
"id": 1,
|
||||
"useranswer": {
|
||||
"answer": "Wrong answer",
|
||||
"fail": true
|
||||
},
|
||||
"correctanswer": {
|
||||
"answer": "Answer checked",
|
||||
"unchecked": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Choice 3 text",
|
||||
"id": 2,
|
||||
"useranswer": {
|
||||
"answer": "This was the correct text",
|
||||
"correct": true
|
||||
},
|
||||
"correctanswer": {
|
||||
"answer": "This was the correct text",
|
||||
"text": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Choice 4 text",
|
||||
"id": 3,
|
||||
"correctanswer": {
|
||||
"answer": "Some text",
|
||||
"text": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Choice 4 text",
|
||||
"id": 3,
|
||||
"useranswer": {
|
||||
"answer": "Some wrong text",
|
||||
"incorrect": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"score": "4 out of 4",
|
||||
"content": "<p>This is an optional extra content in <b>HTML</b>.</p>",
|
||||
"track": true
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
<div class="container-fluid w-100 my-0 p-0">
|
||||
<div class="row w-100 py-3 px-1 m-0 p-md-3">
|
||||
{{>mod_h5pactivity/result/header}}
|
||||
{{{content}}}
|
||||
{{#hasoptions}}
|
||||
{{>mod_h5pactivity/result/options}}
|
||||
{{/hasoptions}}
|
||||
{{^track}}
|
||||
<div class="alert alert-warning w-100" role="alert">
|
||||
{{#str}}no_compatible_track, mod_h5pactivity, {{interactiontype}}{{/str}}
|
||||
</div>
|
||||
{{/track}}
|
||||
</div>
|
||||
</div>
|
66
mod/h5pactivity/templates/result/answer.mustache
Normal file
66
mod/h5pactivity/templates/result/answer.mustache
Normal file
@ -0,0 +1,66 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_h5pactivity/result/answer
|
||||
|
||||
This template render all kind of answers/choice in a results table.
|
||||
|
||||
Variables required for this template:
|
||||
* answer - The answer/choice text
|
||||
|
||||
Variables optional for this template:
|
||||
* pass - The answer pass
|
||||
* fail - The answer failed
|
||||
* correct - The answer is correct
|
||||
* incorrect - The answer is not correct
|
||||
* text - The choice is just text
|
||||
* checked - The choice must be checked
|
||||
* unchecked - The choice must be unchecked
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"answer": "This was the ansewer,",
|
||||
"correct": true,
|
||||
"incorrect": true,
|
||||
"text": true,
|
||||
"checked": true,
|
||||
"unchecked": true,
|
||||
"pass": true,
|
||||
"fail": true
|
||||
}
|
||||
|
||||
}}
|
||||
{{#correct}}
|
||||
{{#pix}}i/valid, moodle, {{#str}}answer_correct, mod_h5pactivity{{/str}}{{/pix}}{{answer}}
|
||||
{{/correct}}
|
||||
{{#incorrect}}
|
||||
{{#pix}}i/invalid, moodle, {{#str}}answer_incorrect, mod_h5pactivity{{/str}}{{/pix}}{{answer}}
|
||||
{{/incorrect}}
|
||||
{{#text}}
|
||||
{{answer}}
|
||||
{{/text}}
|
||||
{{#checked}}
|
||||
{{#pix}}i/checkedcircle, moodle, {{#str}}answer_checked, mod_h5pactivity{{/str}}{{/pix}}
|
||||
{{/checked}}
|
||||
{{#unchecked}}
|
||||
{{/unchecked}}
|
||||
{{#pass}}
|
||||
{{#pix}}i/valid, moodle, {{#str}}answer_pass, mod_h5pactivity{{/str}}{{/pix}}
|
||||
{{/pass}}
|
||||
{{#fail}}
|
||||
{{#pix}}i/invalid, moodle, {{#str}}answer_fail, mod_h5pactivity{{/str}}{{/pix}}
|
||||
{{/fail}}
|
44
mod/h5pactivity/templates/result/header.mustache
Normal file
44
mod/h5pactivity/templates/result/header.mustache
Normal file
@ -0,0 +1,44 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_h5pactivity/result/header
|
||||
|
||||
This template will render a results header inside mod_h5pactivity results report.
|
||||
|
||||
Variables required for this template:
|
||||
* description - Result description
|
||||
|
||||
Variables optional for this template:
|
||||
* success - If the result is marked as success
|
||||
* score - The result score string
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"timecreated": "1587655101",
|
||||
"interactiontype": "choice",
|
||||
"description": "Example of some results\n",
|
||||
"rawscore": "4",
|
||||
"maxscore": "4",
|
||||
"duration": "130",
|
||||
"success": "1",
|
||||
"score": "4 out of 4"
|
||||
}
|
||||
|
||||
}}
|
||||
<h3 class="w-100">
|
||||
{{description}}
|
||||
</h3>
|
118
mod/h5pactivity/templates/result/options.mustache
Normal file
118
mod/h5pactivity/templates/result/options.mustache
Normal file
@ -0,0 +1,118 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_h5pactivity/result/options
|
||||
|
||||
This template will render a choices table inside a H5P activity results report.
|
||||
|
||||
Variables required for this template:
|
||||
* options - An array of options
|
||||
* optionslabel - The right label for options column
|
||||
* correctlabel - The right label for correct answer column
|
||||
* answerlabel - The right label for the attempt answer column
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"optionslabel": "Choice",
|
||||
"correctlabel": "Correct answer",
|
||||
"answerlabel": "Attempt answer",
|
||||
"options": [
|
||||
{
|
||||
"description": "Choice 1 text",
|
||||
"id": 0,
|
||||
"useranswer": {
|
||||
"answer": "Correct answer",
|
||||
"pass": true
|
||||
},
|
||||
"correctanswer": {
|
||||
"answer": "Answer checked",
|
||||
"checked": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Choice 2 text",
|
||||
"id": 1,
|
||||
"useranswer": {
|
||||
"answer": "Wrong answer",
|
||||
"fail": true
|
||||
},
|
||||
"correctanswer": {
|
||||
"answer": "Answer checked",
|
||||
"unchecked": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Choice 3 text",
|
||||
"id": 2,
|
||||
"useranswer": {
|
||||
"answer": "This was the correct text",
|
||||
"correct": true
|
||||
},
|
||||
"correctanswer": {
|
||||
"answer": "This was the correct text",
|
||||
"text": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Choice 4 text",
|
||||
"id": 3,
|
||||
"correctanswer": {
|
||||
"answer": "Some text",
|
||||
"text": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Choice 4 text",
|
||||
"id": 3,
|
||||
"useranswer": {
|
||||
"answer": "Some wrong text",
|
||||
"incorrect": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}}
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{{optionslabel}}</th>
|
||||
<th scope="col">{{correctlabel}}</th>
|
||||
<th scope="col">{{answerlabel}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#options}}
|
||||
<tr>
|
||||
<td>{{description}}</td>
|
||||
<td>{{#correctanswer}}{{>mod_h5pactivity/result/answer}}{{/correctanswer}}</td>
|
||||
<td>{{#useranswer}}{{>mod_h5pactivity/result/answer}}{{/useranswer}}</td>
|
||||
</tr>
|
||||
{{/options}}
|
||||
{{#score}}
|
||||
<tr class="table-light">
|
||||
<td colspan="2" class="d-none d-sm-table-cell border-top-3 border-dark"></td>
|
||||
<td class="d-none d-sm-table-cell border-top border-dark">
|
||||
<strong>{{#str}}score, mod_h5pactivity{{/str}}: {{score}}</strong>
|
||||
</td>
|
||||
<td class="d-table-cell d-sm-none text-right border-top border-dark" colspan="3">
|
||||
<strong>{{#str}}score, mod_h5pactivity{{/str}}: {{score}}</strong>
|
||||
</td>
|
||||
</tr>
|
||||
{{/score}}
|
||||
</tbody>
|
||||
</table>
|
147
mod/h5pactivity/tests/event/report_viewed_test.php
Normal file
147
mod/h5pactivity/tests/event/report_viewed_test.php
Normal file
@ -0,0 +1,147 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Events test.
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_h5pactivity\event;
|
||||
|
||||
use advanced_testcase;
|
||||
use moodle_url;
|
||||
use coding_exception;
|
||||
use context_module;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* H5P activity events test cases.
|
||||
*
|
||||
* @package mod_h5pactivity
|
||||
* @copyright 2020 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class report_viewed_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test report_viewed event.
|
||||
*
|
||||
* @dataProvider report_viewed_data
|
||||
* @param bool $usea if a (instanceid) will be used in the event
|
||||
* @param bool $useattemptid if attemptid will be used in the event
|
||||
* @param bool $useuserid if user id will be used in the event
|
||||
* @param bool $exception if exception is expected
|
||||
*/
|
||||
public function test_report_viewed(bool $usea, bool $useattemptid, bool $useuserid, bool $exception) {
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Must be a non-guest user to create h5pactivities.
|
||||
$this->setAdminUser();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course->id]);
|
||||
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
|
||||
|
||||
// Create a user with 1 attempt.
|
||||
$user = $this->getDataGenerator()->create_and_enrol($course, 'student');
|
||||
$params = ['cmid' => $activity->cmid, 'userid' => $user->id];
|
||||
$attempt = $generator->create_content($activity, $params);
|
||||
|
||||
$other = [];
|
||||
$urlparams = [];
|
||||
if ($usea) {
|
||||
$other['instanceid'] = $activity->id;
|
||||
$urlparams['a'] = $activity->id;
|
||||
}
|
||||
if ($useuserid) {
|
||||
$other['userid'] = $user->id;
|
||||
$urlparams['userid'] = $user->id;
|
||||
}
|
||||
if ($useattemptid) {
|
||||
$other['attemptid'] = $attempt->id;
|
||||
$urlparams['attemptid'] = $attempt->id;
|
||||
}
|
||||
$params = [
|
||||
'context' => context_module::instance($activity->cmid),
|
||||
'objectid' => $activity->id,
|
||||
'other' => $other,
|
||||
];
|
||||
|
||||
if ($exception) {
|
||||
$this->expectException(coding_exception::class);
|
||||
}
|
||||
|
||||
$event = report_viewed::create($params);
|
||||
|
||||
// Triggering and capturing the event.
|
||||
$sink = $this->redirectEvents();
|
||||
$event->trigger();
|
||||
$events = $sink->get_events();
|
||||
$this->assertCount(1, $events);
|
||||
$event = reset($events);
|
||||
|
||||
// Checking that the event contains the expected values.
|
||||
$this->assertInstanceOf('\mod_h5pactivity\event\report_viewed', $event);
|
||||
$this->assertEquals(context_module::instance($activity->cmid), $event->get_context());
|
||||
$this->assertEquals($activity->id, $event->objectid);
|
||||
|
||||
$eventurl = $event->get_url();
|
||||
$url = new moodle_url('/mod/h5pactivity/report.php', $urlparams);
|
||||
$this->assertTrue($eventurl->compare($url));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for data request creation tests.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function report_viewed_data(): array {
|
||||
return [
|
||||
// Exception cases.
|
||||
'Event withour other data (exception)' => [
|
||||
false, false, false, true
|
||||
],
|
||||
'Event with only userid (exception)' => [
|
||||
false, false, true, true
|
||||
],
|
||||
'Event with only attemptid (exception)' => [
|
||||
false, true, false, true
|
||||
],
|
||||
'Event with attemptid and userid (exception)' => [
|
||||
false, true, true, true
|
||||
],
|
||||
// Correct cases.
|
||||
'Event with instance id' => [
|
||||
true, false, false, false
|
||||
],
|
||||
'Event with instance id and attempt id' => [
|
||||
true, false, true, false
|
||||
],
|
||||
'Event with instance id and userid' => [
|
||||
true, true, false, false
|
||||
],
|
||||
'Event with instance id, user id and attemptid' => [
|
||||
true, true, true, false
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
@ -25,7 +25,6 @@
|
||||
namespace mod_h5pactivity\event;
|
||||
|
||||
use advanced_testcase;
|
||||
use context_course;
|
||||
use context_module;
|
||||
|
||||
/**
|
||||
@ -38,7 +37,7 @@ use context_module;
|
||||
class statement_received_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test course_module_viewed event.
|
||||
* Test statement_recieved event.
|
||||
*/
|
||||
public function test_statement_received() {
|
||||
global $USER;
|
||||
|
@ -71,6 +71,9 @@ class mod_h5pactivity_generator extends testing_module_generator {
|
||||
if (!isset($record->grademethod)) {
|
||||
$record->grademethod = manager::GRADEHIGHESTATTEMPT;
|
||||
}
|
||||
if (!isset($record->reviewmode)) {
|
||||
$record->reviewmode = manager::REVIEWCOMPLETION;
|
||||
}
|
||||
|
||||
// The 'packagefile' value corresponds to the draft file area ID. If not specified, create from packagefilepath.
|
||||
if (empty($record->packagefile)) {
|
||||
|
@ -63,6 +63,7 @@ class mod_h5pactivity_generator_testcase extends advanced_testcase {
|
||||
$this->assertEquals(6, $activity->displayoptions);
|
||||
$this->assertEquals(0, $activity->enabletracking);
|
||||
$this->assertEquals(manager::GRADELASTATTEMPT, $activity->grademethod);
|
||||
$this->assertEquals(manager::REVIEWCOMPLETION, $activity->reviewmode);
|
||||
$this->assertEquals(2, count($records));
|
||||
$this->assertEquals('Another h5pactivity', $records[$activity->id]->name);
|
||||
|
||||
|
@ -276,9 +276,9 @@ class attempt_testcase extends \advanced_testcase {
|
||||
attempt::delete_all_attempts($cm, $user);
|
||||
|
||||
// Check data.
|
||||
for ($i = 0; $i < 4; $i++) {
|
||||
$count = $attempts[$i]->count_results();
|
||||
$this->assertEquals($results[$i], $count);
|
||||
for ($assert = 0; $assert < 4; $assert++) {
|
||||
$count = $attempts[$assert]->count_results();
|
||||
$this->assertEquals($results[$assert], $count);
|
||||
}
|
||||
$count = $DB->count_records('h5pactivity_attempts');
|
||||
$this->assertEquals($results[4], $count);
|
||||
|
@ -264,6 +264,80 @@ class manager_testcase extends \advanced_testcase {
|
||||
$this->assertNotEmpty($methods[manager::GRADEMANUAL]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test static get_selected_attempt.
|
||||
*
|
||||
* @dataProvider get_selected_attempt_data
|
||||
* @param int $enabletracking if tracking is enabled
|
||||
* @param int $gradingmethod new grading method
|
||||
* @param int $result the expected result
|
||||
*/
|
||||
public function test_get_selected_attempt(int $enabletracking, int $gradingmethod, int $result) {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$activity = $this->getDataGenerator()->create_module('h5pactivity',
|
||||
['course' => $course, 'enabletracking' => $enabletracking, 'grademethod' => $gradingmethod]);
|
||||
|
||||
$manager = manager::create_from_instance($activity);
|
||||
|
||||
$selected = $manager->get_selected_attempt();
|
||||
|
||||
$this->assertEquals($result, $selected[0]);
|
||||
$this->assertNotEmpty($selected[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for get_users_scaled_score.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_selected_attempt_data(): array {
|
||||
return [
|
||||
'Tracking with max attempt method' => [
|
||||
1, manager::GRADEHIGHESTATTEMPT, manager::GRADEHIGHESTATTEMPT
|
||||
],
|
||||
'Tracking with average attempt method' => [
|
||||
1, manager::GRADEAVERAGEATTEMPT, manager::GRADEAVERAGEATTEMPT
|
||||
],
|
||||
'Tracking with last attempt method' => [
|
||||
1, manager::GRADELASTATTEMPT, manager::GRADELASTATTEMPT
|
||||
],
|
||||
'Tracking with first attempt method' => [
|
||||
1, manager::GRADEFIRSTATTEMPT, manager::GRADEFIRSTATTEMPT
|
||||
],
|
||||
'Tracking with manual attempt grading' => [
|
||||
1, manager::GRADEMANUAL, manager::GRADEMANUAL
|
||||
],
|
||||
'No tracking with max attempt method' => [
|
||||
0, manager::GRADEHIGHESTATTEMPT, manager::GRADEMANUAL
|
||||
],
|
||||
'No tracking with average attempt method' => [
|
||||
0, manager::GRADEAVERAGEATTEMPT, manager::GRADEMANUAL
|
||||
],
|
||||
'No tracking with last attempt method' => [
|
||||
0, manager::GRADELASTATTEMPT, manager::GRADEMANUAL
|
||||
],
|
||||
'No tracking with first attempt method' => [
|
||||
0, manager::GRADEFIRSTATTEMPT, manager::GRADEMANUAL
|
||||
],
|
||||
'No tracking with manual attempt grading' => [
|
||||
0, manager::GRADEMANUAL, manager::GRADEMANUAL
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test static get_review_modes.
|
||||
*/
|
||||
public function test_get_review_modes() {
|
||||
$methods = manager::get_review_modes();
|
||||
$this->assertCount(2, $methods);
|
||||
$this->assertNotEmpty($methods[manager::REVIEWCOMPLETION]);
|
||||
$this->assertNotEmpty($methods[manager::REVIEWNONE]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_grader method.
|
||||
*/
|
||||
@ -282,6 +356,388 @@ class manager_testcase extends \advanced_testcase {
|
||||
$this->assertInstanceOf('mod_h5pactivity\local\grader', $grader);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test static can_view_all_attempts.
|
||||
*
|
||||
* @dataProvider can_view_all_attempts_data
|
||||
* @param int $enabletracking if tracking is enabled
|
||||
* @param bool $usestudent if test must be done with a user role
|
||||
* @param bool $useloggedin if test must be done with the loggedin user
|
||||
* @param bool $result the expected result
|
||||
*/
|
||||
public function test_can_view_all_attempts(int $enabletracking, bool $usestudent, bool $useloggedin, bool $result) {
|
||||
global $USER;
|
||||
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$activity = $this->getDataGenerator()->create_module('h5pactivity',
|
||||
['course' => $course, 'enabletracking' => $enabletracking]);
|
||||
|
||||
$manager = manager::create_from_instance($activity);
|
||||
|
||||
$user = $this->getDataGenerator()->create_and_enrol($course, 'student');
|
||||
$loggedin = $USER;
|
||||
|
||||
// We want to test what when the method is called to check a different user than $USER.
|
||||
if (!$usestudent) {
|
||||
$loggedin = $user;
|
||||
$user = $USER;
|
||||
}
|
||||
|
||||
if ($useloggedin) {
|
||||
$this->setUser($user);
|
||||
$user = null;
|
||||
} else {
|
||||
$this->setUser($loggedin);
|
||||
}
|
||||
|
||||
$this->assertEquals($result, $manager->can_view_all_attempts($user));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_can_view_all_attempts.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function can_view_all_attempts_data(): array {
|
||||
return [
|
||||
// No tracking cases.
|
||||
'No tracking with admin using $USER' => [
|
||||
0, false, false, false
|
||||
],
|
||||
'No tracking with student using $USER' => [
|
||||
0, true, false, false
|
||||
],
|
||||
'No tracking with admin loggedin' => [
|
||||
0, false, true, false
|
||||
],
|
||||
'No tracking with student loggedin' => [
|
||||
0, true, true, false
|
||||
],
|
||||
// Tracking enabled cases.
|
||||
'Tracking with admin using $USER' => [
|
||||
1, false, false, true
|
||||
],
|
||||
'Tracking with student using $USER' => [
|
||||
1, true, false, false
|
||||
],
|
||||
'Tracking with admin loggedin' => [
|
||||
1, false, true, true
|
||||
],
|
||||
'Tracking with student loggedin' => [
|
||||
1, true, true, false
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test static can_view_own_attempts.
|
||||
*
|
||||
* @dataProvider can_view_own_attempts_data
|
||||
* @param int $enabletracking if tracking is enabled
|
||||
* @param int $reviewmode the attempt review mode
|
||||
* @param bool $useloggedin if test must be done with the loggedin user
|
||||
* @param bool $hasattempts if the student have attempts
|
||||
* @param bool $result the expected result
|
||||
*/
|
||||
public function test_can_view_own_attempts(int $enabletracking, int $reviewmode,
|
||||
bool $useloggedin, bool $hasattempts, bool $result) {
|
||||
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$activity = $this->getDataGenerator()->create_module('h5pactivity',
|
||||
['course' => $course, 'enabletracking' => $enabletracking, 'reviewmode' => $reviewmode]);
|
||||
|
||||
$manager = manager::create_from_instance($activity);
|
||||
|
||||
$user = $this->getDataGenerator()->create_and_enrol($course, 'student');
|
||||
|
||||
if ($hasattempts) {
|
||||
$this->generate_fake_attempts($activity, $user, 1);
|
||||
}
|
||||
|
||||
if ($useloggedin) {
|
||||
$this->setUser($user);
|
||||
$user = null;
|
||||
}
|
||||
|
||||
$this->assertEquals($result, $manager->can_view_own_attempts($user));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_can_view_own_attempts.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function can_view_own_attempts_data(): array {
|
||||
return [
|
||||
// No tracking cases.
|
||||
'No tracking, review none, using $USER, without attempts' => [
|
||||
0, manager::REVIEWNONE, false, false, false
|
||||
],
|
||||
'No tracking, review enabled, using $USER, without attempts' => [
|
||||
0, manager::REVIEWCOMPLETION, false, false, false
|
||||
],
|
||||
'No tracking, review none, loggedin, without attempts' => [
|
||||
0, manager::REVIEWNONE, true, false, false
|
||||
],
|
||||
'No tracking, review enabled, loggedin, without attempts' => [
|
||||
0, manager::REVIEWCOMPLETION, true, false, false
|
||||
],
|
||||
'No tracking, review none, using $USER, with attempts' => [
|
||||
0, manager::REVIEWNONE, false, true, false
|
||||
],
|
||||
'No tracking, review enabled, using $USER, with attempts' => [
|
||||
0, manager::REVIEWCOMPLETION, false, true, false
|
||||
],
|
||||
'No tracking, review none, loggedin, with attempts' => [
|
||||
0, manager::REVIEWNONE, true, true, false
|
||||
],
|
||||
'No tracking, review enabled, loggedin, with attempts' => [
|
||||
0, manager::REVIEWCOMPLETION, true, true, false
|
||||
],
|
||||
// Tracking enabled cases.
|
||||
'Tracking enabled, review none, using $USER, without attempts' => [
|
||||
1, manager::REVIEWNONE, false, false, false
|
||||
],
|
||||
'Tracking enabled, review enabled, using $USER, without attempts' => [
|
||||
1, manager::REVIEWCOMPLETION, false, false, true
|
||||
],
|
||||
'Tracking enabled, review none, loggedin, without attempts' => [
|
||||
1, manager::REVIEWNONE, true, false, false
|
||||
],
|
||||
'Tracking enabled, review enabled, loggedin, without attempts' => [
|
||||
1, manager::REVIEWCOMPLETION, true, false, true
|
||||
],
|
||||
'Tracking enabled, review none, using $USER, with attempts' => [
|
||||
1, manager::REVIEWNONE, false, true, false
|
||||
],
|
||||
'Tracking enabled, review enabled, using $USER, with attempts' => [
|
||||
1, manager::REVIEWCOMPLETION, false, true, true
|
||||
],
|
||||
'Tracking enabled, review none, loggedin, with attempts' => [
|
||||
1, manager::REVIEWNONE, true, true, false
|
||||
],
|
||||
'Tracking enabled, review enabled, loggedin, with attempts' => [
|
||||
1, manager::REVIEWCOMPLETION, true, true, true
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test static count_attempts.
|
||||
*/
|
||||
public function test_count_attempts() {
|
||||
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$activity = $this->getDataGenerator()->create_module('h5pactivity',
|
||||
['course' => $course]);
|
||||
|
||||
$manager = manager::create_from_instance($activity);
|
||||
|
||||
// User without attempts.
|
||||
$user1 = $this->getDataGenerator()->create_and_enrol($course, 'student');
|
||||
|
||||
// User with 1 attempt.
|
||||
$user2 = $this->getDataGenerator()->create_and_enrol($course, 'student');
|
||||
$this->generate_fake_attempts($activity, $user2, 1);
|
||||
|
||||
// User with 2 attempts.
|
||||
$user3 = $this->getDataGenerator()->create_and_enrol($course, 'student');
|
||||
$this->generate_fake_attempts($activity, $user3, 1);
|
||||
|
||||
// Incomplete user2 and 3 has only 3 attempts completed.
|
||||
$this->assertEquals(0, $manager->count_attempts($user1->id));
|
||||
$this->assertEquals(3, $manager->count_attempts($user2->id));
|
||||
$this->assertEquals(3, $manager->count_attempts($user3->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test static count_attempts.
|
||||
*/
|
||||
public function test_count_users_attempts() {
|
||||
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$activity = $this->getDataGenerator()->create_module('h5pactivity',
|
||||
['course' => $course]);
|
||||
|
||||
$manager = manager::create_from_instance($activity);
|
||||
|
||||
// User without attempts.
|
||||
$user1 = $this->getDataGenerator()->create_and_enrol($course, 'student');
|
||||
|
||||
// User with 1 attempt.
|
||||
$user2 = $this->getDataGenerator()->create_and_enrol($course, 'student');
|
||||
$this->generate_fake_attempts($activity, $user2, 1);
|
||||
|
||||
// User with 2 attempts.
|
||||
$user3 = $this->getDataGenerator()->create_and_enrol($course, 'student');
|
||||
$this->generate_fake_attempts($activity, $user3, 1);
|
||||
|
||||
$attempts = $manager->count_users_attempts();
|
||||
$this->assertArrayNotHasKey($user1->id, $attempts);
|
||||
$this->assertArrayHasKey($user2->id, $attempts);
|
||||
$this->assertEquals(4, $attempts[$user2->id]);
|
||||
$this->assertArrayHasKey($user3->id, $attempts);
|
||||
$this->assertEquals(4, $attempts[$user3->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test static get_report.
|
||||
*
|
||||
* @dataProvider get_report_data
|
||||
* @param int $enabletracking if tracking is enabled
|
||||
* @param int $reviewmode the attempt review mode
|
||||
* @param bool $createattempts if the student have attempts
|
||||
* @param string $role the user role (student or editingteacher)
|
||||
* @param array $results the expected classname (or null)
|
||||
*/
|
||||
public function test_get_report(int $enabletracking, int $reviewmode, bool $createattempts,
|
||||
string $role, array $results) {
|
||||
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$activity = $this->getDataGenerator()->create_module('h5pactivity',
|
||||
['course' => $course, 'enabletracking' => $enabletracking, 'reviewmode' => $reviewmode]);
|
||||
|
||||
$manager = manager::create_from_instance($activity);
|
||||
$cm = get_coursemodule_from_id('h5pactivity', $activity->cmid, 0, false, MUST_EXIST);
|
||||
|
||||
$users = [
|
||||
'editingteacher' => $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'),
|
||||
'student' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
|
||||
'otheruser' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
|
||||
];
|
||||
|
||||
$attempts = [];
|
||||
if ($createattempts) {
|
||||
$this->generate_fake_attempts($activity, $users['student'], 1);
|
||||
$this->generate_fake_attempts($activity, $users['otheruser'], 2);
|
||||
$attempts['student'] = attempt::last_attempt($users['student'], $cm);
|
||||
$attempts['otheruser'] = attempt::last_attempt($users['otheruser'], $cm);
|
||||
}
|
||||
|
||||
$classnamebase = 'mod_h5pactivity\\local\\report\\';
|
||||
|
||||
$attemptid = null;
|
||||
if (isset($attempts['student'])) {
|
||||
$attemptid = $attempts['student']->get_id() ?? null;
|
||||
}
|
||||
$userid = $users['student']->id;
|
||||
|
||||
// Check reports.
|
||||
$this->setUser($users[$role]);
|
||||
|
||||
$report = $manager->get_report(null, null);
|
||||
if ($results[0] === null) {
|
||||
$this->assertNull($report);
|
||||
} else {
|
||||
$this->assertEquals($classnamebase.$results[0], get_class($report));
|
||||
}
|
||||
|
||||
$report = $manager->get_report($userid, null);
|
||||
if ($results[1] === null) {
|
||||
$this->assertNull($report);
|
||||
} else {
|
||||
$this->assertEquals($classnamebase.$results[1], get_class($report));
|
||||
}
|
||||
|
||||
$report = $manager->get_report($userid, $attemptid);
|
||||
if ($results[2] === null) {
|
||||
$this->assertNull($report);
|
||||
} else {
|
||||
$this->assertEquals($classnamebase.$results[2], get_class($report));
|
||||
}
|
||||
|
||||
// Check that student cannot access another student reports.
|
||||
if ($role == 'student') {
|
||||
$attemptid = null;
|
||||
if (isset($attempts['otheruser'])) {
|
||||
$attemptid = $attempts['otheruser']->get_id() ?? null;
|
||||
}
|
||||
$userid = $users['otheruser']->id;
|
||||
|
||||
$report = $manager->get_report($userid, null);
|
||||
$this->assertNull($report);
|
||||
|
||||
$report = $manager->get_report($userid, $attemptid);
|
||||
$this->assertNull($report);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_get_report.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_report_data(): array {
|
||||
return [
|
||||
// No tracking scenarios.
|
||||
'No tracking, review none, no attempts, teacher' => [
|
||||
0, manager::REVIEWNONE, false, 'editingteacher', [null, null, null]
|
||||
],
|
||||
'No tracking, review own, no attempts, teacher' => [
|
||||
0, manager::REVIEWCOMPLETION, false, 'editingteacher', [null, null, null]
|
||||
],
|
||||
'No tracking, review none, no attempts, student' => [
|
||||
0, manager::REVIEWNONE, false, 'student', [null, null, null]
|
||||
],
|
||||
'No tracking, review own, no attempts, student' => [
|
||||
0, manager::REVIEWCOMPLETION, false, 'student', [null, null, null]
|
||||
],
|
||||
'No tracking, review none, with attempts, teacher' => [
|
||||
0, manager::REVIEWNONE, true, 'editingteacher', [null, null, null]
|
||||
],
|
||||
'No tracking, review own, with attempts, teacher' => [
|
||||
0, manager::REVIEWCOMPLETION, true, 'editingteacher', [null, null, null]
|
||||
],
|
||||
'No tracking, review none, with attempts, student' => [
|
||||
0, manager::REVIEWNONE, true, 'student', [null, null, null]
|
||||
],
|
||||
'No tracking, review own, with attempts, student' => [
|
||||
0, manager::REVIEWCOMPLETION, true, 'student', [null, null, null]
|
||||
],
|
||||
// Tracking enabled scenarios.
|
||||
'Tracking enabled, review none, no attempts, teacher' => [
|
||||
1, manager::REVIEWNONE, false, 'editingteacher', ['participants', 'attempts', 'attempts']
|
||||
],
|
||||
'Tracking enabled, review own, no attempts, teacher' => [
|
||||
1, manager::REVIEWCOMPLETION, false, 'editingteacher', ['participants', 'attempts', 'attempts']
|
||||
],
|
||||
'Tracking enabled, review none, no attempts, student' => [
|
||||
1, manager::REVIEWNONE, false, 'student', [null, null, null]
|
||||
],
|
||||
'Tracking enabled, review own, no attempts, student' => [
|
||||
1, manager::REVIEWCOMPLETION, false, 'student', ['attempts', 'attempts', 'attempts']
|
||||
],
|
||||
'Tracking enabled, review none, with attempts, teacher' => [
|
||||
1, manager::REVIEWNONE, true, 'editingteacher', ['participants', 'attempts', 'results']
|
||||
],
|
||||
'Tracking enabled, review own, with attempts, teacher' => [
|
||||
1, manager::REVIEWCOMPLETION, true, 'editingteacher', ['participants', 'attempts', 'results']
|
||||
],
|
||||
'Tracking enabled, review none, with attempts, student' => [
|
||||
1, manager::REVIEWNONE, true, 'student', [null, null, null]
|
||||
],
|
||||
'Tracking enabled, review own, with attempts, student' => [
|
||||
1, manager::REVIEWCOMPLETION, true, 'student', ['attempts', 'attempts', 'results']
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert fake attempt data into h5pactiviyt_attempts.
|
||||
*
|
||||
|
@ -25,5 +25,5 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->component = 'mod_h5pactivity';
|
||||
$plugin->version = 2020041401;
|
||||
$plugin->version = 2020042202;
|
||||
$plugin->requires = 2020013000;
|
||||
|
@ -81,6 +81,19 @@ $PAGE->set_context($context);
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(format_string($moduleinstance->name));
|
||||
|
||||
// Attempts review.
|
||||
if ($manager->can_view_all_attempts()) {
|
||||
$reviewurl = new moodle_url('report.php', ['a' => $cm->instance]);
|
||||
$reviewmessage = get_string('review_all_attempts', 'mod_h5pactivity', $manager->count_attempts());
|
||||
} else if ($manager->can_view_own_attempts() && $manager->count_attempts($USER->id)) {
|
||||
$reviewurl = new moodle_url('report.php', ['a' => $cm->instance, 'userid' => $USER->id]);
|
||||
$reviewmessage = get_string('review_my_attempts', 'mod_h5pactivity');
|
||||
}
|
||||
if (isset($reviewurl)) {
|
||||
$widget = new mod_h5pactivity\output\reportlink($reviewurl, $reviewmessage);
|
||||
echo $OUTPUT->render($widget);
|
||||
}
|
||||
|
||||
if ($manager->is_tracking_enabled()) {
|
||||
$trackcomponent = 'mod_h5pactivity';
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user