diff --git a/archive_form.php b/archive_form.php index 839efeb..aea0bd2 100644 --- a/archive_form.php +++ b/archive_form.php @@ -23,9 +23,18 @@ */ +use mod_quiz\local\reports\attempts_report_options_form; + defined('MOODLE_INTERNAL') || die(); -require_once($CFG->libdir.'/formslib.php'); +// This work-around is required until Moodle 4.2 is the lowest version we support. +if (class_exists('\mod_quiz\local\reports\attempts_report_options_form')) { + class_alias('\mod_quiz\local\reports\attempts_report_options_form', '\quiz_archive_settings_form_parent_class_alias'); +} else { + require_once($CFG->dirroot . '/mod/quiz/report/attemptsreport_form.php'); + class_alias('\mod_quiz_attempts_report_form', '\quiz_archive_settings_form_parent_class_alias'); +} + /** * Quiz archive report settings form. @@ -34,14 +43,45 @@ * @copyright 2018 Luca Bösch * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class quiz_archive_settings_form extends moodleform { +class quiz_archive_settings_form extends quiz_archive_settings_form_parent_class_alias { + + /** + * Definition of our form. Overriding parent method, because our form is much simpler + * and does not have multiple sections. + * + * @return void + */ + protected function definition() { + $mform = $this->_form; + + $mform->addElement('header', 'preferencesuser', get_string('reportdisplayoptions', 'quiz')); + + $this->standard_preference_fields($mform); + + $mform->addElement('submit', 'submitbutton', get_string('showreport', 'quiz')); + } /** - * Called to define this moodle form. + * Override parent function. Our form currently only has two checkboxes, so their + * data is always valid or could at least be converted to valid values. * + * @param mixed $data + * @param mixed $files + * @return array + */ + public function validation($data, $files) { + return []; + } + + /** + * Add the preference fields that we offer. + * + * @param MoodleQuickForm $mform the form * @return void */ - public function definition() { - $mform =& $this->_form; + protected function standard_preference_fields(MoodleQuickForm $mform) { + $mform->addElement('advcheckbox', 'showhistory', get_string('includehistory', 'quiz_archive')); + $mform->addElement('advcheckbox', 'showright', get_string('includecorrectanswer', 'quiz_archive')); } + } diff --git a/archive_options.php b/archive_options.php index 1dc064a..6003b9f 100644 --- a/archive_options.php +++ b/archive_options.php @@ -22,6 +22,18 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +use mod_quiz\local\reports\attempts_report_options; + +defined('MOODLE_INTERNAL') || die(); + +// This work-around is required until Moodle 4.2 is the lowest version we support. +if (class_exists('\mod_quiz\local\reports\attempts_report_options')) { + class_alias('\mod_quiz\local\reports\attempts_report_options', '\quiz_archive_options_parent_class_alias'); +} else { + require_once($CFG->dirroot . '/mod/quiz/report/attemptsreport_options.php'); + class_alias('\mod_quiz_attempts_report_options', '\quiz_archive_options_parent_class_alias'); +} + /** * Class to store the options for a {@see quiz_archive_report}. * @@ -29,75 +41,13 @@ * @copyright 2018 Luca Bösch * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class quiz_archive_options extends mod_quiz_attempts_report_options { - - /** @var string the report mode. */ - public $mode; - - /** @var object the settings for the quiz being reported on. */ - public $quiz; - - /** @var object the course module objects for the quiz being reported on. */ - public $cm; - - /** @var object the course settings for the course the quiz is in. */ - public $course; - - /** - * @var array form field name => corresponding quiz_attempt:: state constant. - */ - protected static $statefields = [ - 'stateinprogress' => quiz_attempt::IN_PROGRESS, - 'stateoverdue' => quiz_attempt::OVERDUE, - 'statefinished' => quiz_attempt::FINISHED, - 'stateabandoned' => quiz_attempt::ABANDONED, - ]; +class quiz_archive_options extends quiz_archive_options_parent_class_alias { - /** - * @var string quiz_attempts_report::ALL_WITH or quiz_attempts_report::ENROLLED_WITH - * quiz_attempts_report::ENROLLED_WITHOUT or quiz_attempts_report::ENROLLED_ALL - */ - public $attempts = quiz_attempts_report::ENROLLED_WITH; + /** @var bool whether to show the correct response. */ + public $showright = true; - /** @var int the currently selected group. 0 if no group is selected. */ - public $group = 0; - - /** - * @var array|null of quiz_attempt::IN_PROGRESS, etc. constants. null means - * no restriction. - */ - public $states = [quiz_attempt::IN_PROGRESS, quiz_attempt::OVERDUE, - quiz_attempt::FINISHED, quiz_attempt::ABANDONED, ]; - - /** - * @var bool whether to show all finished attmepts, or just the one that gave - * the final grade for the user. - */ - public $onlygraded = false; - - /** @var int Number of attempts to show per page. */ - public $pagesize = quiz_attempts_report::DEFAULT_PAGE_SIZE; - - /** @var string whether the data should be downloaded in some format, or '' to display it. */ - public $download = ''; - - /** @var bool whether the current user has permission to see grades. */ - public $usercanseegrades; - - /** @var bool whether the report table should have a column of checkboxes. */ - public $checkboxcolumn = false; - - /** @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; + /** @var bool whether to show the history. */ + public $showhistory = true; /** * Constructor. @@ -111,51 +61,16 @@ public function __construct($mode, $quiz, $cm, $course) { $this->quiz = $quiz; $this->cm = $cm; $this->course = $course; - - $this->usercanseegrades = quiz_report_should_show_grades($quiz, context_module::instance($cm->id)); - } - - /** - * Get the URL to show the report with these options. - * @return moodle_url the URL. - */ - public function get_url() { - return new moodle_url('/mod/quiz/report.php', $this->get_url_params()); - } - - /** - * Get the URL parameters required to show the report with these options. - * @return array URL parameter name => value. - */ - protected function get_url_params() { - $params = [ - 'id' => $this->cm->id, - 'mode' => $this->mode, - 'attempts' => $this->attempts, - 'onlygraded' => $this->onlygraded, - ]; - - if ($this->states) { - $params['states'] = implode('-', $this->states); - } - - if (groups_get_activity_groupmode($this->cm, $this->course)) { - $params['group'] = $this->group; - } - return $params; } /** * Get the current value of the settings to pass to the settings form. */ 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; - } + $toform = new stdClass(); + + $toform->showright = $this->showright; + $toform->showhistory = $this->showhistory; return $toform; } @@ -165,74 +80,35 @@ public function get_initial_form_data() { * @param object $fromform The data from $mform->get_data() from the settings form. */ 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; - } + $this->showright = $fromform->showright; + $this->showhistory = $fromform->showhistory; } /** * Set the fields of this object from the URL parameters. */ 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); - } + $this->showright = optional_param('right', $this->showright, PARAM_BOOL); + $this->showhistory = optional_param('history', $this->showhistory, PARAM_BOOL); } /** - * Set the fields of this object from the user's preferences. - * (For those settings that are backed by user-preferences). + * Override parent method, because we do not have settings that are backed by + * user-preferences. */ public function setup_from_user_preferences() { - parent::setup_from_user_preferences(); - - $this->showqtext = get_user_preferences('quiz_report_archive_qtext', $this->showqtext); - $this->showresponses = get_user_preferences('quiz_report_archive_resp', $this->showresponses); - $this->showright = get_user_preferences('quiz_report_archive_right', $this->showright); - if (quiz_allows_multiple_tries($this->quiz)) { - $this->whichtries = get_user_preferences('quiz_report_archive_which_tries', $this->whichtries); - } } /** - * Update the user preferences so they match the settings in this object. - * (For those settings that are backed by user-preferences). + * Override parent method, because we do not have settings that are backed by + * user-preferences. */ public function update_user_preferences() { - parent::update_user_preferences(); - - set_user_preference('quiz_report_archive_qtext', $this->showqtext); - set_user_preference('quiz_report_archive_resp', $this->showresponses); - set_user_preference('quiz_report_archive_right', $this->showright); - if (quiz_allows_multiple_tries($this->quiz)) { - set_user_preference('quiz_report_archive_which_tries', $this->whichtries); - } } /** - * Check the settings, and remove any 'impossible' combinations. + * Override parent method, because our settings cannot be incompatible. */ 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 != quiz_attempts_report::ENROLLED_WITHOUT); } } diff --git a/lang/en/quiz_archive.php b/lang/en/quiz_archive.php index 5046d40..f9dd8b8 100644 --- a/lang/en/quiz_archive.php +++ b/lang/en/quiz_archive.php @@ -28,3 +28,7 @@ // PRIVACY. $string['privacy:metadata'] = 'The quiz archive plugin does not store any personal data about any user.'; + +// OPTIONS. +$string['includehistory'] = 'Include response history'; +$string['includecorrectanswer'] = 'Include correct answer'; diff --git a/report.php b/report.php index 8e16ada..294f3aa 100644 --- a/report.php +++ b/report.php @@ -25,22 +25,25 @@ use mod_quiz\local\reports\report_base; use mod_quiz\quiz_attempt; use mod_quiz\question\display_options; +use mod_quiz\local\reports\attempts_report; defined('MOODLE_INTERNAL') || die(); // This work-around is required until Moodle 4.2 is the lowest version we support. if (class_exists('\mod_quiz\local\reports\report_base')) { - class_alias('\mod_quiz\local\reports\report_base', '\quiz_archive_report_parent_class_alias'); + class_alias('\mod_quiz\local\reports\attempts_report', '\quiz_archive_report_parent_class_alias'); + class_alias('\mod_quiz\quiz_attempt', '\quiz_archive_quiz_attempt'); class_alias('\mod_quiz\question\display_options', '\quiz_archive_mod_quiz_display_options'); - class_alias('mod_quiz\quiz_attempt', '\quiz_archive_quiz_attempt'); } else { require_once($CFG->dirroot . '/mod/quiz/report/attemptsreport.php'); require_once($CFG->dirroot . '/mod/quiz/attemptlib.php'); - class_alias('\quiz_default_report', '\quiz_archive_report_parent_class_alias'); - class_alias('\mod_quiz_display_options', '\quiz_archive_mod_quiz_display_options'); + class_alias('\quiz_attempts_report', '\quiz_archive_report_parent_class_alias'); class_alias('\quiz_attempt', '\quiz_archive_quiz_attempt'); + class_alias('\mod_quiz_display_options', '\quiz_archive_mod_quiz_display_options'); } +require_once($CFG->dirroot . '/mod/quiz/report/archive/archive_options.php'); +require_once($CFG->dirroot . '/mod/quiz/report/archive/archive_form.php'); require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php'); require_once($CFG->dirroot . '/mod/quiz/locallib.php'); require_once($CFG->libdir . '/pagelib.php'); @@ -63,12 +66,8 @@ class quiz_archive_report extends quiz_archive_report_parent_class_alias { protected $cm; /** @var object course object. */ protected $course; - /** @var object the quiz settings object. */ - protected $quiz; - /** @var context the quiz context. */ - protected $context; - /** @var students the students having attempted the quiz. */ - protected $students; + /** @var object display options for the report. */ + protected $options; /** * Display the report. @@ -80,27 +79,34 @@ class quiz_archive_report extends quiz_archive_report_parent_class_alias { * @throws moodle_exception */ public function display($quiz, $cm, $course) { - global $PAGE; + $this->init('archive', 'quiz_archive_settings_form', $quiz, $cm, $course); + + $this->options = new quiz_archive_options('archive', $quiz, $cm, $course); + + if ($fromform = $this->form->get_data()) { + $this->options->process_settings_from_form($fromform); + + } else { + $this->options->process_settings_from_params(); + } - $this->quiz = $quiz; + $this->form->set_data($this->options->get_initial_form_data()); + + $this->quizobj = $quiz; $this->cm = $cm; $this->course = $course; // Get the URL options. $slot = optional_param('slot', null, PARAM_INT); - $questionid = optional_param('qid', null, PARAM_INT); $grade = optional_param('grade', null, PARAM_ALPHA); if (!in_array($grade, ['all', 'needsgrading', 'autograded', 'manuallygraded'])) { $grade = null; } - $page = optional_param('page', 0, PARAM_INT); // Check permissions. $this->context = context_module::instance($cm->id); require_capability('mod/quiz:grade', $this->context); - $shownames = has_capability('quiz/grading:viewstudentnames', $this->context); - $showidnumbers = has_capability('quiz/grading:viewidnumber', $this->context); // Get the list of questions in this quiz. $this->questions = quiz_report_get_significant_questions($quiz); @@ -113,6 +119,8 @@ public function display($quiz, $cm, $course) { // Start output. $this->print_header_and_tabs($cm, $course, $quiz, 'archive'); + $this->form->display(); + // What sort of page to display? if (!$hasquestions) { echo quiz_no_questions_message($quiz, $cm, $this->context); @@ -122,21 +130,11 @@ public function display($quiz, $cm, $course) { return true; } - /** - * Get the URL of the front page of the report that lists all the questions. - * @return string the URL. - */ - protected function base_url() { - return new moodle_url('/mod/quiz/report.php', - ['id' => $this->cm->id, 'mode' => 'archive']); - } - /** * Display all attempts. */ protected function display_archive() { - global $OUTPUT, $PAGE; - $studentattempts = $this->quizreportgetstudentandattempts($this->quiz); + $studentattempts = $this->quizreportgetstudentandattempts($this->quizobj); foreach ($studentattempts as $studentattempt) { echo $this->quiz_report_get_student_attempt($studentattempt['attemptid'], $studentattempt['userid']); } @@ -155,11 +153,11 @@ protected function quizreportgetstudentandattempts($quiz) { $sql = "SELECT DISTINCT quiza.id attemptid, u.id userid, u.firstname, u.lastname FROM {user} u " . "LEFT JOIN {quiz_attempts} quiza " . "ON quiza.userid = u.id WHERE quiza.quiz = :quizid AND quiza.preview = 0 ORDER BY u.lastname ASC, u.firstname ASC"; - $params = ['quizid' => $this->quiz->id]; + $params = ['quizid' => $this->quizobj->id]; $results = $DB->get_records_sql($sql, $params); $students = []; foreach ($results as $result) { - array_push($students, array('userid' => $result->userid, 'attemptid' => $result->attemptid)); + array_push($students, ['userid' => $result->userid, 'attemptid' => $result->attemptid]); } return $students; } @@ -179,7 +177,7 @@ protected function quiz_report_get_student_attempt($attemptid, $userid) { // Work out some time-related things. $attempt = $attemptobj->get_attempt(); $quiz = $attemptobj->get_quiz(); - $options = quiz_archive_mod_quiz_display_options::make_from_quiz($this->quiz, quiz_attempt_state($quiz, $attempt)); + $options = quiz_archive_mod_quiz_display_options::make_from_quiz($this->quizobj, quiz_attempt_state($quiz, $attempt)); $options->flags = quiz_get_flag_option($attempt, context_module::instance($this->cm->id)); $overtime = 0; @@ -211,10 +209,10 @@ protected function quiz_report_get_student_attempt($attemptid, $userid) { ]; // Timing information. - $summarydata['startedon'] = array( + $summarydata['startedon'] = [ 'title' => get_string('startedon', 'quiz'), 'content' => userdate($attempt->timestart), - ); + ]; $summarydata['state'] = [ 'title' => get_string('attemptstate', 'quiz'), @@ -318,7 +316,8 @@ protected function quiz_report_get_student_attempt($attemptid, $userid) { $displayoptions->marks = 2; $displayoptions->manualcomment = 1; $displayoptions->feedback = 1; - $displayoptions->history = true; + $displayoptions->history = $this->options->showhistory; + $displayoptions->rightanswer = $this->options->showright; $displayoptions->correctness = 1; $displayoptions->numpartscorrect = 1; $displayoptions->flags = 1; diff --git a/styles.css b/styles.css index 02bb923..3650b49 100644 --- a/styles.css +++ b/styles.css @@ -17,6 +17,9 @@ #page-mod-quiz-report #block-region-side-post { display: none; } + fieldset#id_preferencesuser { + display: none; + } header[role=banner] { display: none; } diff --git a/tests/behat/displayoptions.feature b/tests/behat/displayoptions.feature new file mode 100644 index 0000000..d6ae8b7 --- /dev/null +++ b/tests/behat/displayoptions.feature @@ -0,0 +1,63 @@ +@mod @mod_quiz @quiz @quiz_archive @javascript +Feature: Using display options to customize the report + In order to change the appearance of my report + As a teacher + I need to use the available options + + Background: + Given the following "users" exist: + | username | firstname | lastname | email | idnumber | + | teacher1 | T1 | Teacher1 | teacher1@example.com | T1000 | + | student1 | S1 | Student1 | student1@example.com | S1000 | + And the following "courses" exist: + | fullname | shortname | category | + | Course 1 | C1 | 0 | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | student1 | 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 | + | quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | + And the following "questions" exist: + | questioncategory | qtype | name | questiontext | + | Test questions | truefalse | TF1 | First question | + | Test questions | truefalse | TF2 | Second question | + And quiz "Quiz 1" contains the following questions: + | question | page | maxmark | + | TF1 | 1 | | + | TF2 | 1 | 3.0 | + + # Add an attempt + And I log in as "student1" + And I am on "Course 1" course homepage + And I follow "Quiz 1" + And I press "Attempt quiz" + And I click on "True" "radio" in the "First question" "question" + And I click on "False" "radio" in the "Second question" "question" + And I press "Finish attempt ..." + And I press "Submit all and finish" + And I confirm the quiz submission in the modal dialog + And I log out + And I am on the "Quiz 1" "quiz_archive > Archive" page logged in as "teacher1" + + Scenario: Enabling and disabling history + # Checking with the default setting + Then I should see "Response history" in the ".history" "css_element" + + # Disabling the history and checking again + When I set the field "id_showhistory" to "0" + And I press "Show report" + Then ".history" "css_element" should not exist + + Scenario: Enabling and disabling correct answer + # Checking with the default setting + Then I should see "The correct answer is" + + # Disabling correct answer and checking again + When I set the field "id_showright" to "0" + And I press "Show report" + Then I should not see "The correct answer is"