Commit 25215446 authored by 0815-xyz's avatar 0815-xyz
Browse files

Initial commit

parents
<?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/>.
/**
* A class to display a table with user's own attempts on the activity's view page.
*
* @copyright 2022 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_adaptivequiz\local;
use coding_exception;
use help_icon;
use mod_adaptivequiz\local\attempt\attempt_state;
use mod_adaptivequiz_renderer;
use moodle_url;
use stdClass;
use table_sql;
final class user_attempts_table extends table_sql {
/**
* @var mod_adaptivequiz_renderer $renderer
*/
private $renderer;
public function __construct(mod_adaptivequiz_renderer $renderer) {
parent::__construct('userattemptstable');
$this->renderer = $renderer;
}
/**
* A convenience function to call a bunch of init methods.
*
* @param moodle_url $baseurl
* @param stdClass $adaptivequiz A record form {adaptivequiz}. id, lowestlevel, highestlevel, showabilitymeasure are
* the expected fields.
* @param int $userid
* @throws coding_exception
*/
public function init(moodle_url $baseurl, stdClass $adaptivequiz, int $userid): void {
$columns = ['state', 'timefinished'];
if ($adaptivequiz->showabilitymeasure) {
$columns[] = 'measure';
}
$this->define_columns($columns);
$headers = [
get_string('attempt_state', 'adaptivequiz'),
get_string('attemptfinishedtimestamp', 'adaptivequiz'),
];
if ($adaptivequiz->showabilitymeasure) {
$headers[] = get_string('abilityestimated', 'adaptivequiz') . ' / ' .
$adaptivequiz->lowestlevel . ' - ' . $adaptivequiz->highestlevel;
}
$this->define_headers($headers);
$this->set_attribute('class', 'generaltable userattemptstable');
$this->is_downloadable(false);
$this->collapsible(false);
$this->sortable(false, 'timefinished', SORT_DESC);
$this->define_help_for_headers(
[2 => new help_icon('abilityestimated', 'adaptivequiz')]
);
$this->set_column_css_classes();
$this->set_content_alignment_in_columns();
$this->define_baseurl($baseurl);
$this->set_sql('a.id, a.attemptstate AS state, a.timemodified AS timefinished, a.measure, q.highestlevel, ' .
'q.lowestlevel', '{adaptivequiz_attempt} a, {adaptivequiz} q', 'a.instance = q.id AND q.id = ? ' .
'AND userid = ?', [$adaptivequiz->id, $userid]);
}
/**
* @throws coding_exception
*/
protected function col_state(stdClass $row): string {
return get_string('recent' . $row->state, 'adaptivequiz');
}
protected function col_timefinished(stdClass $row): string {
if ($row->state != attempt_state::COMPLETED) {
return '';
}
return userdate($row->timefinished);
}
protected function col_measure(stdClass $row): string {
return $this->renderer->format_measure($row);
}
private function set_content_alignment_in_columns(): void {
foreach (array_keys($this->columns) as $columnname) {
$this->column_class[$columnname] .= ' text-center';
}
}
private function set_column_css_classes(): void {
$this->column_class['state'] .= ' statecol';
if (array_key_exists('measure', $this->columns)) {
$this->column_class['measure'] .= ' abilitymeasurecol';
}
}
}
<?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/>.
/**
* A class to display a table with user's own attempts on the activity's view page.
*
* @copyright 2022 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_adaptivequiz\output;
use renderable;
use stdClass;
final class ability_measure implements renderable {
/**
* @var float $abilitymeasure
*/
public $measurevalue;
/**
* @var int $lowestquestiondifficulty
*/
public $lowestquestiondifficulty;
/**
* @var int $highestquestiondifficulty
*/
public $highestquestiondifficulty;
/**
* A convenience method to convert the object to what {@link mod_adaptivequiz_renderer::format_measure()} expects
* to produce a formatted ability measure.
*/
public function as_object_to_format(): stdClass {
$return = new stdClass();
$return->measure = $this->measurevalue;
$return->lowestlevel = $this->lowestquestiondifficulty;
$return->highestlevel = $this->highestquestiondifficulty;
return $return;
}
/**
* A named constructor to set up the object and increase code readability.
*
* @param stdClass $adaptivequiz A record from {adaptivequiz}. lowestlevel and highestlevel are the expected fields.
* @param float $measurevalue
* @return self
*/
public static function of_attempt_on_adaptive_quiz(stdClass $adaptivequiz, float $measurevalue): self {
$return = new self();
$return->lowestquestiondifficulty = !empty($adaptivequiz->lowestlevel) ? $adaptivequiz->lowestlevel : 0;
$return->highestquestiondifficulty = !empty($adaptivequiz->highestlevel) ? $adaptivequiz->highestlevel : 0;
$return->measurevalue = $measurevalue;
return $return;
}
}
<?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/>.
declare(strict_types=1);
namespace mod_adaptivequiz\output;
use renderable;
use renderer_base;
use templatable;
/**
* Output object to display the number of questions answered out of total question number through an attempt.
*
* @package mod_adaptivequiz
* @copyright 2022 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class attempt_progress implements renderable, templatable {
/**
* @var int $questionsanswered
*/
private $questionsanswered;
/**
* @var int $maximumquestions
*/
private $maximumquestions;
/**
* @var bool $showprogressbar Whether a progress should be depicted as a filling bar. True by default.
*/
private $showprogressbar;
/**
* @var string|null $helpicon Already rendered markup for the help icon if needed.
*/
private $helpiconcontent;
/**
* The constructor. See the related class properties.
*
* @param int $questionsanswered
* @param int $maximumquestions
* @param bool $showprogressbar
* @param string|null $helpiconcontent
*/
public function __construct(int $questionsanswered, int $maximumquestions, bool $showprogressbar, ?string $helpiconcontent) {
$this->questionsanswered = $questionsanswered;
$this->maximumquestions = $maximumquestions;
$this->showprogressbar = $showprogressbar;
$this->helpiconcontent = $helpiconcontent;
}
/**
* Returns an object of the same class with modified property.
*/
public function without_progress_bar(): self {
return new self($this->questionsanswered, $this->maximumquestions, false, $this->helpiconcontent);
}
/**
* Returns an object of the same class with modified property.
*
* @param string $helpiconcontent See the related class property.
*/
public function with_help_icon_content(string $helpiconcontent): self {
return new self($this->questionsanswered, $this->maximumquestions, $this->showprogressbar, $helpiconcontent);
}
/**
* Exports the renderer data in a format that is suitable for a Mustache template.
*
* @param renderer_base $output
*/
public function export_for_template(renderer_base $output): array {
$fortemplate = [
'questionsanswerednumber' => $this->questionsanswered,
'maximumquestionsnumber' => $this->maximumquestions,
];
if ($this->showprogressbar) {
$fortemplate['showprogressbar'] = true;
$fortemplate['percentprogressbarfilled'] = floor($this->questionsanswered / $this->maximumquestions * 100);
}
$fortemplate['helpiconcontent'] = $this->helpiconcontent;
return $fortemplate;
}
/**
* A named constructor to instantiate an object from minimal data.
*
* @param int $questionsanswered
* @param int $maximumquestions
*/
public static function with_defaults(int $questionsanswered, int $maximumquestions): self {
return new self($questionsanswered, $maximumquestions, true, null);
}
}
<?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/>.
/**
* @copyright 2013 Middlebury College {@link http://www.middlebury.edu/}
* @copyright 2022 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_adaptivequiz\output\questionanalysis;
use html_table;
use html_writer;
use mod_adaptivequiz\local\questionanalysis\question_analyser;
use moodle_url;
use plugin_renderer_base;
use question_display_options;
use question_engine;
use stdClass;
class renderer extends plugin_renderer_base {
/** @var string $sortdir the sorting direction being used */
protected $sortdir = '';
/** @var moodle_url $sorturl the current base url used for keeping the table sorted */
protected $sorturl = '';
/** @var int $groupid variable used to reference the groupid that is currently being used to filter by */
public $groupid = 0;
/** @var array options that should be used for opening the secure popup. */
protected static $popupoptions = array(
'left' => 0,
'top' => 0,
'fullscreen' => true,
'scrollbars' => false,
'resizeable' => false,
'directories' => false,
'toolbar' => false,
'titlebar' => false,
'location' => false,
'status' => false,
'menubar' => false
);
/**
* This function returns page header information to be printed to the page
* @return string HTML markup for header inforation
*/
public function print_header() {
return $this->header();
}
/**
* This function returns page footer information to be printed to the page
* @return string HTML markup for footer inforation
*/
public function print_footer() {
return $this->footer();
}
/**
* This function generates the HTML required to display the initial reports table
* @param array $records attempt records from adaptivequiz_attempt table
* @param stdClass $cm course module object set to the instance of the activity
* @param string $sort the column the the table is to be sorted by
* @param string $sortdir the direction of the sort
* @return string HTML markup
*/
public function get_report_table($headers, $records, $cm, $baseurl, $sort, $sortdir) {
$table = new html_table();
$table->attributes['class'] = 'generaltable quizsummaryofattempt boxaligncenter';
$table->head = $this->format_report_table_headers($headers, $cm, $baseurl, $sort, $sortdir);
$table->align = array('center', 'center', 'center');
$table->size = array('', '', '');
$table->data = $records;
return html_writer::table($table);
}
/**
* This function creates the table header links that will be used to allow instructor to sort the data
* @param stdClass $cm a course module object set to the instance of the activity
* @param string $sort the column the the table is to be sorted by
* @param string $sortdir the direction of the sort
* @return array an array of column headers (firstname / lastname, number of attempts, standard error)
*/
public function format_report_table_headers($headers, $cm, $baseurl, $sort, $sortdir) {
/* Create header links */
$contents = array();
foreach ($headers as $key => $name) {
if ($sort == $key) {
$seperator = ' ';
if ($sortdir == 'DESC') {
$sortdir = 'ASC';
$imageparam = array('src' => $this->image_url('t/up'), 'alt' => '');
$icon = html_writer::empty_tag('img', $imageparam);
} else {
$sortdir = 'DESC';
$imageparam = array('src' => $this->image_url('t/down'), 'alt' => '');
$icon = html_writer::empty_tag('img', $imageparam);
}
} else {
$sortdir = 'ASC';
$seperator = '';
$icon = '';
}
$url = new moodle_url($baseurl, array('cmid' => $cm->id, 'sort' => $key, 'sortdir' => $sortdir));
$contents[] = html_writer::link($url, $name.$seperator.$icon);
}
return $contents;
}
/**
* This function prints paging information
* @param int $totalrecords the total number of records returned
* @param int $page the current page the user is on
* @param int $perpage the number of records displayed on one page
* @return string HTML markup
*/
public function print_paging_bar($totalrecords, $page, $perpage, $cm, $baseurl, $sort, $sortdir) {
$url = new moodle_url($baseurl, array('cmid' => $cm->id, 'sort' => $sort, 'sortdir' => $sortdir));
$output = '';
$output .= $this->paging_bar($totalrecords, $page, $perpage, $url);
return $output;
}
/**
* This function generates the HTML required to display the single-question report
* @param array $headers The labels for the report
* @param array $record An attempt record
* @return string HTML markup
*/
public function get_single_question_report($headers, $record) {
$table = new html_table();
$table->attributes['class'] = 'generaltable quizsummaryofattempt boxaligncenter';
$table->head = array(get_string('statistic', 'adaptivequiz'), get_string('value', 'adaptivequiz'));
$table->align = array('left', 'left');
$table->size = array('200px', '');
$table->width = '100%';
while ($name = array_shift($headers)) {
$value = array_shift($record);
$table->data[] = array($name, $value);
}
return html_writer::table($table);
}
/**
* Generate an HTML view of a single question.
*
* @param $analyzer
* @return string HTML markup
*/
public function get_question_details(question_analyser $analyzer, $context) {
// Setup display options.
$options = new question_display_options();
$options->readonly = true;
$options->flags = question_display_options::HIDDEN;
$options->marks = question_display_options::MAX_ONLY;
$options->rightanswer = question_display_options::VISIBLE;
$options->correctness = question_display_options::VISIBLE;
$options->numpartscorrect = question_display_options::VISIBLE;
// Init question usage and set default behaviour of usage.
$quba = question_engine::make_questions_usage_by_activity('mod_adaptivequiz', $context);
$quba->set_preferred_behaviour('deferredfeedback');
$quba->add_question($analyzer->get_question_definition());
$quba->start_question(1);
$quba->process_action(1, $quba->get_correct_response(1));
return $quba->render_question(1, $options);
}
}
<?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/>.
namespace mod_adaptivequiz\output\report;
use core\chart_line;
use core\chart_series;
use mod_adaptivequiz\local\report\attempt_report_helper;
use renderable;
use renderer_base;
use stdClass;
use templatable;
/**
* An object to render as a report on question administration for the given attempt.
*
* @package mod_adaptivequiz
* @copyright 2024 Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class attempt_administration_report implements renderable, templatable {
/**
* @var int $attemptid
*/
private int $attemptid;
/**
* The constructor.
*
* @param int $attemptid
*/
public function __construct(int $attemptid) {
$this->attemptid = $attemptid;
}
/**
* Implementation of the interface.
*
* @param renderer_base $output
* @return array
*/
public function export_for_template(renderer_base $output) {
$data = attempt_report_helper::prepare_administration_data($this->attemptid);
$chart = new chart_line();
$chart->set_labels(array_keys($data));
$xaxis = $chart->get_xaxis(0, true);
$xaxis->set_label(get_string('questionnumber', 'adaptivequiz'));
$yaxis = $chart->get_yaxis(0, true);
$yaxis->set_label(get_string('attemptquestion_ability', 'adaptivequiz'));
$yaxis->set_stepsize(1);
$targetdiffseries = new chart_series(get_string('reportattemptadmcharttargetdifflabel', 'adaptivequiz'),
array_values(array_map(fn (stdClass $dataitem): int => $dataitem->targetdifficulty, $data)));
$targetdiffseries->set_color('#a1caf1');
$chart->add_series($targetdiffseries);
$admdiffseries = new chart_series(get_string('reportattemptadmchartadmdifflabel', 'adaptivequiz'),
array_values(array_map(fn (stdClass $dataitem): int => $dataitem->administereddifficulty, $data)));
$admdiffseries->set_color('#875692');
$chart->add_series($admdiffseries);
$chart->add_series(new chart_series(get_string('attemptquestion_rightwrong', 'adaptivequiz'),
array_values(array_map(
fn (stdClass $dataitem): string => $dataitem->answeredcorrectly
? get_string('reportattemptadmanswerright', 'adaptivequiz')
: get_string('reportattemptadmanswerwrong', 'adaptivequiz'),
$data
))
));
$abilityseries = new chart_series(get_string('attemptquestion_ability', 'adaptivequiz'),
array_values(array_map(fn (stdClass $dataitem): float => round($dataitem->abilitymeasure, 2), $data)));
$abilityseries->set_color('#7f180d');
$chart->add_series($abilityseries);
// We don't care about the label here, as it's supposed to be not displayed.
$standarderrormaxseries = new chart_series('standarderrormax', array_values(array_map(
fn (stdClass $dataitem): float => round($dataitem->standarderrormax, 2), $data
)));
$standarderrormaxseries->set_fill('-1');
$standarderrormaxseries->set_color('rgba(255, 26, 104, 0.2)');
$chart->add_series($standarderrormaxseries);
// Same for the label as above.
$standarderrorminseries = new chart_series('standarderrormin', array_values(array_map(
fn (stdClass $dataitem): float => round($dataitem->standarderrormin, 2), $data
)));
$standarderrorminseries->set_fill('-2');
$standarderrorminseries->set_color('rgba(255, 26, 104, 0.2)');
$chart->add_series($standarderrorminseries);
$chart->add_series(new chart_series(get_string('graphlegend_error', 'adaptivequiz'),
array_values(array_map(
fn (stdClass $dataitem): string => '+/- ' . format_float($dataitem->standarderror * 100, 2) . '%', $data
))
));
return [
'chartdata' => json_encode($chart),
'withtable' => true,
];
}
}
<?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/>.
namespace mod_adaptivequiz\output\report;
use core\chart_bar;
use core\chart_series;
use mod_adaptivequiz\local\report\attempt_report_helper;
use renderable;
use renderer_base;
use stdClass;
use templatable;
/**
* An object to render as a report on answers distribution for the given attempt.
*
* @package mod_adaptivequiz
* @copyright 2024 Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class attempt_answers_distribution_report implements renderable, templatable {
/**
* @var int $attemptid
*/
private int $attemptid;
/**
* The constructor.
*
* @param int $attemptid
*/
public function __construct(int $attemptid) {
$this->attemptid = $attemptid;
}
/**
* Implementation of the interface.
*
* @param renderer_base $output
* @return array
*/
public function export_for_template(renderer_base $output) {
global $USER, $DB;
$attemptrecord = $DB->get_record('adaptivequiz_attempt', ['id' => $this->attemptid], '*', MUST_EXIST);
$adaptivequizid = $attemptrecord->instance;
$showchartstacked = true;
if ($chartsettingsjson = get_user_preferences("mod_adaptivequiz_answers_distribution_chart_settings_$adaptivequizid")) {
$chartsettings = json_decode($chartsettingsjson);
$showchartstacked = $chartsettings->showstacked;
}
$data = attempt_report_helper::prepare_answers_distribution_data($this->attemptid);
// Display only those levels where question were actually administered.
$data = array_filter($data, fn (stdClass $dataitem): bool => $dataitem->numcorrect > 0 || $dataitem->numwrong > 0);
$chart = new chart_bar();
$chart->set_stacked($showchartstacked);
$chart->set_labels(array_keys($data));
$xaxis = $chart->get_xaxis(0, true);
$xaxis->set_label(get_string('reportanswersdistributionchartxaxislabel', 'adaptivequiz'));
$yaxis = $chart->get_yaxis(0, true);
$yaxis->set_label(get_string('reportanswersdistributionchartyaxislabel', 'adaptivequiz'));
$yaxis->set_stepsize(1);
$chart->add_series(new chart_series(get_string('reportanswersdistributionchartnumrightlabel', 'adaptivequiz'),
array_values(array_map(fn (stdClass $dataitem): int => $dataitem->numcorrect, $data))));
$chart->add_series(new chart_series(get_string('reportanswersdistributionchartnumwronglabel', 'adaptivequiz'),
array_values(array_map(fn (stdClass $dataitem): int => $dataitem->numwrong, $data))));
return [
'showchartstacked' => $showchartstacked,
'userid' => $USER->id,
'adaptivequizid' => $adaptivequizid,
'chartdata' => json_encode($chart),
'withtable' => true,
];
}
}
<?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 definition of a renderable for an action available for an individual user attempt in the report.
*
* @package mod_adaptivequiz
* @copyright 2022 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_adaptivequiz\output\report\individual_user_attempts;
use moodle_url;
use pix_icon;
use renderable;
use renderer_base;
use templatable;
/**
* Definition of a renderable for an action available for an individual user attempt in the report.
*
* @package mod_adaptivequiz
*/
final class individual_user_attempt_action implements renderable, templatable {
/**
* @var moodle_url $url;
*/
private $url;
/**
* @var pix_icon $icon
*/
private $icon;
/**
* @var string $title
*/
private $title;
/**
* The constructor.
*
* @param moodle_url $url
* @param pix_icon $icon
* @param string $title
*/
public function __construct(moodle_url $url, pix_icon $icon, string $title) {
$this->url = $url;
$this->icon = $icon;
$this->title = $title;
}
/**
* Exports the renderer data in a format that is suitable for a Mustache template.
*
* @param renderer_base $output
*/
public function export_for_template(renderer_base $output): array {
return [
'url' => $this->url->out(false),
'icon' => $output->render($this->icon),
'title' => $this->title,
];
}
}
<?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 definition of a renderable for actions available for an individual user attempt in the report.
*
* @package mod_adaptivequiz
* @copyright 2022 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_adaptivequiz\output\report\individual_user_attempts;
use renderable;
use renderer_base;
use templatable;
/**
* Definition of a renderable for actions available for an individual user attempt in the report.
*
* @package mod_adaptivequiz
*/
final class individual_user_attempt_actions implements renderable, templatable {
/**
* @var individual_user_attempt_action[] $actions
*/
private $actions = [];
/**
* An interface to add an action object to the actions set.
*
* @param individual_user_attempt_action $action
*/
public function add(individual_user_attempt_action $action): void {
$this->actions[] = $action;
}
/**
* Exports the renderer data in a format that is suitable for a Mustache template.
*
* @param renderer_base $output
*/
public function export_for_template(renderer_base $output): array {
$actions = [];
foreach ($this->actions as $action) {
$actions[] = $action->export_for_template($output);
}
return [
'actions' => $actions,
];
}
}
<?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/>.
/**
* A class to display a table with user's own attempts on the activity's view page.
*
* @copyright 2022 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_adaptivequiz\output;
use renderable;
use stdClass;
final class user_attempt_summary implements renderable {
/**
* @var string $attemptstate
*/
public $attemptstate;
/**
* @var int $timefinished
*/
public $timefinished;
/**
* @var float $abilitymeasure
*/
public $abilitymeasure;
/**
* @var int $lowestquestiondifficulty
*/
public $lowestquestiondifficulty;
/**
* @var int $highestquestiondifficulty
*/
public $highestquestiondifficulty;
/**
* @param stdClass $attempt A record from {adaptivequiz_attempt}. attemptstate, timemodified, measure are
* the expected fields.
* @param stdClass $adaptivequiz A record from {adaptivequiz}. lowestlevel, highestlevel, showabilitymeasure are
* the expected fields.
*/
public static function from_db_records(stdClass $attempt, stdClass $adaptivequiz): self {
$return = new self();
$return->attemptstate = !empty($attempt->attemptstate) ? $attempt->attemptstate : '';
$return->timefinished = !empty($attempt->timemodified) ? $attempt->timemodified : 0;
$return->abilitymeasure = !empty($attempt->measure) && $adaptivequiz->showabilitymeasure
? $attempt->measure
: 0;
$return->lowestquestiondifficulty = !empty($adaptivequiz->lowestlevel) ? $adaptivequiz->lowestlevel : 0;
$return->highestquestiondifficulty = !empty($adaptivequiz->highestlevel) ? $adaptivequiz->highestlevel : 0;
return $return;
}
}
<?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/>.
/**
* Confirmation page to close a student attempt.
*
* @copyright 2013 Remote-Learner {@link http://www.remote-learner.ca/}
* @copyright 2022 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../../config.php');
require_once($CFG->dirroot . '/mod/adaptivequiz/locallib.php');
use mod_adaptivequiz\local\attempt\attempt_state;
$attemptid = required_param('attempt', PARAM_INT);
$confirm = optional_param('confirm', 0, PARAM_INT);
$attempt = $DB->get_record('adaptivequiz_attempt', ['id' => $attemptid], '*', MUST_EXIST);
$adaptivequiz = $DB->get_record('adaptivequiz', ['id' => $attempt->instance], '*', MUST_EXIST);
$cm = get_coursemodule_from_instance('adaptivequiz', $adaptivequiz->id, $adaptivequiz->course, false, MUST_EXIST);
$course = $DB->get_record('course', ['id' => $adaptivequiz->course], '*', MUST_EXIST);
require_login($course, true, $cm);
$context = context_module::instance($cm->id);
require_capability('mod/adaptivequiz:viewreport', $context);
$returnurl = new moodle_url('/mod/adaptivequiz/viewattemptreport.php', ['cmid' => $cm->id, 'userid' => $attempt->userid]);
if ($attempt->attemptstate == attempt_state::COMPLETED) {
throw new moodle_exception('errorclosingattempt_alreadycomplete', 'adaptivequiz', $returnurl);
}
$user = $DB->get_record('user', ['id' => $attempt->userid], '*', MUST_EXIST);
$PAGE->set_url('/mod/adaptivequiz/closeattempt.php', ['attempt' => $attempt->id]);
$PAGE->set_title(format_string($adaptivequiz->name));
$PAGE->set_heading(format_string($course->fullname));
$PAGE->set_context($context);
$renderer = $PAGE->get_renderer('mod_adaptivequiz');
$performancecalculation = new stdClass();
$performancecalculation->measure = $attempt->measure;
$performancecalculation->stderror = $attempt->standarderror;
$performancecalculation->lowestlevel = $adaptivequiz->lowestlevel;
$performancecalculation->highestlevel = $adaptivequiz->highestlevel;
$a = new stdClass();
$a->name = fullname($user);
$a->started = userdate($attempt->timecreated);
$a->modified = userdate($attempt->timemodified);
$a->num_questions = format_string($attempt->questionsattempted);
$a->measure = $renderer->format_measure($performancecalculation);
$a->standarderror = $renderer->format_standard_error($performancecalculation);
$a->current_user_name = fullname($USER);
$a->current_user_id = format_string($USER->id);
$a->now = userdate(time());
if ($confirm) {
$statusmessage = get_string('attemptclosedstatus', 'adaptivequiz', $a);
$closemessage = get_string('attemptclosed', 'adaptivequiz', $a);
adaptivequiz_complete_attempt($attempt->uniqueid, $adaptivequiz, $context, $attempt->userid, $attempt->standarderror,
$statusmessage);
redirect($returnurl, $closemessage, 4);
}
$message = html_writer::tag('p', get_string('confirmcloseattempt', 'adaptivequiz', $a)) .
html_writer::tag('p', get_string('confirmcloseattemptstats', 'adaptivequiz', $a)) .
html_writer::tag('p', get_string('confirmcloseattemptscore', 'adaptivequiz', $a));
$confirm = new moodle_url('/mod/adaptivequiz/closeattempt.php', ['attempt' => $attempt->id, 'confirm' => 1]);
echo $renderer->header();
echo $renderer->confirm($message, $confirm, $returnurl);
echo $renderer->footer();
<?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/>.
/**
* Adaptive testing capabilities definition
*
* @package mod
* @subpackage adaptivequiz
* @category access
* @copyright 2013 onwards Remote-Learner {@link http://www.remote-learner.ca/}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$capabilities = array(
// Ability to add a new adaptivequiz to the course.
'mod/adaptivequiz:addinstance' => array(
'riskbitmask' => RISK_XSS,
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
'archetypes' => array(
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
),
'clonepermissionsfrom' => 'moodle/course:manageactivities'
),
// Ability to view adaptivequiz report.
'mod/adaptivequiz:viewreport' => array(
'riskbitmask' => RISK_PERSONAL,
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
),
),
// Ability to view review pervious attempts.
'mod/adaptivequiz:reviewattempts' => array(
'riskbitmask' => RISK_PERSONAL,
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
'archetypes' => array(
'student' => CAP_ALLOW,
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
),
),
// Ability to attempt the activity.
'mod/adaptivequiz:attempt' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'student' => CAP_ALLOW
)
),
);
<?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/>.
/**
* @copyright 2022 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$observers = [
[
'eventname' => '\mod_adaptivequiz\event\attempt_completed',
'callback' => '\mod_adaptivequiz\attempt_state_change_observers::attempt_completed'
]
];
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/adaptivequiz/db" VERSION="20221102" COMMENT="XMLDB file for Moodle mod/adaptivequiz"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
<TABLES>
<TABLE NAME="adaptivequiz" COMMENT="Adaptive quiz instances table" NEXT="adaptivequiz_question">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="course id foreign key"/>
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="Name of the activity instance"/>
<FIELD NAME="intro" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="Description of activity"/>
<FIELD NAME="introformat" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="activity intro text format"/>
<FIELD NAME="attempts" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Number of allowed attempts"/>
<FIELD NAME="password" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="A password that the student must enter before starting or continuing an adaptive quiz attempt."/>
<FIELD NAME="browsersecurity" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Restriciton on the browser the student must use. E.g. securewindow."/>
<FIELD NAME="attemptfeedback" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="Feedback given to students when their attempt has been completed."/>
<FIELD NAME="attemptfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Format of attempt feedback"/>
<FIELD NAME="showabilitymeasure" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether the ability measure should be presented to a test-taker in attempt summary."/>
<FIELD NAME="showattemptprogress" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether quiz progress info should be presented to a test-taker during attempting a quiz."/>
<FIELD NAME="showownattemptresult" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether attempt result info should be presented to a test-taker."/>
<FIELD NAME="highestlevel" TYPE="int" LENGTH="3" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The highest difficulty level the adaptive quiz will go to."/>
<FIELD NAME="lowestlevel" TYPE="int" LENGTH="3" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The lowest difficulty level the adaptive quiz will go to."/>
<FIELD NAME="acceptancethreshold" TYPE="number" LENGTH="4" NOTNULL="true" DEFAULT="0.5" SEQUENCE="false" DECIMALS="2" COMMENT="The value that determines the acceptable level of correctness"/>
<FIELD NAME="questionschecked" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="notification to prompt user to review questions"/>
<FIELD NAME="questionchecktrigger" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="number of attempts that need to be completed before question analysis is advised'"/>
<FIELD NAME="minimumquestions" TYPE="int" LENGTH="3" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The minimum number of questions that mus be attempted by the user"/>
<FIELD NAME="maximumquestions" TYPE="int" LENGTH="3" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The maximum number of question that can be attempted by the user"/>
<FIELD NAME="standarderror" TYPE="number" LENGTH="10" NOTNULL="true" DEFAULT="0.0" SEQUENCE="false" DECIMALS="5" COMMENT="The standard error that must be met before ending the attempt."/>
<FIELD NAME="startinglevel" TYPE="int" LENGTH="3" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The level of difficult all attempts will start with"/>
<FIELD NAME="grademethod" TYPE="int" LENGTH="3" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Which of multiple attempts should be reported to the grade book. 1=highest, 3=first, 4=last."/>
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Time created timestamp"/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Time modified timesampt"/>
<FIELD NAME="completionattemptcompleted" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Stores whether a custom completion rule based on whether a user has a completed attempt enabled."/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="course_foreign" TYPE="foreign" FIELDS="course" REFTABLE="course" REFFIELDS="id" COMMENT="Foreign key to the course table."/>
</KEYS>
</TABLE>
<TABLE NAME="adaptivequiz_question" COMMENT="An association table for activity instance and question categories.">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="instance" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Activity instance id. Foreign key to activityquiz."/>
<FIELD NAME="questioncategory" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Question category id. Foreign key to questions."/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="instance_foreign" TYPE="foreign" FIELDS="instance" REFTABLE="adaptivequiz" REFFIELDS="id" COMMENT="Foreign key to adaptivequiz table."/>
<KEY NAME="questioncategory_foreign" TYPE="foreign" FIELDS="questioncategory" REFTABLE="question_categories" REFFIELDS="id" COMMENT="Foreign key to questino_categories table."/>
</KEYS>
</TABLE>
<TABLE NAME="adaptivequiz_attempt" COMMENT="Logging of attempts">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="instance"/>
<FIELD NAME="instance" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Activity instance the attempt was for"/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="User id. Foreign key from user."/>
<FIELD NAME="uniqueid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Question usage id. Foreign key to question_usages."/>
<FIELD NAME="attemptstate" TYPE="char" LENGTH="30" NOTNULL="true" SEQUENCE="false" COMMENT="The state of the attempt"/>
<FIELD NAME="attemptstopcriteria" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="The reason why the attempt was stopped"/>
<FIELD NAME="questionsattempted" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The number of question attempted"/>
<FIELD NAME="difficultysum" TYPE="number" LENGTH="10" NOTNULL="true" DEFAULT="0.0" SEQUENCE="false" DECIMALS="7" COMMENT="The sum of difficulty levels attempted measured in logits"/>
<FIELD NAME="standarderror" TYPE="number" LENGTH="10" NOTNULL="true" DEFAULT="0.0" SEQUENCE="false" DECIMALS="5" COMMENT="The standard error that was achieved during the attempt"/>
<FIELD NAME="measure" TYPE="number" LENGTH="10" NOTNULL="true" DEFAULT="0.0" SEQUENCE="false" DECIMALS="5" COMMENT="The attempt ability measure in logits"/>
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Time created timestamp"/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Time modified timestamp"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="instance_foreign"/>
<KEY NAME="instance_foreign" TYPE="foreign" FIELDS="instance" REFTABLE="adaptivequiz" REFFIELDS="id" COMMENT="Foreign key to adaptivequiz table."/>
<KEY NAME="userid_foreign" TYPE="foreign" FIELDS="userid" REFTABLE="user" REFFIELDS="id" COMMENT="Foreign key to user table."/>
<KEY NAME="uniqueid_foreign" TYPE="foreign" FIELDS="uniqueid" REFTABLE="question_usages" REFFIELDS="id" COMMENT="Foreign key to question_usages table."/>
</KEYS>
<INDEXES>
<INDEX NAME="instance_userid_idx" UNIQUE="false" FIELDS="instance, userid" COMMENT="Instance and user id index"/>
</INDEXES>
</TABLE>
</TABLES>
</XMLDB>
<?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/>.
/**
* Definition of log events for the adaptive quiz module.
*
* @package mod_adaptivequiz
* @category log
* @copyright 2013 onwards Remote-Learner {@link http://www.remote-learner.ca/}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $DB;
$logs = array(
array('module' => 'adaptivequiz', 'action' => 'view', 'mtable' => 'adaptivequiz', 'field' => 'name'),
array('module' => 'adaptivequiz', 'action' => 'add', 'mtable' => 'adaptivequiz', 'field' => 'name'),
array('module' => 'adaptivequiz', 'action' => 'update', 'mtable' => 'adaptivequiz', 'field' => 'name'),
array('module' => 'adaptivequiz', 'action' => 'report', 'mtable' => 'adaptivequiz', 'field' => 'name'),
array('module' => 'adaptivequiz', 'action' => 'attempt', 'mtable' => 'adaptivequiz', 'field' => 'name'),
array('module' => 'adaptivequiz', 'action' => 'submit', 'mtable' => 'adaptivequiz', 'field' => 'name'),
array('module' => 'adaptivequiz', 'action' => 'review', 'mtable' => 'adaptivequiz', 'field' => 'name'),
array('module' => 'adaptivequiz', 'action' => 'start attempt', 'mtable' => 'adaptivequiz', 'field' => 'name'),
array('module' => 'adaptivequiz', 'action' => 'close attempt', 'mtable' => 'adaptivequiz', 'field' => 'name'),
array('module' => 'adaptivequiz', 'action' => 'start attempt', 'mtable' => 'adaptivequiz', 'field' => 'name'),
array('module' => 'adaptivequiz', 'action' => 'continue attempt', 'mtable' => 'adaptivequiz', 'field' => 'name'),
array('module' => 'adaptivequiz', 'action' => 'start attempt', 'mtable' => 'adaptivequiz', 'field' => 'name'),
);
<?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/>.
/**
* Adaptive testing uninstall script
*
* This module was created as a collaborative effort between Middlebury College
* and Remote Learner.
*
* @package mod_adaptivequiz
* @copyright 2013 onwards Remote-Learner {@link http://www.remote-learner.ca/}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Custom uninstallation procedure
* @return bool: only returns truel
*/
function xmldb_adaptivequiz_uninstall() {
return true;
}
<?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 function with the definition of upgrade steps for the plugin.
*
* @package mod_adaptivequiz
* @copyright 2013 Remote-Learner {@link http://www.remote-learner.ca/}
* @copyright 2022 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Defines upgrade steps for the plugin.
*
* @param mixed $oldversion
*/
function xmldb_adaptivequiz_upgrade($oldversion) {
global $CFG, $DB;
$dbman = $DB->get_manager();
if ($oldversion < 2014020400) {
// Define field grademethod.
$table = new xmldb_table('adaptivequiz');
$field = new xmldb_field('grademethod', XMLDB_TYPE_INTEGER, '3', null, XMLDB_NOTNULL, null, 1, 'startinglevel');
// Conditionally add field grademethod.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Quiz savepoint reached.
upgrade_mod_savepoint(true, 2014020400, 'adaptivequiz');
}
if ($oldversion < 2022012600) {
$table = new xmldb_table('adaptivequiz');
$field = new xmldb_field('showabilitymeasure', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, false, '0',
'attemptfeedbackformat');
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
upgrade_mod_savepoint(true, 2022012600, 'adaptivequiz');
}
if ($oldversion < 2022092600) {
$table = new xmldb_table('adaptivequiz');
$field = new xmldb_field('completionattemptcompleted', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, false, 0);
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
upgrade_mod_savepoint(true, 2022092600, 'adaptivequiz');
}
if ($oldversion < 2022110200) {
$table = new xmldb_table('adaptivequiz');
$field = new xmldb_field('showattemptprogress', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, 0,
'showabilitymeasure');
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
upgrade_mod_savepoint(true, 2022110200, 'adaptivequiz');
}
//KNIGHT
if ($oldversion < 2024041901) {
$table = new xmldb_table('adaptivequiz');
$field = new xmldb_field('showownattemptresult', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0',
'showattemptprogress');
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
}
if ($oldversion < 2024041901) {
$table = new xmldb_table('adaptivequiz');
$field = new xmldb_field('acceptancethreshold', XMLDB_TYPE_NUMBER, '4, 2', null, XMLDB_NOTNULL, null, '0.5',
'lowestlevel');
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
}
if ($oldversion < 2024041901) {
$table = new xmldb_table('adaptivequiz');
$field = new xmldb_field('questionschecked', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0',
'acceptancethreshold');
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
}
if ($oldversion < 2024041901) {
$table = new xmldb_table('adaptivequiz');
$field = new xmldb_field('questionchecktrigger', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0',
'questionschecked');
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
upgrade_mod_savepoint(true, 2024041901, 'adaptivequiz');
}
return true;
}
<?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/>.
/**
* Confirmation page to remove student attempts.
*
* @copyright 2013 onwards Remote-Learner {@link http://www.remote-learner.ca/}
* @copyright 2022 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../../config.php');
$attemptid = required_param('attempt', PARAM_INT);
$confirm = optional_param('confirm', 0, PARAM_INT);
$attempt = $DB->get_record('adaptivequiz_attempt', ['id' => $attemptid], '*', MUST_EXIST);
$adaptivequiz = $DB->get_record('adaptivequiz', ['id' => $attempt->instance], '*', MUST_EXIST);
$cm = get_coursemodule_from_instance('adaptivequiz', $adaptivequiz->id, $adaptivequiz->course, false, MUST_EXIST);
$course = $DB->get_record('course', ['id' => $adaptivequiz->course], '*', MUST_EXIST);
require_login($course, true, $cm);
$context = context_module::instance($cm->id);
require_capability('mod/adaptivequiz:viewreport', $context);
$user = $DB->get_record('user', ['id' => $attempt->userid], '*', MUST_EXIST);
$PAGE->set_url('/mod/adaptivequiz/delattempt.php', ['attempt' => $attempt->id]);
$PAGE->set_title(format_string($adaptivequiz->name));
$PAGE->set_heading(format_string($course->fullname));
$PAGE->set_context($context);
$returnurl = new moodle_url('/mod/adaptivequiz/viewattemptreport.php', ['cmid' => $cm->id, 'userid' => $user->id]);
$a = new stdClass();
$a->name = fullname($user);
$a->timecompleted = userdate($attempt->timemodified);
if ($confirm) {
question_engine::delete_questions_usage_by_activity($attempt->uniqueid);
$DB->delete_records('adaptivequiz_attempt', ['id' => $attempt->id]);
adaptivequiz_update_grades($adaptivequiz, $user->id);
$message = get_string('attemptdeleted', 'adaptivequiz', $a);
redirect($returnurl, $message, 4);
}
$message = get_string('confirmdeleteattempt', 'adaptivequiz', $a);
$confirm = new moodle_url('/mod/adaptivequiz/delattempt.php', ['attempt' => $attempt->id, 'confirm' => 1]);
echo $OUTPUT->header();
echo $OUTPUT->confirm($message, $confirm, $returnurl);
echo $OUTPUT->footer();
<?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/>.
/**
* Redirect users who clicked on a link in the gradebook.
*
* @copyright 2013 onwards Remote-Learner {@link http://www.remote-learner.ca/}
* @copyright 2022 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(dirname(__FILE__).'/../../config.php');
$id = required_param('id', PARAM_INT); // Course module ID.
$itemnumber = optional_param('itemnumber', 0, PARAM_INT); // Item number, may be != 0 for activities that allow more than one
// grade per user.
$userid = optional_param('userid', 0, PARAM_INT); // Graded user ID (optional).
if (!$cm = get_coursemodule_from_id('adaptivequiz', $id)) {
throw new moodle_exception('invalidcoursemodule');
}
if (!$course = $DB->get_record('course', array('id' => $cm->course))) {
throw new moodle_exception("coursemisconf");
}
require_login($course, true, $cm);
$context = context_module::instance($cm->id);
if (has_capability('mod/adaptivequiz:viewreport', $context)) {
$params = array('cmid' => $id);
if ($userid) {
$params['userid'] = $userid;
$url = new moodle_url('/mod/adaptivequiz/viewattemptreport.php', $params);
} else {
$url = new moodle_url('/mod/adaptivequiz/viewreport.php', $params);
}
} else {
$params = array('id' => $id);
$url = new moodle_url('/mod/adaptivequiz/view.php', $params);
}
redirect($url);
exit;
<?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/>.
/**
* @copyright 2013 onwards Remote-Learner {@link http://www.remote-learner.ca/}
* @copyright 2022 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(dirname(__FILE__).'/../../config.php');
require_once($CFG->dirroot.'/mod/adaptivequiz/lib.php');
use mod_adaptivequiz\event\course_module_instance_list_viewed;
$id = required_param('id', PARAM_INT); // Course.
$course = $DB->get_record('course', array('id' => $id), '*', MUST_EXIST);
require_course_login($course);
course_module_instance_list_viewed::create_from_course($course)->trigger();
$coursecontext = context_course::instance($course->id);
$PAGE->set_url('/mod/adaptivequiz/index.php', array('id' => $id));
$PAGE->set_title(format_string($course->fullname));
$PAGE->set_heading(format_string($course->fullname));
$PAGE->set_context($coursecontext);
echo $OUTPUT->header();
if (!$adaptivequizinstances = get_all_instances_in_course('adaptivequiz', $course)) {
notice(get_string('nonewmodules', 'adaptivequiz'), new moodle_url('/course/view.php', array('id' => $course->id)));
}
$table = new html_table();
if ($course->format == 'weeks') {
$table->head = array(get_string('week'), get_string('name'));
$table->align = array('center', 'left');
} else if ($course->format == 'topics') {
$table->head = array(get_string('topic'), get_string('name'));
$table->align = array('center', 'left', 'left', 'left');
} else {
$table->head = array(get_string('name'));
$table->align = array('left', 'left', 'left');
}
foreach ($adaptivequizinstances as $adaptivequizinstance) {
if (!$adaptivequizinstance->visible) {
$link = html_writer::link(
new moodle_url('/mod/adaptivequiz/view.php', array('id' => $adaptivequizinstance->coursemodule)),
format_string($adaptivequizinstance->name, true),
array('class' => 'dimmed'));
} else {
$link = html_writer::link(
new moodle_url('/mod/adaptivequiz/view.php', array('id' => $adaptivequizinstance->coursemodule)),
format_string($adaptivequizinstance->name, true));
}
if ($course->format == 'weeks' || $course->format == 'topics') {
$table->data[] = array($adaptivequizinstance->section, $link);
} else {
$table->data[] = array($link);
}
}
echo $OUTPUT->heading(get_string('modulenameplural', 'adaptivequiz'), 2);
echo html_writer::table($table);
echo $OUTPUT->footer();
<?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/>.
/**
* Strings for the English language.
*
* @copyright 2013 onwards Remote-Learner {@link http://www.remote-learner.ca/}
* @copyright 2022 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$string['abilityestimated'] = 'Estimated ability';
$string['abilityestimated_help'] = 'The estimated ability of a test-taker aligns with the question difficulty at which the test-taker has a 50% probability of answering the question correctly. To identify the performance level, match the ability value with the questions level range (see the range after the \'/\' symbol).';
$string['attemptfeedbackdefaulttext'] = 'You\'ve finished the attempt, thank you for taking the quiz!';
$string['attemptquestion_ability'] = 'Ability Measure';
$string['attemptquestionsprogress'] = 'Questions progress: {$a}';
$string['attemptquestionsprogress_help'] = 'The maximum number of questions displayed here is not necessarily the number of questions you have to take during the quiz. It is the MAXIMUM POSSIBLE number of questions you might take, the quiz may finish earlier if the ability measure is sufficiently defined.';
$string['attempt_summary'] = 'Attempt Summary';
$string['attemptsusernoprevious'] = 'You haven\'t attempted this quiz yet.';
$string['attemptsuserprevious'] = 'Your previous attempts';
$string['attemptnofirstquestion'] = 'Sorry, but couldn\'t define the first question to start the attempt, the quiz is possibly misconfigured. ';
$string['completionattemptcompletedcminfo'] = 'Complete an attempt';
$string['completionattemptcompletedform'] = 'Student must have al least one completed attempt on this activity';
$string['eventattemptcompleted'] = 'Attempt completed';
$string['modformshowattemptprogress'] = 'Show quiz progress to students';
$string['modformshowattemptprogress_help'] = 'When selected, during attempt, a student will see a progress bar depicting how many questions are answered out of the maximum number.';
//KINGHT: Strings for students' ability to review the attempt results.
$string['modformshowownattemptresult'] = 'Show attempt results to students';
$string['modformshowownattemptresult_help'] = 'Sometimes it may be useful to provide students with the ability to review their own results. With this setting enabled a student may press a link to review their previous attempts after finishing the attempt and in the attempts summary as well.';
$string['showabilitymeasure'] = 'Show ability measure to students';
$string['showabilitymeasure_help'] = 'Sometimes it may be useful to reveal ability estimations to students after taking an adaptive quiz. With this setting enabled a student may see ability estimation in the attempts summary and right after finishing an attempt as well.';
$string['questionspoolerrornovalidstartingquestions'] = 'The selected questions categories do not contain questions which are properly tagged to match the selected starting level of difficulty.';
$string['reportanswersdistributionchartdisplaystacked'] = 'Display bars stacked';
$string['reportanswersdistributionchartnumrightlabel'] = 'Number of correct answers';
$string['reportanswersdistributionchartnumwronglabel'] = 'Number of wrong answers';
$string['reportanswersdistributionchartxaxislabel'] = 'Question difficulty';
$string['reportanswersdistributionchartyaxislabel'] = 'Number of answers';
$string['reportattemptadmanswerright'] = 'C';
$string['reportattemptadmanswerwrong'] = 'W';
$string['reportattemptadmchartadmdifflabel'] = 'Administered Difficulty';
$string['reportattemptadmcharttargetdifflabel'] = 'Target Difficulty';
$string['reportattemptanswerdistributiontab'] = 'Answer Distribution';
$string['reportattemptgraphtab'] = 'Attempt Graph';
$string['reportattemptgraphtabletitle'] = 'Table View of Attempt Graph';
$string['reportattemptquestionsdetailstab'] = 'Questions Details';
$string['reportattemptreviewpageheading'] = '{$a->quizname} - reviewing attempt by {$a->fullname} submitted on {$a->finished}';
$string['reportattemptsbothenrolledandnotenrolled'] = 'all users who ever made attempts';
$string['reportattemptsdownloadfilename'] = '{$a}_attempts_report';
$string['reportattemptsenrolledwithattempts'] = 'participants who made attempts';
$string['reportattemptsenrolledwithnoattempts'] = 'participants without attempts made';
$string['reportattemptsfilterformsubmit'] = 'Filter';
$string['reportattemptsfilterincludeinactiveenrolments'] = 'Include users with inactive enrolments';
$string['reportattemptsfilterincludeinactiveenrolments_help'] = 'Whether include users with suspended enrolments.';
$string['reportattemptsfilterusers'] = 'Show';
$string['reportattemptsfilterformheader'] = 'Filtering';
$string['reportattemptsnotenrolled'] = 'not enrolled users who made attempts';
$string['reportattemptspersistentfilter'] = 'Persistent filter';
$string['reportattemptspersistentfilter_help'] = 'When checked, the filter settings below will be stored when submitted, and then applied each time you visit the report page.';
$string['reportattemptsprefsformheader'] = 'Report Preferences';
$string['reportattemptsprefsformsubmit'] = 'Apply';
$string['reportattemptsresetfilter'] = 'Reset filter';
$string['reportattemptsshowinitialbars'] = 'Show initials bar';
$string['reportattemptsusersperpage'] = 'Number of users displayed:';
$string['reportattemptsummarytab'] = 'Attempt Summary';
$string['reportindividualuserattemptpageheading'] = '{$a->quizname} - individual user attempts report for {$a->username}';
$string['reportuserattemptstitleshort'] = '{$a}\'s attempt';
$string['reportquestionanalysispageheading'] = '{$a} - questions report';
$string['modulenameplural'] = 'Adaptive Quiz';
$string['modulename'] = 'Adaptive Quiz';
$string['modulename_help'] = 'The Adaptive Quiz activity enables a teacher to create quizes that efficiently measure the takers\' abilities. Adaptive quizes are comprised of questions selected from the question bank that are tagged with a score of their difficulty. The questions are chosen to match the estimated ability level of the current test-taker. If the test-taker succeeds on a question, a more challenging question is presented next. If the test-taker answers a question incorrectly, a less-challenging question is presented next. This technique will develop into a sequence of questions converging on the test-taker\'s effective ability level. The quiz stops when the test-taker\'s ability is determined to the required accuracy.
This activity is best suited to determining an ability measure along a unidimensional scale. While the scale can be very broad, the questions must all provide a measure of ability or aptitude on the same scale. In a placement test for example, questions low on the scale that novices are able to answer correctly should also be answerable by experts, while questions higher on the scale should only be answerable by experts or a lucky guess. Questions that do not discriminate between takers of different abilities on will make the test ineffective and may provide inconclusive results.
Questions used in the Adaptive Quiz must
* be automatically scored as correct/incorrect
* be tagged with their difficulty using \'adpq_\' followed by a positive integer that is within the range for the quiz
The Adaptive Quiz can be configured to
* define the range of question-difficulties/user-abilities to be measured. 1-10, 1-16, and 1-100 are examples of valid ranges.
* define the precision required before the quiz is stopped. Often an error of 5% in the ability measure is an appropriate stopping rule
* require a minimum number of questions to be answered
* require a maximum number of questions that can be answered
This description and the testing process in this activity are based on <a href="http://www.rasch.org/memo69.pdf">Computer-Adaptive Testing: A Methodology Whose Time Has Come</a> by John Michael Linacre, Ph.D. MESA Psychometric Laboratory - University of Chicago. MESA Memorandum No. 69.';
$string['pluginadministration'] = 'Adaptive Quiz';
$string['pluginname'] = 'Adaptive Quiz';
$string['nonewmodules'] = 'No Adaptive Quiz instances found';
$string['adaptivequizname'] = 'Name';
$string['adaptivequizname_help'] = 'Enter the name of the Adaptive Quiz instance';
$string['adaptivequiz:addinstance'] = 'Add a new adaptive quiz';
$string['adaptivequiz:viewreport'] = 'View adaptive quiz reports';
$string['adaptivequiz:reviewattempts'] = 'Review adaptive quiz submissions';
$string['adaptivequiz:attempt'] = 'Attempt adaptive quiz';
$string['attemptsallowed'] = 'Attempts allowed';
$string['attemptsallowed_help'] = 'The number of times a student may attempt this activity';
$string['requirepassword'] = 'Required password';
$string['requirepassword_help'] = 'Students are required to enter a password before beginning their attempt';
$string['browsersecurity'] = 'Browser security';
$string['browsersecurity_help'] = 'If "Full screen pop-up with some JavaScript security" is selected the quiz will only start if the student has a JavaScript-enabled web-browser, the quiz appears in a full screen popup window that covers all the other windows and has no navigation controls and students are prevented, as far as is possible, from using facilities like copy and paste';
$string['minimumquestions'] = 'Minimum number of questions';
$string['minimumquestions_help'] = 'The minimum number of questions the student must attempt';
$string['maximumquestions'] = 'Maximum number of questions';
$string['maximumquestions_help'] = 'The maximum number of questions the student can attempt';
$string['startinglevel'] = 'Starting level of difficulty';
$string['startinglevel_help'] = 'The the student begins an attempt, the activity will randomly select a question matching the level of difficulty';
$string['lowestlevel'] = 'Lowest level of difficulty';
$string['lowestlevel_help'] = 'The lowest or least difficult level the assessment can select questions from. During an attempt the activity will not go beyond this level of difficulty';
$string['highestlevel'] = 'Highest level of difficulty';
$string['highestlevel_help'] = 'The highest or most difficult level the assessment can select questions from. During an attempt the activity will not go beyond this level of difficulty';
//KNIGHT
$string['acceptancethreshold'] = 'Acceptance Threshold';
$string['acceptancethreshold_help'] = 'Input a value between 0 and 1 that determines the acceptable level of correctness';
$string['formacceptanceleveloutofbounds'] = 'Acceptance threshold must be a value between 0 and 1';
$string['questionpool'] = 'Question pool';
$string['questionpool_help'] = 'Select the question category(ies) where the activity will pull questions from during an attempt.';
$string['formelementempty'] = 'Input a positive integer from 1 to 999';
$string['formelementnumeric'] = 'Input a numeric value from 1 to 999';
$string['formelementnegative'] = 'Input a positive number from 1 to 999';
$string['formminquestgreaterthan'] = 'Minimum number of questions must be less than maximum number of questions';
$string['formlowlevelgreaterthan'] = 'Lowest level must be less than highest level';
$string['formstartleveloutofbounds'] = 'The starting level must be a number that is inbetween the lowest and highest level';
$string['standarderror'] = 'Standard Error to stop';
$string['standarderror_help'] = 'When the amount of error in the measure of the user\'s ability drops below this amount, the quiz will stop. Tune this value from the default of 5% to require more or less precision in the ability measure';
$string['formelementdecimal'] = 'Input a decimal number. Maximum 10 digits long and maximum 5 digits to the right of the decimal point';
$string['attemptfeedback'] = 'Attempt feedback';
$string['attemptfeedback_help'] = 'The attempt feedback is displayed to the user once the attempt is finished';
$string['formquestionpool'] = 'Select at least one question category';
$string['submitanswer'] = 'Submit answer';
$string['startattemptbtn'] = 'Start attempt';
$string['errorfetchingquest'] = 'Unable to fetch a question for level {$a->level}';
$string['leveloutofbounds'] = 'Requested level {$a->level} out of bounds for the attempt';
$string['errorattemptstate'] = 'There was an error in determining the state of the attempt';
$string['nopermission'] = 'You don\t have permission to view this resource';
$string['maxquestattempted'] = 'Maximum number of questions attempted';
$string['notyourattempt'] = 'This is not your attempt at the activity';
$string['noattemptsallowed'] = 'No more attempts allowed at this activity';
$string['updateattempterror'] = 'Error trying to update attempt record';
$string['numofattemptshdr'] = 'Number of attempts';
$string['standarderrorhdr'] = 'Standard error';
$string['errorlastattpquest'] = 'Error checking the response value for the last attempted question';
$string['errornumattpzero'] = 'Error with number of questions attempted equals zero, but user submitted an answer to previous question';
$string['errorsumrightwrong'] = 'Sum of correct and incorrect answers does not equal the total number of questions attempted';
$string['calcerrorwithinlimits'] = 'Calculated standard error of {$a->calerror} is within the limits imposed by the activity {$a->definederror}';
$string['missingtagprefix'] = 'Missing tag prefix';
$string['recentactquestionsattempted'] = 'Questions attempted: {$a}';
$string['recentattemptstate'] = 'State of attempt:';
$string['recentinprogress'] = 'In progress';
$string['notinprogress'] = 'This attempt is not in progress.';
$string['recentcomplete'] = 'Completed';
$string['functiondisabledbysecuremode'] = 'That functionality is currently disabled';
$string['enterrequiredpassword'] = 'Enter required password';
$string['requirepasswordmessage'] = 'To attempt this quiz you need to know the quiz password';
$string['wrongpassword'] = 'Password is incorrect';
$string['attemptstate'] = 'State of attempt';
$string['attemptstopcriteria'] = 'Reason for stopping attempt';
$string['questionsattempted'] = 'Sum of questions attempted';
$string['attemptfinishedtimestamp'] = 'Attempt finish time';
$string['reviewattempt'] = 'Review attempt';
$string['indvuserreport'] = 'Individual user attempts report for {$a}';
$string['activityreports'] = 'Attempts report';
$string['stopingconditionshdr'] = 'Stopping conditions';
$string['reviewattemptreport'] = 'Reviewing attempt by {$a->fullname} submitted on {$a->finished}';
$string['deleteattemp'] = 'Delete attempt';
$string['confirmdeleteattempt'] = 'Confirming the deletion of attempt from {$a->name} submitted on {$a->timecompleted}';
$string['attemptdeleted'] = 'Attempt deleted for {$a->name} submitted on {$a->timecompleted}';
$string['closeattempt'] = 'Close attempt';
$string['confirmcloseattempt'] = 'Are you sure that you wish to close and finalize this attempt of {$a->name}?';
$string['confirmcloseattemptstats'] = 'This attempt was started on {$a->started} and last updated on {$a->modified}.';
$string['confirmcloseattemptscore'] = '{$a->num_questions} questions were answered and the score so far is {$a->measure} {$a->standarderror}.';
$string['attemptclosedstatus'] = 'Manually closed by {$a->current_user_name} (user-id: {$a->current_user_id}) on {$a->now}.';
$string['attemptclosed'] = 'The attempt has been manually closed.';
$string['errorclosingattempt_alreadycomplete'] = 'This attempt is already complete, it cannot be manually closed.';
$string['formstderror'] = 'Must enter a percent less than 50 and greater than or equal to 0';
$string['score'] = 'Score';
$string['bestscore'] = 'Best Score';
$string['bestscorestderror'] = 'Standard Error';
$string['attempt_questiondetails'] = 'Question Details';
$string['attemptstarttime'] = 'Attempt start time';
$string['attempttotaltime'] = 'Total time (hh:mm:ss)';
$string['attempt_user'] = 'User';
$string['attempt_state'] = 'Attempt state';
$string['attemptquestion_level'] = 'Question Level';
$string['attemptquestion_rightwrong'] = 'Answer Correct/Wrong';
$string['attemptquestion_difficulty'] = 'Question Difficulty (logits)';
$string['attemptquestion_diffsum'] = 'Difficulty Sum';
$string['attemptquestion_abilitylogits'] = 'Measured Ability (logits)';
$string['attemptquestion_stderr'] = 'Standard Error (&plusmn;&nbsp;logits)';
$string['graphlegend_error'] = 'Standard Error';
$string['questionnumber'] = 'Question #';
$string['na'] = 'n/a';
$string['downloadcsv'] = 'Download CSV';
$string['grademethod'] = 'Grading method';
$string['gradehighest'] = 'Highest grade';
$string['attemptfirst'] = 'First attempt';
$string['attemptlast'] = 'Last attempt';
$string['grademethod_help'] = 'When multiple attempts are allowed, the following methods are available for calculating the final quiz grade:
* Highest grade of all attempts
* First attempt (all other attempts are ignored)
* Last attempt (all other attempts are ignored)';
$string['resetadaptivequizsall'] = 'Delete all Adaptive Quiz attempts';
$string['all_attempts_deleted'] = 'All Adaptive Quiz attempts were deleted';
$string['all_grades_removed'] = 'All Adaptive Quiz grades were removed';
//KNIGHT
$string['questionchecktrigger'] = 'Question analysis trigger';
$string['questionchecktrigger_help'] = 'Number of attempts that need to be completed before question analysis is advised. The default value of 0 means there will be no question revision alert.';
$string['questioncheckmessage'] = 'A sufficient number of attempts has now been conducted to allow revision of question categorisation. Once you have visited the Question Analysis tab, this notification will disappear.';
$string['questionanalysisbtn'] = 'Question Analysis';
$string['id'] = 'ID';
$string['name'] = 'Name';
$string['questions_report'] = 'Questions Report';
$string['question_report'] = 'Question Analysis';
$string['times_used_display_name'] = 'Times Used';
$string['percent_correct_display_name'] = '% Correct';
$string['discrimination_display_name'] = 'Discrimination';
$string['back_to_all_questions'] = '&laquo; Back to all questions';
$string['answers_display_name'] = 'Answers';
$string['answer'] = 'Answer';
$string['statistic'] = 'Statistic';
$string['value'] = 'Value';
$string['highlevelusers'] = 'Users above the question-level';
$string['midlevelusers'] = 'Users near the question-level';
$string['lowlevelusers'] = 'Users below the question-level';
$string['user'] = 'User';
$string['result'] = 'Result';
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment