first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
@@ -0,0 +1,99 @@
<?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/>.
/**
* Privacy Subsystem implementation for quiz_responses.
*
* @package quiz_responses
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace quiz_responses\privacy;
use core_privacy\local\metadata\collection;
use core_privacy\local\request\writer;
use core_privacy\local\request\transform;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/question/engine/questionattempt.php');
/**
* Privacy Subsystem for quiz_responses with user preferences.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\user_preference_provider {
/**
* Returns meta data about this system.
*
* @param collection $collection The initialised collection to add items to.
* @return collection A listing of user data stored through this system.
*/
public static function get_metadata(collection $collection): collection {
$collection->add_user_preference('quiz_report_responses_qtext', 'privacy:preference:qtext');
$collection->add_user_preference('quiz_report_responses_resp', 'privacy:preference:resp');
$collection->add_user_preference('quiz_report_responses_right', 'privacy:preference:right');
$collection->add_user_preference('quiz_report_responses_which_tries', 'privacy:preference:which_tries');
return $collection;
}
/**
* Export all user preferences for the plugin.
*
* @param int $userid The userid of the user whose data is to be exported.
*/
public static function export_user_preferences(int $userid) {
$preferences = [
'qtext',
'resp',
'right',
];
foreach ($preferences as $key) {
$preference = get_user_preferences("quiz_report_responses_{$key}", null, $userid);
if (null !== $preference) {
$desc = get_string("privacy:preference:{$key}", 'quiz_responses');
writer::export_user_preference('quiz_responses', $key, transform::yesno($preference), $desc);
}
}
$preference = get_user_preferences("quiz_report_responses_which_tries", null, $userid);
if (null !== $preference) {
switch($preference) {
case \question_attempt::FIRST_TRY:
$value = get_string("privacy:preference:which_tries:first", 'quiz_responses');
break;
case \question_attempt::LAST_TRY:
$value = get_string("privacy:preference:which_tries:last", 'quiz_responses');
break;
case \question_attempt::ALL_TRIES:
$value = get_string("privacy:preference:which_tries:all", 'quiz_responses');
break;
}
$desc = get_string("privacy:preference:which_tries", 'quiz_responses');
writer::export_user_preference('quiz_responses', 'which_tries', $value, $desc);
}
}
}
+39
View File
@@ -0,0 +1,39 @@
<?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/>.
/**
* Post-install script for the quiz responses report.
* @package quiz_responses
* @copyright 2013 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Post-install script
*/
function xmldb_quiz_responses_install() {
global $DB;
$record = new stdClass();
$record->name = 'responses';
$record->displayorder = '9000';
$DB->insert_record('quiz_reports', $record);
}
@@ -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/>.
/**
* This file defines the quiz responses table for showing first or all tries at a question.
*
* @package quiz_responses
* @copyright 2014 The Open University
* @author Jamie Pratt <me@jamiep.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
use mod_quiz\quiz_attempt;
defined('MOODLE_INTERNAL') || die();
/**
* This is a table subclass for displaying the quiz responses report, showing first or all tries.
*
* @package quiz_responses
* @copyright 2014 The Open University
* @author Jamie Pratt <me@jamiep.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class quiz_first_or_all_responses_table extends quiz_last_responses_table {
/**
* The full question usage object for each try shown in report.
*
* @var question_usage_by_activity[]
*/
protected $questionusagesbyactivity;
protected function field_from_extra_data($tablerow, $slot, $field) {
$questionattempt = $this->get_question_attempt($tablerow->usageid, $slot);
switch($field) {
case 'questionsummary' :
return $questionattempt->get_question_summary();
case 'responsesummary' :
return $this->get_summary_after_try($tablerow, $slot);
case 'rightanswer' :
return $questionattempt->get_right_answer_summary();
default :
throw new coding_exception('Unknown question attempt field.');
}
}
protected function load_extra_data() {
if (count($this->rawdata) === 0) {
return;
}
$qubaids = $this->get_qubaids_condition();
$dm = new question_engine_data_mapper();
$this->questionusagesbyactivity = $dm->load_questions_usages_by_activity($qubaids);
// Insert an extra field in attempt data and extra rows where necessary.
$newrawdata = [];
foreach ($this->rawdata as $attempt) {
if (!isset($this->questionusagesbyactivity[$attempt->usageid])) {
// This is a user without attempts.
$attempt->try = 0;
$attempt->lasttryforallparts = true;
$newrawdata[] = $attempt;
continue;
}
// We have an attempt, which may require several rows.
$maxtriesinanyslot = 1;
foreach ($this->questionusagesbyactivity[$attempt->usageid]->get_slots() as $slot) {
$tries = $this->get_no_of_tries($attempt, $slot);
$maxtriesinanyslot = max($maxtriesinanyslot, $tries);
}
for ($try = 1; $try <= $maxtriesinanyslot; $try++) {
$newtablerow = clone($attempt);
$newtablerow->lasttryforallparts = ($try == $maxtriesinanyslot);
if ($try !== $maxtriesinanyslot) {
$newtablerow->state = quiz_attempt::IN_PROGRESS;
}
$newtablerow->try = $try;
$newrawdata[] = $newtablerow;
if ($this->options->whichtries == question_attempt::FIRST_TRY) {
break;
}
}
}
$this->rawdata = $newrawdata;
}
/**
* Return the question attempt object.
*
* @param int $questionusagesid
* @param int $slot
* @return question_attempt
*/
protected function get_question_attempt($questionusagesid, $slot) {
return $this->questionusagesbyactivity[$questionusagesid]->get_question_attempt($slot);
}
/**
* Find the state for $slot given after this try.
*
* @param stdClass $tablerow row data
* @param int $slot Slot number.
* @return question_state The question state after the attempt.
*/
protected function slot_state($tablerow, $slot) {
$qa = $this->get_question_attempt($tablerow->usageid, $slot);
$submissionsteps = $qa->get_steps_with_submitted_response_iterator();
$step = $submissionsteps[$tablerow->try];
if ($step === null) {
return null;
}
if ($this->is_last_try($tablerow, $slot, $tablerow->try)) {
// If this is the last try then the step with the try data does not contain the correct state. We need to
// use the last step's state, after the attempt has been finished.
return $qa->get_state();
}
return $step->get_state();
}
/**
* Get the summary of the response after the try.
*
* @param stdClass $tablerow row data
* @param int $slot Slot number.
* @return string summary for the question after this try.
*/
public function get_summary_after_try($tablerow, $slot) {
$qa = $this->get_question_attempt($tablerow->usageid, $slot);
if (!($qa->get_question(false) instanceof question_manually_gradable)) {
// No responses, and we cannot call summarise_response below.
return null;
}
$submissionsteps = $qa->get_steps_with_submitted_response_iterator();
$step = $submissionsteps[$tablerow->try];
if ($step === null) {
return null;
}
$qtdata = $step->get_qt_data();
return $qa->get_question()->summarise_response($qtdata);
}
/**
* Has this question usage been flagged?
*
* @param int $questionusageid Question usage id.
* @param int $slot Slot number
* @return bool Has it been flagged?
*/
protected function is_flagged($questionusageid, $slot) {
return $this->get_question_attempt($questionusageid, $slot)->is_flagged();
}
/**
* The grade for this slot after this try.
*
* @param stdClass $tablerow attempt data from db.
* @param int $slot Slot number.
* @return float The fraction.
*/
protected function slot_fraction($tablerow, $slot) {
$qa = $this->get_question_attempt($tablerow->usageid, $slot);
$submissionsteps = $qa->get_steps_with_submitted_response_iterator();
$step = $submissionsteps[$tablerow->try];
if ($step === null) {
return null;
}
if ($this->is_last_try($tablerow, $slot, $tablerow->try)) {
// If this is the last try then the step with the try data does not contain the correct fraction. We need to
// use the last step's fraction, after the attempt has been finished.
return $qa->get_fraction();
}
return $step->get_fraction();
}
/**
* Is this the last try in the question attempt?
*
* @param stdClass $tablerow attempt data from db.
* @param int $slot Slot number
* @param int $tryno try no
* @return bool Is it the last try?
*/
protected function is_last_try($tablerow, $slot, $tryno) {
return $tryno == $this->get_no_of_tries($tablerow, $slot);
}
/**
* How many tries were attempted at this question in this slot, during this usage?
*
* @param stdClass $tablerow attempt data from db.
* @param int $slot Slot number
* @return int the number of tries in the question attempt for slot $slot.
*/
public function get_no_of_tries($tablerow, $slot) {
return count($this->get_question_attempt($tablerow->usageid, $slot)->get_steps_with_submitted_response_iterator());
}
/**
* What is the step no this try was seen in?
*
* @param int $questionusageid The question usage id.
* @param int $slot Slot number
* @param int $tryno Try no
* @return int the step no or zero if not found
*/
protected function step_no_for_try($questionusageid, $slot, $tryno) {
$qa = $this->get_question_attempt($questionusageid, $slot);
return $qa->get_steps_with_submitted_response_iterator()->step_no_for_try($tryno);
}
public function col_checkbox($tablerow) {
if ($tablerow->try != 1) {
return '';
} else {
return parent::col_checkbox($tablerow);
}
}
/**
* Cell value function for email column. This extracts the contents for any cell in the email column from the row data.
*
* @param stdClass $tablerow Row data.
* @return string What to put in the cell for this column, for this row data.
*/
public function col_email($tablerow) {
if ($tablerow->try > 1) {
return '';
} else {
return $tablerow->email;
}
}
/**
* Cell value function for sumgrades column. This extracts the contents for any cell in the sumgrades column from the row data.
*
* @param stdClass $tablerow Row data.
* @return string What to put in the cell for this column, for this row data.
*/
public function col_sumgrades($tablerow) {
if ($tablerow->try == 0) {
// We are showing a user without a quiz attempt.
return '-';
} else if (!$tablerow->lasttryforallparts) {
// There are more rows to come for this quiz attempt, so we will show this later.
return '';
} else {
// Last row for this attempt. Now is the time to show attempt-related data.
return parent::col_sumgrades($tablerow);
}
}
public function col_state($tablerow) {
if ($tablerow->try == 0) {
// We are showing a user without a quiz attempt.
return '-';
} else if (!$tablerow->lasttryforallparts) {
// There are more rows to come for this quiz attempt, so we will show this later.
return '';
} else {
// Last row for this attempt. Now is the time to show attempt-related data.
return parent::col_state($tablerow);
}
}
public function get_row_class($tablerow) {
if ($this->options->whichtries == question_attempt::ALL_TRIES && $tablerow->lasttryforallparts) {
return 'lastrowforattempt';
} else {
return '';
}
}
public function make_review_link($data, $tablerow, $slot) {
if ($this->slot_state($tablerow, $slot) === null) {
return $data;
} else {
return parent::make_review_link($data, $tablerow, $slot);
}
}
}
@@ -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/>.
/**
* Strings for component 'quiz_responses', language 'en', branch 'MOODLE_20_STABLE'
*
* @package quiz_responses
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['cannotloadoptions'] = 'Could not load question options';
$string['include'] = 'Include the';
$string['mustselectcols'] = 'You must include something.';
$string['pagesize'] = 'Page size';
$string['pluginname'] = 'Responses';
$string['privacy:preference:qtext'] = 'Whether to show the question text columns.';
$string['privacy:preference:resp'] = 'Whether to show the students\' response columns.';
$string['privacy:preference:right'] = 'Whether to show the correct response columns.';
$string['privacy:preference:which_tries'] = 'Which tries to show responses from.';
$string['privacy:preference:which_tries:first'] = 'The first try at a question during an attempt by a user.';
$string['privacy:preference:which_tries:last'] = 'The last try at a question during an attempt by a user.';
$string['privacy:preference:which_tries:all'] = 'All tries at a question during an attempt by a user.';
$string['questiontext'] = 'question text';
$string['reportresponses'] = 'Responses';
$string['response'] = 'response';
$string['responses'] = 'Responses';
$string['responsesdownload'] = 'Responses download';
$string['responsesfilename'] = 'responses';
$string['responsesoptions'] = 'Responses options';
$string['responsesreport'] = 'Responses report';
$string['responsestitle'] = 'Responses';
$string['responsex'] = 'Response {$a}';
$string['rightanswer'] = 'right answer';
$string['rightanswerx'] = 'Right answer {$a}';
$string['showattempts'] = 'Only show / download attempts';
$string['showthe'] = 'Show the';
$string['summaryofquestiontext'] = 'Summary of the question';
$string['summaryofresponse'] = 'Summary of the response given';
$string['summaryofrightanswer'] = 'Summary of the right answer';
@@ -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/>.
use mod_quiz\local\reports\attempts_report_table;
use mod_quiz\quiz_attempt;
/**
* This is a table subclass for displaying the quiz responses report.
*
* @copyright 2008 Jean-Michel Vedrine
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class quiz_last_responses_table extends attempts_report_table {
/**
* Constructor
* @param stdClass $quiz
* @param context $context
* @param string $qmsubselect
* @param quiz_responses_options $options
* @param \core\dml\sql_join $groupstudentsjoins
* @param \core\dml\sql_join $studentsjoins
* @param array $questions
* @param moodle_url $reporturl
*/
public function __construct($quiz, $context, $qmsubselect, quiz_responses_options $options,
\core\dml\sql_join $groupstudentsjoins, \core\dml\sql_join $studentsjoins, $questions, $reporturl) {
parent::__construct('mod-quiz-report-responses-report', $quiz, $context,
$qmsubselect, $options, $groupstudentsjoins, $studentsjoins, $questions, $reporturl);
}
public function build_table() {
if (!$this->rawdata) {
return;
}
$this->strtimeformat = str_replace(',', ' ', get_string('strftimedatetime'));
parent::build_table();
}
public function col_sumgrades($attempt) {
if ($attempt->state != quiz_attempt::FINISHED) {
return '-';
}
$grade = quiz_rescale_grade($attempt->sumgrades, $this->quiz);
if ($this->is_downloading()) {
return $grade;
}
$gradehtml = '<a href="review.php?q=' . $this->quiz->id . '&amp;attempt=' .
$attempt->attempt . '">' . $grade . '</a>';
return $gradehtml;
}
public function data_col($slot, $field, $attempt) {
if ($attempt->usageid == 0) {
return '-';
}
$value = $this->field_from_extra_data($attempt, $slot, $field);
if (is_null($value)) {
$summary = '-';
} else {
$summary = trim($value);
}
if ($this->is_downloading() && $this->is_downloading() != 'html') {
return $summary;
}
$summary = s($summary);
if ($this->is_downloading() || $field != 'responsesummary') {
return $summary;
}
return $this->make_review_link($summary, $attempt, $slot);
}
/**
* Column text from the extra data loaded in load_extra_data(), before html formatting etc.
*
* @param stdClass $attempt
* @param int $slot
* @param string $field
* @return string
*/
protected function field_from_extra_data($attempt, $slot, $field) {
if (!isset($this->lateststeps[$attempt->usageid][$slot])) {
return '-';
}
return $this->lateststeps[$attempt->usageid][$slot]->$field;
}
public function other_cols($colname, $attempt) {
if (preg_match('/^question(\d+)$/', $colname, $matches)) {
return $this->data_col($matches[1], 'questionsummary', $attempt);
} else if (preg_match('/^response(\d+)$/', $colname, $matches)) {
return $this->data_col($matches[1], 'responsesummary', $attempt);
} else if (preg_match('/^right(\d+)$/', $colname, $matches)) {
return $this->data_col($matches[1], 'rightanswer', $attempt);
} else {
return parent::other_cols($colname, $attempt);
}
}
protected function requires_extra_data() {
return true;
}
protected function is_latest_step_column($column) {
if (preg_match('/^(?:question|response|right)([0-9]+)/', $column, $matches)) {
return $matches[1];
}
return false;
}
/**
* Get any fields that might be needed when sorting on date for a particular slot.
* @param int $slot the slot for the column we want.
* @param string $alias the table alias for latest state information relating to that slot.
* @return string sql fragment to alias fields.
*/
protected function get_required_latest_state_fields($slot, $alias) {
global $DB;
return $DB->sql_order_by_text("{$alias}.questionsummary") . " AS question{$slot},
" . $DB->sql_order_by_text("{$alias}.rightanswer") . " AS right{$slot},
" . $DB->sql_order_by_text("{$alias}.responsesummary") . " AS response{$slot}";
}
}
+193
View File
@@ -0,0 +1,193 @@
<?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/>.
/**
* This file defines the quiz responses report class.
*
* @package quiz_responses
* @copyright 2006 Jean-Michel Vedrine
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
use mod_quiz\local\reports\attempts_report;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/mod/quiz/report/responses/responses_options.php');
require_once($CFG->dirroot . '/mod/quiz/report/responses/responses_form.php');
require_once($CFG->dirroot . '/mod/quiz/report/responses/last_responses_table.php');
require_once($CFG->dirroot . '/mod/quiz/report/responses/first_or_all_responses_table.php');
/**
* Quiz report subclass for the responses report.
*
* This report lists some combination of
* * what question each student saw (this makes sense if random questions were used).
* * the response they gave,
* * and what the right answer is.
*
* Like the overview report, there are options for showing students with/without
* attempts, and for deleting selected attempts.
*
* @copyright 1999 onwards Martin Dougiamas and others {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class quiz_responses_report extends attempts_report {
public function display($quiz, $cm, $course) {
global $OUTPUT, $DB;
list($currentgroup, $studentsjoins, $groupstudentsjoins, $allowedjoins) = $this->init(
'responses', 'quiz_responses_settings_form', $quiz, $cm, $course);
$options = new quiz_responses_options('responses', $quiz, $cm, $course);
if ($fromform = $this->form->get_data()) {
$options->process_settings_from_form($fromform);
} else {
$options->process_settings_from_params();
}
$this->form->set_data($options->get_initial_form_data());
// Load the required questions.
$questions = quiz_report_get_significant_questions($quiz);
// Prepare for downloading, if applicable.
$courseshortname = format_string($course->shortname, true,
['context' => context_course::instance($course->id)]);
if ($options->whichtries === question_attempt::LAST_TRY) {
$tableclassname = 'quiz_last_responses_table';
} else {
$tableclassname = 'quiz_first_or_all_responses_table';
}
$table = new $tableclassname($quiz, $this->context, $this->qmsubselect,
$options, $groupstudentsjoins, $studentsjoins, $questions, $options->get_url());
$filename = quiz_report_download_filename(get_string('responsesfilename', 'quiz_responses'),
$courseshortname, $quiz->name);
$table->is_downloading($options->download, $filename,
$courseshortname . ' ' . format_string($quiz->name, true));
if ($table->is_downloading()) {
raise_memory_limit(MEMORY_EXTRA);
}
$this->hasgroupstudents = false;
if (!empty($groupstudentsjoins->joins)) {
$sql = "SELECT DISTINCT u.id
FROM {user} u
$groupstudentsjoins->joins
WHERE $groupstudentsjoins->wheres";
$this->hasgroupstudents = $DB->record_exists_sql($sql, $groupstudentsjoins->params);
}
$hasstudents = false;
if (!empty($studentsjoins->joins)) {
$sql = "SELECT DISTINCT u.id
FROM {user} u
$studentsjoins->joins
WHERE $studentsjoins->wheres";
$hasstudents = $DB->record_exists_sql($sql, $studentsjoins->params);
}
if ($options->attempts == self::ALL_WITH) {
// This option is only available to users who can access all groups in
// groups mode, so setting allowed to empty (which means all quiz attempts
// are accessible, is not a security problem.
$allowedjoins = new \core\dml\sql_join();
}
$this->process_actions($quiz, $cm, $currentgroup, $groupstudentsjoins, $allowedjoins, $options->get_url());
$hasquestions = quiz_has_questions($quiz->id);
// Start output.
if (!$table->is_downloading()) {
// Only print headers if not asked to download data.
$this->print_standard_header_and_messages($cm, $course, $quiz,
$options, $currentgroup, $hasquestions, $hasstudents);
// Print the display options.
$this->form->display();
}
$hasstudents = $hasstudents && (!$currentgroup || $this->hasgroupstudents);
if ($hasquestions && ($hasstudents || $options->attempts == self::ALL_WITH)) {
$table->setup_sql_queries($allowedjoins);
if (!$table->is_downloading()) {
// Print information on the grading method.
if ($strattempthighlight = quiz_report_highlighting_grading_method(
$quiz, $this->qmsubselect, $options->onlygraded)) {
echo '<div class="quizattemptcounts">' . $strattempthighlight . '</div>';
}
}
// Define table columns.
$columns = [];
$headers = [];
if (!$table->is_downloading() && $options->checkboxcolumn) {
$columnname = 'checkbox';
$columns[] = $columnname;
$headers[] = $table->checkbox_col_header($columnname);
}
$this->add_user_columns($table, $columns, $headers);
$this->add_state_column($columns, $headers);
if ($table->is_downloading()) {
$this->add_time_columns($columns, $headers);
}
$this->add_grade_columns($quiz, $options->usercanseegrades, $columns, $headers);
foreach ($questions as $id => $question) {
if ($options->showqtext) {
$columns[] = 'question' . $id;
$headers[] = get_string('questionx', 'question', $question->displaynumber);
}
if ($options->showresponses) {
$columns[] = 'response' . $id;
$headers[] = get_string('responsex', 'quiz_responses', $question->displaynumber);
}
if ($options->showright) {
$columns[] = 'right' . $id;
$headers[] = get_string('rightanswerx', 'quiz_responses', $question->displaynumber);
}
}
$table->define_columns($columns);
$table->define_headers($headers);
$table->sortable(true, 'uniqueid');
// Set up the table.
$table->define_baseurl($options->get_url());
$this->configure_user_columns($table);
$table->no_sorting('feedbacktext');
$table->column_class('sumgrades', 'bold');
$table->set_attribute('id', 'responses');
$table->collapsible(true);
$table->out($options->pagesize, true);
}
return true;
}
}
@@ -0,0 +1,65 @@
<?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/>.
use mod_quiz\local\reports\attempts_report;
use mod_quiz\local\reports\attempts_report_options_form;
/**
* Quiz responses report settings form.
*
* @copyright 2008 Jean-Michel Vedrine
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class quiz_responses_settings_form extends attempts_report_options_form {
protected function other_preference_fields(MoodleQuickForm $mform) {
$mform->addGroup([
$mform->createElement('advcheckbox', 'qtext', '',
get_string('questiontext', 'quiz_responses')),
$mform->createElement('advcheckbox', 'resp', '',
get_string('response', 'quiz_responses')),
$mform->createElement('advcheckbox', 'right', '',
get_string('rightanswer', 'quiz_responses')),
], 'coloptions', get_string('showthe', 'quiz_responses'), [' '], false);
$mform->disabledIf('qtext', 'attempts', 'eq', attempts_report::ENROLLED_WITHOUT);
$mform->disabledIf('resp', 'attempts', 'eq', attempts_report::ENROLLED_WITHOUT);
$mform->disabledIf('right', 'attempts', 'eq', attempts_report::ENROLLED_WITHOUT);
}
public function validation($data, $files) {
$errors = parent::validation($data, $files);
if ($data['attempts'] != attempts_report::ENROLLED_WITHOUT && !(
$data['qtext'] || $data['resp'] || $data['right'])) {
$errors['coloptions'] = get_string('reportmustselectstate', 'quiz');
}
return $errors;
}
protected function other_attempt_fields(MoodleQuickForm $mform) {
parent::other_attempt_fields($mform);
if (quiz_allows_multiple_tries($this->_customdata['quiz'])) {
$mform->addElement('select', 'whichtries', get_string('whichtries', 'question'), [
question_attempt::FIRST_TRY => get_string('firsttry', 'question'),
question_attempt::LAST_TRY => get_string('lasttry', 'question'),
question_attempt::ALL_TRIES => get_string('alltries', 'question')]
);
$mform->setDefault('whichtries', question_attempt::LAST_TRY);
$mform->disabledIf('whichtries', 'attempts', 'eq', attempts_report::ENROLLED_WITHOUT);
}
}
}
@@ -0,0 +1,120 @@
<?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/>.
use mod_quiz\local\reports\attempts_report;
use mod_quiz\local\reports\attempts_report_options;
/**
* Class to store the options for a {@link quiz_responses_report}.
*
* @copyright 2012 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class quiz_responses_options extends attempts_report_options {
/** @var bool whether to show the question text columns. */
public $showqtext = false;
/** @var bool whether to show the students' response columns. */
public $showresponses = true;
/** @var bool whether to show the correct response columns. */
public $showright = false;
/** @var bool which try/tries to show responses from. */
public $whichtries = question_attempt::LAST_TRY;
protected function get_url_params() {
$params = parent::get_url_params();
$params['qtext'] = $this->showqtext;
$params['resp'] = $this->showresponses;
$params['right'] = $this->showright;
if (quiz_allows_multiple_tries($this->quiz)) {
$params['whichtries'] = $this->whichtries;
}
return $params;
}
public function get_initial_form_data() {
$toform = parent::get_initial_form_data();
$toform->qtext = $this->showqtext;
$toform->resp = $this->showresponses;
$toform->right = $this->showright;
if (quiz_allows_multiple_tries($this->quiz)) {
$toform->whichtries = $this->whichtries;
}
return $toform;
}
public function setup_from_form_data($fromform) {
parent::setup_from_form_data($fromform);
$this->showqtext = $fromform->qtext;
$this->showresponses = $fromform->resp;
$this->showright = $fromform->right;
if (quiz_allows_multiple_tries($this->quiz)) {
$this->whichtries = $fromform->whichtries;
}
}
public function setup_from_params() {
parent::setup_from_params();
$this->showqtext = optional_param('qtext', $this->showqtext, PARAM_BOOL);
$this->showresponses = optional_param('resp', $this->showresponses, PARAM_BOOL);
$this->showright = optional_param('right', $this->showright, PARAM_BOOL);
if (quiz_allows_multiple_tries($this->quiz)) {
$this->whichtries = optional_param('whichtries', $this->whichtries, PARAM_ALPHA);
}
}
public function setup_from_user_preferences() {
parent::setup_from_user_preferences();
$this->showqtext = get_user_preferences('quiz_report_responses_qtext', $this->showqtext);
$this->showresponses = get_user_preferences('quiz_report_responses_resp', $this->showresponses);
$this->showright = get_user_preferences('quiz_report_responses_right', $this->showright);
if (quiz_allows_multiple_tries($this->quiz)) {
$this->whichtries = get_user_preferences('quiz_report_responses_which_tries', $this->whichtries);
}
}
public function update_user_preferences() {
parent::update_user_preferences();
set_user_preference('quiz_report_responses_qtext', $this->showqtext);
set_user_preference('quiz_report_responses_resp', $this->showresponses);
set_user_preference('quiz_report_responses_right', $this->showright);
if (quiz_allows_multiple_tries($this->quiz)) {
set_user_preference('quiz_report_responses_which_tries', $this->whichtries);
}
}
public function resolve_dependencies() {
parent::resolve_dependencies();
if (!$this->showqtext && !$this->showresponses && !$this->showright) {
// We have to show at least something.
$this->showresponses = true;
}
// We only want to show the checkbox to delete attempts
// if the user has permissions and if the report mode is showing attempts.
$this->checkboxcolumn = has_capability('mod/quiz:deleteattempts', context_module::instance($this->cm->id))
&& ($this->attempts != attempts_report::ENROLLED_WITHOUT);
}
}
@@ -0,0 +1,75 @@
@mod @mod_quiz @quiz @quiz_reponses
Feature: Basic use of the Responses report
In order to see how my students are progressing
As a teacher
I need to see all their quiz responses
Background: Using the Responses report
Given the following "users" exist:
| username | firstname | lastname |
| teacher | The | Teacher |
| student1 | Student | One |
| student2 | Student | Two |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "course enrolments" exist:
| user | course | role |
| teacher | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "activities" exist:
| activity | name | intro | course | idnumber | preferredbehaviour |
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | interactive |
And the following "questions" exist:
| questioncategory | qtype | name | template |
| Test questions | numerical | NQ | pi3tries |
And quiz "Quiz 1" contains the following questions:
| question | page | maxmark | displaynumber |
| NQ | 1 | 3.0 | 1a |
@javascript
Scenario: Report works when there are no attempts
When I am on the "Quiz 1" "mod_quiz > Responses report" page logged in as teacher
Then I should see "Attempts: 0"
And I should see "Nothing to display"
And I set the field "Attempts from" to "enrolled users who have not attempted the quiz"
@javascript
Scenario: Report works when there are attempts
Given user "student1" has started an attempt at quiz "Quiz 1"
And user "student1" has checked answers in their attempt at quiz "Quiz 1":
| slot | response |
| 1 | 1.0 |
And user "student1" has checked answers in their attempt at quiz "Quiz 1":
| slot | response |
| 1 | 3.0 |
And user "student1" has checked answers in their attempt at quiz "Quiz 1":
| slot | response |
| 1 | 3.14 |
And user "student1" has finished an attempt at quiz "Quiz 1"
When I am on the "Quiz 1" "mod_quiz > Responses report" page logged in as teacher
Then I should see "Attempts: 1"
And I should see "Student One"
And I should not see "Student Two"
And I set the field "Attempts from" to "enrolled users who have, or have not, attempted the quiz"
And I set the field "Which tries" to "All tries"
And I should see "Response 1a"
And I press "Show report"
And "Student OneReview attempt" row "Response 1aSort by Response 1a Ascending" column of "responses" table should contain "1.0"
And "Student OneReview attempt" row "Status" column of "responses" table should contain ""
And "Finished" row "Grade/100.00Sort by Grade/100.00 Ascending" column of "responses" table should contain "33.33"
And "Finished" row "Response 1aSort by Response 1a Ascending" column of "responses" table should contain "3.14"
And "Student Two" row "Status" column of "responses" table should contain "-"
And "Student Two" row "Response 1aSort by Response 1a Ascending" column of "responses" table should contain "-"
@javascript
Scenario: Report does not allow strange combinations of options
Given I am on the "Quiz 1" "mod_quiz > Responses report" page logged in as teacher
And the "Which tries" "select" should be enabled
When I set the field "Attempts from" to "enrolled users who have not attempted the quiz"
Then the "Which tries" "select" should be disabled
@@ -0,0 +1,7 @@
slot,type,which,cat,mark,overrides.hint.0.text,overrides.hint.0.format,overrides.hint.1.text,overrides.hint.1.format,overrides.hint.2.text,overrides.hint.2.format,overrides.hint.3.text,overrides.hint.3.format,overrides.shuffleanswers
1,random,,rand,1,"Hint 1",0,"Hint 2",0,"Hint 3",0,"Hint 4",0,0
,shortanswer,,rand,1,"Hint 1",0,"Hint 2",0,"Hint 3",0,"Hint 4",0,0
,numerical,,rand,1,"Hint 1",0,"Hint 2",0,"Hint 3",0,"Hint 4",0,0
2,calculatedsimple,sumwithvariants,maincat,1,"Hint 1",0,"Hint 2",0,"Hint 3",0,"Hint 4",0,0
3,match,,maincat,1,"Hint 1",0,"Hint 2",0,"Hint 3",0,"Hint 4",0,0
4,truefalse,,maincat,1,"",0,"",0,"",0,"",0,0
1 slot type which cat mark overrides.hint.0.text overrides.hint.0.format overrides.hint.1.text overrides.hint.1.format overrides.hint.2.text overrides.hint.2.format overrides.hint.3.text overrides.hint.3.format overrides.shuffleanswers
2 1 random rand 1 Hint 1 0 Hint 2 0 Hint 3 0 Hint 4 0 0
3 shortanswer rand 1 Hint 1 0 Hint 2 0 Hint 3 0 Hint 4 0 0
4 numerical rand 1 Hint 1 0 Hint 2 0 Hint 3 0 Hint 4 0 0
5 2 calculatedsimple sumwithvariants maincat 1 Hint 1 0 Hint 2 0 Hint 3 0 Hint 4 0 0
6 3 match maincat 1 Hint 1 0 Hint 2 0 Hint 3 0 Hint 4 0 0
7 4 truefalse maincat 1 0 0 0 0 0
+2
View File
@@ -0,0 +1,2 @@
testnumber,preferredbehaviour
00,interactive
1 testnumber preferredbehaviour
2 00 interactive
@@ -0,0 +1,10 @@
quizattempt,submittedstepno,slot.1.fraction,slot.1.responsesummary,slot.1.state,slot.2.responsesummary,slot.2.fraction,slot.2.state,slot.3.responsesummary,slot.3.fraction,slot.3.state,slot.4.responsesummary,slot.4.fraction,slot.4.state
1,1,,toad,todo,19.4,1.0,gradedright,"frog -> mammal; cat -> mammal; newt -> amphibian",,todo,True,1.0,gradedright
1,2,1.0,frog,gradedright,,,,"frog -> amphibian; cat -> mammal; newt -> amphibian",0.8888889,gradedright,,,
2,1,,frog,todo,-0.6,,todo,"frog -> amphibian; cat -> mammal; newt -> amphibian",,todo,True,,todo
3,1,0,3.142,gradedwrong,19.4,1.0,gradedright,"frog -> amphibian; cat -> mammal; newt -> amphibian",1.0,gradedright,False,0.0,gradedwrong
4,1,,2,todo,9.4,1.0,gradedright,"frog -> mammal; cat -> amphibian; newt -> amphibian",0.3333333,gradedpartial,False,0.0,gradedwrong
4,2,0,3.142,gradedwrong,,,,,,,,,
5,1,1.0,frog,gradedright,7.1,1.0,gradedright,"frog -> amphibian; cat -> mammal; newt -> amphibian",1.0,gradedright,True,1.0,gradedright
6,1,0,3.1,gradedwrong,9.1,1.0,gradedright,"frog -> amphibian; cat -> mammal; newt -> amphibian",1.0,gradedright,True,1.0,gradedright
7,1,0,2.5,gradedwrong,-0.2,0.0,gradedwrong,"frog -> amphibian; cat -> mammal; newt -> amphibian",1.0,gradedright,False,0,gradedwrong
1 quizattempt submittedstepno slot.1.fraction slot.1.responsesummary slot.1.state slot.2.responsesummary slot.2.fraction slot.2.state slot.3.responsesummary slot.3.fraction slot.3.state slot.4.responsesummary slot.4.fraction slot.4.state
2 1 1 toad todo 19.4 1.0 gradedright frog -> mammal; cat -> mammal; newt -> amphibian todo True 1.0 gradedright
3 1 2 1.0 frog gradedright frog -> amphibian; cat -> mammal; newt -> amphibian 0.8888889 gradedright
4 2 1 frog todo -0.6 todo frog -> amphibian; cat -> mammal; newt -> amphibian todo True todo
5 3 1 0 3.142 gradedwrong 19.4 1.0 gradedright frog -> amphibian; cat -> mammal; newt -> amphibian 1.0 gradedright False 0.0 gradedwrong
6 4 1 2 todo 9.4 1.0 gradedright frog -> mammal; cat -> amphibian; newt -> amphibian 0.3333333 gradedpartial False 0.0 gradedwrong
7 4 2 0 3.142 gradedwrong
8 5 1 1.0 frog gradedright 7.1 1.0 gradedright frog -> amphibian; cat -> mammal; newt -> amphibian 1.0 gradedright True 1.0 gradedright
9 6 1 0 3.1 gradedwrong 9.1 1.0 gradedright frog -> amphibian; cat -> mammal; newt -> amphibian 1.0 gradedright True 1.0 gradedright
10 7 1 0 2.5 gradedwrong -0.2 0.0 gradedwrong frog -> amphibian; cat -> mammal; newt -> amphibian 1.0 gradedright False 0 gradedwrong
+18
View File
@@ -0,0 +1,18 @@
quizattempt,firstname,lastname,randqs.1,responses.1.answer,responses.1.-submit,responses.1.-tryagain,variants.2,responses.2.answer,responses.2.-submit,responses.2.-tryagain,responses.3.frog,responses.3.cat,responses.3.newt,responses.3.-submit,responses.3.-tryagain,responses.4.answer,responses.4.-submit,responses.4.-tryagain,finished
1,John,Jones,shortanswer,toad,1,0,4,19.4,0,0,mammal,mammal,amphibian,0,0,1,0,0,0
1,John,Jones,shortanswer,toad,0,1,4,19.4,0,0,mammal,mammal,amphibian,0,0,1,0,0,0
1,John,Jones,shortanswer,frog,1,0,4,19.4,0,0,mammal,mammal,amphibian,0,0,1,0,0,0
1,John,Jones,shortanswer,toad,0,0,4,19.4,0,0,mammal,mammal,amphibian,1,0,1,0,0,0
1,John,Jones,shortanswer,toad,0,0,4,19.4,0,0,mammal,mammal,amphibian,0,1,1,0,0,0
1,John,Jones,shortanswer,frog,0,0,4,19.4,0,0,amphibian,mammal,amphibian,1,0,1,0,0,1
2,John,Smith,shortanswer,frog,0,0,6,-0.6,0,0,amphibian,mammal,amphibian,0,0,1,0,0,0
3,John,Vicars,numerical,3.142,0,0,4,19.4,0,0,amphibian,mammal,amphibian,0,0,0,0,0,1
4,John,Pacino,numerical,2,1,0,6,9.4,0,0,mammal,amphibian,amphibian,0,0,0,0,0,0
4,John,Pacino,numerical,2,0,1,6,9.4,0,0,mammal,amphibian,amphibian,0,0,0,0,0,0
4,John,Pacino,numerical,3.142,1,0,6,9.4,0,0,mammal,amphibian,amphibian,0,0,0,0,0,0
4,John,Pacino,numerical,3.142,0,0,6,9.4,0,0,mammal,amphibian,amphibian,0,0,0,1,0,0
4,John,Pacino,numerical,3.142,0,0,6,9.4,0,0,mammal,amphibian,amphibian,0,0,0,0,1,0
4,John,Pacino,numerical,3.142,0,0,6,9.4,0,0,mammal,amphibian,amphibian,0,0,1,1,0,1
5,John,Deniro,shortanswer,frog,0,0,9,7.1,0,0,amphibian,mammal,amphibian,0,0,1,0,0,1
6,John,Banks,numerical,3.1,0,0,7,9.1,0,0,amphibian,mammal,amphibian,0,0,1,0,0,1
7,John,Asimov,numerical,2.5,0,0,3,-0.2,0,0,amphibian,mammal,amphibian,0,0,0,0,0,1
1 quizattempt firstname lastname randqs.1 responses.1.answer responses.1.-submit responses.1.-tryagain variants.2 responses.2.answer responses.2.-submit responses.2.-tryagain responses.3.frog responses.3.cat responses.3.newt responses.3.-submit responses.3.-tryagain responses.4.answer responses.4.-submit responses.4.-tryagain finished
2 1 John Jones shortanswer toad 1 0 4 19.4 0 0 mammal mammal amphibian 0 0 1 0 0 0
3 1 John Jones shortanswer toad 0 1 4 19.4 0 0 mammal mammal amphibian 0 0 1 0 0 0
4 1 John Jones shortanswer frog 1 0 4 19.4 0 0 mammal mammal amphibian 0 0 1 0 0 0
5 1 John Jones shortanswer toad 0 0 4 19.4 0 0 mammal mammal amphibian 1 0 1 0 0 0
6 1 John Jones shortanswer toad 0 0 4 19.4 0 0 mammal mammal amphibian 0 1 1 0 0 0
7 1 John Jones shortanswer frog 0 0 4 19.4 0 0 amphibian mammal amphibian 1 0 1 0 0 1
8 2 John Smith shortanswer frog 0 0 6 -0.6 0 0 amphibian mammal amphibian 0 0 1 0 0 0
9 3 John Vicars numerical 3.142 0 0 4 19.4 0 0 amphibian mammal amphibian 0 0 0 0 0 1
10 4 John Pacino numerical 2 1 0 6 9.4 0 0 mammal amphibian amphibian 0 0 0 0 0 0
11 4 John Pacino numerical 2 0 1 6 9.4 0 0 mammal amphibian amphibian 0 0 0 0 0 0
12 4 John Pacino numerical 3.142 1 0 6 9.4 0 0 mammal amphibian amphibian 0 0 0 0 0 0
13 4 John Pacino numerical 3.142 0 0 6 9.4 0 0 mammal amphibian amphibian 0 0 0 1 0 0
14 4 John Pacino numerical 3.142 0 0 6 9.4 0 0 mammal amphibian amphibian 0 0 0 0 1 0
15 4 John Pacino numerical 3.142 0 0 6 9.4 0 0 mammal amphibian amphibian 0 0 1 1 0 1
16 5 John Deniro shortanswer frog 0 0 9 7.1 0 0 amphibian mammal amphibian 0 0 1 0 0 1
17 6 John Banks numerical 3.1 0 0 7 9.1 0 0 amphibian mammal amphibian 0 0 1 0 0 1
18 7 John Asimov numerical 2.5 0 0 3 -0.2 0 0 amphibian mammal amphibian 0 0 0 0 0 1
@@ -0,0 +1,140 @@
<?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/>.
/**
* Privacy provider tests.
*
* @package quiz_responses
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace quiz_responses\privacy;
use core_privacy\local\metadata\collection;
use quiz_responses\privacy\provider;
use core_privacy\local\request\writer;
use core_privacy\local\request\transform;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/question/engine/questionattempt.php');
/**
* Privacy provider tests class.
*
* @package quiz_responses
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider_test extends \core_privacy\tests\provider_testcase {
/**
* When no preference exists, there should be no export.
*/
public function test_preference_unset(): void {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
provider::export_user_preferences($USER->id);
$this->assertFalse(writer::with_context(\context_system::instance())->has_any_data());
}
/**
* Preference does exist.
*/
public function test_preference_bool_true(): void {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
set_user_preference('quiz_report_responses_qtext', true);
set_user_preference('quiz_report_responses_resp', true);
set_user_preference('quiz_report_responses_right', true);
provider::export_user_preferences($USER->id);
$writer = writer::with_context(\context_system::instance());
$this->assertTrue($writer->has_any_data());
$preferences = $writer->get_user_preferences('quiz_responses');
$this->assertNotEmpty($preferences->qtext);
$this->assertEquals(transform::yesno(1), $preferences->qtext->value);
$this->assertNotEmpty($preferences->resp);
$this->assertEquals(transform::yesno(1), $preferences->resp->value);
$this->assertNotEmpty($preferences->right);
$this->assertEquals(transform::yesno(1), $preferences->right->value);
}
/**
* Preference does exist.
*/
public function test_preference_bool_false(): void {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
set_user_preference('quiz_report_responses_qtext', false);
set_user_preference('quiz_report_responses_resp', false);
set_user_preference('quiz_report_responses_right', false);
provider::export_user_preferences($USER->id);
$writer = writer::with_context(\context_system::instance());
$this->assertTrue($writer->has_any_data());
$preferences = $writer->get_user_preferences('quiz_responses');
$this->assertNotEmpty($preferences->qtext);
$this->assertEquals(transform::yesno(0), $preferences->qtext->value);
$this->assertNotEmpty($preferences->resp);
$this->assertEquals(transform::yesno(0), $preferences->resp->value);
$this->assertNotEmpty($preferences->right);
$this->assertEquals(transform::yesno(0), $preferences->right->value);
}
/**
* Preference does exist.
*/
public function test_preference_bool_which_first(): void {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
set_user_preference('quiz_report_responses_which_tries', \question_attempt::FIRST_TRY);
provider::export_user_preferences($USER->id);
$writer = writer::with_context(\context_system::instance());
$this->assertTrue($writer->has_any_data());
$preferences = $writer->get_user_preferences('quiz_responses');
$expected = get_string("privacy:preference:which_tries:first", 'quiz_responses');
$this->assertNotEmpty($preferences->which_tries);
$this->assertEquals($expected, $preferences->which_tries->value);
}
}
@@ -0,0 +1,128 @@
<?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 quiz_responses;
use mod_quiz\quiz_attempt;
use question_bank;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/mod/quiz/tests/attempt_walkthrough_from_csv_test.php');
require_once($CFG->dirroot . '/mod/quiz/report/statistics/report.php');
require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php');
/**
* Quiz attempt walk through using data from csv file.
*
* @package quiz_responses
* @category test
* @copyright 2013 The Open University
* @author Jamie Pratt <me@jamiep.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class responses_from_steps_walkthrough_test extends \mod_quiz\attempt_walkthrough_from_csv_test {
protected function get_full_path_of_csv_file(string $setname, string $test): string {
// Overridden here so that __DIR__ points to the path of this file.
return __DIR__."/fixtures/{$setname}{$test}.csv";
}
/**
* @var string[] names of the files which contain the test data.
*/
protected $files = ['questions', 'steps', 'responses'];
/**
* Create a quiz add questions to it, walk through quiz attempts and then check results.
*
* @param array $quizsettings settings to override default settings for quiz created by generator. Taken from quizzes.csv.
* @param array $csvdata of data read from csv file "questionsXX.csv", "stepsXX.csv" and "responsesXX.csv".
* @dataProvider get_data_for_walkthrough
*/
public function test_walkthrough_from_csv($quizsettings, $csvdata): void {
$this->resetAfterTest(true);
question_bank::get_qtype('random')->clear_caches_before_testing();
$this->create_quiz($quizsettings, $csvdata['questions']);
$quizattemptids = $this->walkthrough_attempts($csvdata['steps']);
foreach ($csvdata['responses'] as $responsesfromcsv) {
$responses = $this->explode_dot_separated_keys_to_make_subindexs($responsesfromcsv);
if (!isset($quizattemptids[$responses['quizattempt']])) {
throw new \coding_exception("There is no quizattempt {$responses['quizattempt']}!");
}
$this->assert_response_test($quizattemptids[$responses['quizattempt']], $responses);
}
}
protected function assert_response_test($quizattemptid, $responses) {
$quizattempt = quiz_attempt::create($quizattemptid);
foreach ($responses['slot'] as $slot => $tests) {
$slothastests = false;
foreach ($tests as $test) {
if ('' !== $test) {
$slothastests = true;
}
}
if (!$slothastests) {
continue;
}
$qa = $quizattempt->get_question_attempt($slot);
$stepswithsubmit = $qa->get_steps_with_submitted_response_iterator();
$step = $stepswithsubmit[$responses['submittedstepno']];
if (null === $step) {
throw new \coding_exception("There is no step no {$responses['submittedstepno']} ".
"for slot $slot in quizattempt {$responses['quizattempt']}!");
}
foreach (['responsesummary', 'fraction', 'state'] as $column) {
if (isset($tests[$column]) && $tests[$column] != '') {
switch($column) {
case 'responsesummary' :
$actual = $qa->get_question()->summarise_response($step->get_qt_data());
break;
case 'fraction' :
if (count($stepswithsubmit) == $responses['submittedstepno']) {
// If this is the last step then we need to look at the fraction after the question has been
// finished.
$actual = $qa->get_fraction();
} else {
$actual = $step->get_fraction();
}
break;
case 'state' :
if (count($stepswithsubmit) == $responses['submittedstepno']) {
// If this is the last step then we need to look at the state after the question has been
// finished.
$state = $qa->get_state();
} else {
$state = $step->get_state();
}
$actual = substr(get_class($state), strlen('question_state_'));
}
$expected = $tests[$column];
$failuremessage = "Error in quizattempt {$responses['quizattempt']} in $column, slot $slot, ".
"submittedstepno {$responses['submittedstepno']}";
$this->assertEquals($expected, $actual, $failuremessage);
}
}
}
}
}
+30
View File
@@ -0,0 +1,30 @@
<?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/>.
/**
* Quiz responses report version information.
*
* @package quiz_responses
* @copyright 2011 Tim Hunt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2024042200;
$plugin->requires = 2024041600;
$plugin->component = 'quiz_responses';