From 6c923f4bf058df3ac1f45b3494b7934003625df8 Mon Sep 17 00:00:00 2001 From: Safat Shahin Date: Thu, 19 Aug 2021 10:02:16 +1000 Subject: [PATCH] MDL-72448 qbank_history: Add history plugin to core This implementation will introduce history plugin to show the versions of a question. This plugin uses the actual qbank api to implement the feature. --- lib/classes/plugin_manager.php | 1 + question/bank/history/classes/helper.php | 47 +++++ .../history/classes/history_action_column.php | 60 ++++++ .../bank/history/classes/output/renderer.php | 39 ++++ .../bank/history/classes/plugin_feature.php | 36 ++++ .../bank/history/classes/privacy/provider.php | 33 +++ .../history/classes/question_history_view.php | 199 ++++++++++++++++++ .../history/classes/version_number_column.php | 43 ++++ question/bank/history/history.php | 53 +++++ .../bank/history/lang/en/qbank_history.php | 32 +++ .../history/templates/history_header.mustache | 45 ++++ .../behat/question_history_action.feature | 53 +++++ .../behat/question_version_column.feature | 31 +++ question/bank/history/tests/helper_test.php | 90 ++++++++ .../tests/question_history_view_test.php | 123 +++++++++++ question/bank/history/version.php | 31 +++ question/classes/local/bank/view.php | 2 + 17 files changed, 918 insertions(+) create mode 100644 question/bank/history/classes/helper.php create mode 100644 question/bank/history/classes/history_action_column.php create mode 100644 question/bank/history/classes/output/renderer.php create mode 100644 question/bank/history/classes/plugin_feature.php create mode 100644 question/bank/history/classes/privacy/provider.php create mode 100644 question/bank/history/classes/question_history_view.php create mode 100644 question/bank/history/classes/version_number_column.php create mode 100644 question/bank/history/history.php create mode 100644 question/bank/history/lang/en/qbank_history.php create mode 100644 question/bank/history/templates/history_header.mustache create mode 100644 question/bank/history/tests/behat/question_history_action.feature create mode 100644 question/bank/history/tests/behat/question_version_column.feature create mode 100644 question/bank/history/tests/helper_test.php create mode 100644 question/bank/history/tests/question_history_view_test.php create mode 100644 question/bank/history/version.php diff --git a/lib/classes/plugin_manager.php b/lib/classes/plugin_manager.php index 094a5b77b85..63dc85a4eae 100644 --- a/lib/classes/plugin_manager.php +++ b/lib/classes/plugin_manager.php @@ -1957,6 +1957,7 @@ class core_plugin_manager { 'editquestion', 'exporttoxml', 'exportquestions', + 'history', 'importquestions', 'managecategories', 'previewquestion', diff --git a/question/bank/history/classes/helper.php b/question/bank/history/classes/helper.php new file mode 100644 index 00000000000..b9ee5f54ede --- /dev/null +++ b/question/bank/history/classes/helper.php @@ -0,0 +1,47 @@ +. + +namespace qbank_history; + +/** + * Helper class for question history. + * + * @package qbank_history + * @copyright 2022 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class helper { + + /** + * Get the question history url. + * + * @param int $entryid id of the question entry + * @param string $returnrul url of the page to return to + * @param int $courseid id of the course + * @return \moodle_url + */ + public static function question_history_url(int $entryid, string $returnrul, int $courseid): \moodle_url { + $params = [ + 'entryid' => $entryid, + 'returnurl' => $returnrul, + 'courseid' => $courseid + ]; + + return new \moodle_url('/question/bank/history/history.php', $params); + } + +} diff --git a/question/bank/history/classes/history_action_column.php b/question/bank/history/classes/history_action_column.php new file mode 100644 index 00000000000..b3e9116c76c --- /dev/null +++ b/question/bank/history/classes/history_action_column.php @@ -0,0 +1,60 @@ +. + +namespace qbank_history; + +use core_question\local\bank\menu_action_column_base; + +/** + * Question bank column for the history action icon. + * + * @package qbank_history + * @copyright 2022 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class history_action_column extends menu_action_column_base { + + // Store this lang string for performance. + protected $strpreview; + + public function init(): void { + parent::init(); + $this->strpreview = get_string('history_action', 'qbank_history'); + } + + public function get_name(): string { + return 'historyaction'; + } + + protected function get_url_icon_and_label(\stdClass $question): array { + if (!\question_bank::is_qtype_installed($question->qtype)) { + // It sometimes happens that people end up with junk questions + // in their question bank of a type that is no longer installed. + // We cannot do most actions on them, because that leads to errors. + return [null, null, null]; + } + + if (question_has_capability_on($question, 'use')) { + $url = helper::question_history_url($question->questionbankentryid, $this->qbank->returnurl, + $this->qbank->course->id); + return [$url, 't/log', $this->strpreview]; + } + + return [null, null, null]; + } + +} diff --git a/question/bank/history/classes/output/renderer.php b/question/bank/history/classes/output/renderer.php new file mode 100644 index 00000000000..254f9cea021 --- /dev/null +++ b/question/bank/history/classes/output/renderer.php @@ -0,0 +1,39 @@ +. + +namespace qbank_history\output; + +/** + * Class renderer for rendering question history. + * + * @package qbank_history + * @copyright 2022 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class renderer extends \plugin_renderer_base { + + /** + * Render the history header. + * + * @param array $historydata data to be passed in the mustache + * @return string + */ + public function render_history_header(array $historydata): string { + return $this->render_from_template('qbank_history/history_header', $historydata); + } + +} diff --git a/question/bank/history/classes/plugin_feature.php b/question/bank/history/classes/plugin_feature.php new file mode 100644 index 00000000000..304f77d47e7 --- /dev/null +++ b/question/bank/history/classes/plugin_feature.php @@ -0,0 +1,36 @@ +. + +namespace qbank_history; + +/** + * Class plugin_feature is the entrypoint for the columns. + * + * @package qbank_history + * @copyright 2022 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class plugin_feature extends \core_question\local\bank\plugin_features_base { + + public function get_question_columns($qbank): array { + return [ + new history_action_column($qbank), + new version_number_column($qbank) + ]; + } + +} diff --git a/question/bank/history/classes/privacy/provider.php b/question/bank/history/classes/privacy/provider.php new file mode 100644 index 00000000000..7a639ed4049 --- /dev/null +++ b/question/bank/history/classes/privacy/provider.php @@ -0,0 +1,33 @@ +. + +namespace qbank_history\privacy; + +/** + * Privacy Subsystem for qbank_history implementing null_provider. + * + * @package qbank_history + * @copyright 2022 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements \core_privacy\local\metadata\null_provider { + + public static function get_reason(): string { + return 'privacy:metadata'; + } + +} diff --git a/question/bank/history/classes/question_history_view.php b/question/bank/history/classes/question_history_view.php new file mode 100644 index 00000000000..4d0d47c9cce --- /dev/null +++ b/question/bank/history/classes/question_history_view.php @@ -0,0 +1,199 @@ +. + +namespace qbank_history; + +use core_question\local\bank\question_edit_contexts; +use core_question\local\bank\view; +use moodle_url; +use stdClass; + +/** + * Custom view class for the history page. + * + * @package qbank_history + * @copyright 2022 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class question_history_view extends view { + + /** + * Entry id to get the versions + * + * @var int $entryid + */ + protected $entryid; + + /** + * Base url for the return. + * + * @var \moodle_url $basereturnurl + */ + protected $basereturnurl; + + /** + * Constructor for the history. + * @param question_edit_contexts $contexts the contexts of api call + * @param moodle_url $pageurl url of the page + * @param stdClass $course course settings + * @param int $entryid quiz settings + * @param string $returnurl url to return to + */ + public function __construct(question_edit_contexts $contexts, moodle_url $pageurl, stdClass $course, int $entryid, + string $returnurl) { + parent::__construct($contexts, $pageurl, $course); + $this->entryid = $entryid; + $this->basereturnurl = new \moodle_url($returnurl); + } + + protected function wanted_columns(): array { + $this->requiredcolumns = []; + $excludefeatures = [ + 'question_usage_column', + 'history_action_column' + ]; + $questionbankcolumns = $this->get_question_bank_plugins(); + foreach ($questionbankcolumns as $classobject) { + if (empty($classobject) || in_array($classobject->get_column_name(), $excludefeatures)) { + continue; + } + $this->requiredcolumns[$classobject->get_column_name()] = $classobject; + } + + return $this->requiredcolumns; + } + + public function wanted_filters($cat, $tagids, $showhidden, $recurse, $editcontexts, $showquestiontext): void { + $categorydata = explode(',', $cat); + $contextid = $categorydata[1]; + $catcontext = \context::instance_by_id($contextid); + $thiscontext = $this->get_most_specific_context(); + $this->display_question_bank_header(); + + // Display tag filter if usetags setting is enabled/enablefilters is true. + if ($this->enablefilters) { + if (is_array($this->customfilterobjects)) { + foreach ($this->customfilterobjects as $filterobjects) { + $this->searchconditions[] = $filterobjects; + } + } else { + if (get_config('core', 'usetags')) { + array_unshift($this->searchconditions, + new \core_question\bank\search\tag_condition([$catcontext, $thiscontext], $tagids)); + } + + array_unshift($this->searchconditions, new \core_question\bank\search\hidden_condition(!$showhidden)); + } + } + $this->display_options_form($showquestiontext); + } + + protected function display_advanced_search_form($advancedsearch): void { + foreach ($advancedsearch as $searchcondition) { + echo $searchcondition->display_options_adv(); + } + } + + protected function create_new_question_form($category, $canadd): void { + // As we dont want to create questions in this page. + } + + /** + * Default sort for question data. + * @return array + */ + protected function default_sort(): array { + $defaultsort = []; + if (class_exists('\\qbank_viewcreator\\creator_name_column')) { + $sort = 'qbank_viewcreator\creator_name_column-timecreated'; + } + $defaultsort[$sort] = 1; + + return $defaultsort; + } + + protected function build_query(): void { + // Get the required tables and fields. + $joins = []; + $fields = ['qv.status', 'qv.version', 'qv.id as versionid', 'qbe.id as questionbankentryid']; + if (!empty($this->requiredcolumns)) { + foreach ($this->requiredcolumns as $column) { + $extrajoins = $column->get_extra_joins(); + foreach ($extrajoins as $prefix => $join) { + if (isset($joins[$prefix]) && $joins[$prefix] != $join) { + throw new \coding_exception('Join ' . $join . ' conflicts with previous join ' . $joins[$prefix]); + } + $joins[$prefix] = $join; + } + $fields = array_merge($fields, $column->get_required_fields()); + } + } + $fields = array_unique($fields); + + // Build the order by clause. + $sorts = []; + foreach ($this->sort as $sort => $order) { + list($colname, $subsort) = $this->parse_subsort($sort); + $sorts[] = $this->requiredcolumns[$colname]->sort_expression($order < 0, $subsort); + } + + // Build the where clause. + $entryid = "qbe.id = $this->entryid"; + // Changes done here to get the questions only for the passed entryid. + $tests = ['q.parent = 0', $entryid]; + $this->sqlparams = []; + foreach ($this->searchconditions as $searchcondition) { + if ($searchcondition->where()) { + $tests[] = '((' . $searchcondition->where() .'))'; + } + if ($searchcondition->params()) { + $this->sqlparams = array_merge($this->sqlparams, $searchcondition->params()); + } + } + // Build the SQL. + $sql = ' FROM {question} q ' . implode(' ', $joins); + $sql .= ' WHERE ' . implode(' AND ', $tests); + $this->countsql = 'SELECT count(1)' . $sql; + $this->loadsql = 'SELECT ' . implode(', ', $fields) . $sql . ' ORDER BY ' . implode(', ', $sorts); + } + + /** + * Display the header for the question bank in the history page to include question name and type. + */ + public function display_question_bank_header(): void { + global $PAGE, $DB; + $sql = 'SELECT q.* + FROM {question} q + JOIN {question_versions} qv ON qv.questionid = q.id + JOIN {question_bank_entries} qbe ON qbe.id = qv.questionbankentryid + WHERE qv.version = (SELECT MAX(v.version) + FROM {question_versions} v + JOIN {question_bank_entries} be + ON be.id = v.questionbankentryid + WHERE be.id = qbe.id) + AND qbe.id = ?'; + $latestquestiondata = $DB->get_record_sql($sql, [$this->entryid]); + $historydata = [ + 'questionname' => $latestquestiondata->name, + 'returnurl' => $this->basereturnurl, + 'questionicon' => print_question_icon($latestquestiondata) + ]; + // Header for the page before the actual form from the api. + echo $PAGE->get_renderer('qbank_history')->render_history_header($historydata); + } + +} diff --git a/question/bank/history/classes/version_number_column.php b/question/bank/history/classes/version_number_column.php new file mode 100644 index 00000000000..f003add71b7 --- /dev/null +++ b/question/bank/history/classes/version_number_column.php @@ -0,0 +1,43 @@ +. + +namespace qbank_history; + +use core_question\local\bank\column_base; + +/** + * Question bank column for the question version number. + * + * @package qbank_history + * @copyright 2022 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class version_number_column extends column_base { + + public function get_name(): string { + return 'questionversionnumber'; + } + + protected function get_title(): string { + return get_string('questionversionnumber', 'qbank_history'); + } + + protected function display_content($question, $rowclasses): void { + print_string('questionversiondata', 'qbank_history', $question->version); + } + +} diff --git a/question/bank/history/history.php b/question/bank/history/history.php new file mode 100644 index 00000000000..f4e12a2f7ab --- /dev/null +++ b/question/bank/history/history.php @@ -0,0 +1,53 @@ +. + +/** + * Question history preview. + * + * @package qbank_history + * @copyright 2022 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once(__DIR__ . '/../../../config.php'); +require_once($CFG->dirroot . '/question/editlib.php'); + +require_login(); +core_question\local\bank\helper::require_plugin_enabled('qbank_history'); + +$entryid = required_param('entryid', PARAM_INT); +$returnurl = required_param('returnurl', PARAM_RAW); + +list($thispageurl, $contexts, $cmid, $cm, $module, $pagevars) = + question_edit_setup('questions', '/question/bank/history/history.php'); + +$url = new moodle_url($thispageurl, ['entryid' => $entryid, 'returnurl' => $returnurl]); +$PAGE->set_url($url); +$questionbank = new \qbank_history\question_history_view($contexts, $url, $COURSE, $entryid, $returnurl, $cm); + +$streditingquestions = get_string('history_header', 'qbank_history'); +$PAGE->set_title($streditingquestions); +$PAGE->set_heading($streditingquestions); +$context = $contexts->lowest(); +$PAGE->set_context($context); +$PAGE->navbar->add(get_string('question'), new moodle_url($returnurl)); +$PAGE->navbar->add($streditingquestions, $url); + +echo $OUTPUT->header(); +// Print the question area. +$questionbank->display($pagevars, 'questions'); +echo $OUTPUT->footer(); diff --git a/question/bank/history/lang/en/qbank_history.php b/question/bank/history/lang/en/qbank_history.php new file mode 100644 index 00000000000..63e30456d71 --- /dev/null +++ b/question/bank/history/lang/en/qbank_history.php @@ -0,0 +1,32 @@ +. + +/** + * Strings for component qbank_history, language 'en'. + * + * @package qbank_history + * @copyright 2022 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['close_history'] = 'Close'; +$string['history_action'] = 'History'; +$string['history_header'] = 'Question history'; +$string['pluginname'] = 'Question history'; +$string['privacy:metadata'] = 'Question history plugin does not store any user data.'; +$string['questionversionnumber'] = 'Version'; +$string['questionversiondata'] = 'v{$a}'; diff --git a/question/bank/history/templates/history_header.mustache b/question/bank/history/templates/history_header.mustache new file mode 100644 index 00000000000..5efb37c6ad0 --- /dev/null +++ b/question/bank/history/templates/history_header.mustache @@ -0,0 +1,45 @@ +{{! + 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 . +}} +{{! + @template qbank_history/history_header + + The header of the history page. + * returnurl - The url of the page to return to, usually the base qbank page + * questionincon - The icon of the question type + * questionname - The name of the latest question version + + Example context (json): + { + "returnurl": "https://url/courseid=1", + "questionicon": "", + "questionname": "Question 1" + } +}} + +
+
+
+

+ {{{questionicon}}} + {{questionname}} +

+
+ +
+
diff --git a/question/bank/history/tests/behat/question_history_action.feature b/question/bank/history/tests/behat/question_history_action.feature new file mode 100644 index 00000000000..982c9070f04 --- /dev/null +++ b/question/bank/history/tests/behat/question_history_action.feature @@ -0,0 +1,53 @@ +@qbank @qbank_history +Feature: Use the qbank plugin manager page for question history + In order to check the plugin behaviour with enable and disable + + Background: + Given the following "courses" exist: + | fullname | shortname | category | + | Course 1 | C1 | 0 | + And the following "activities" exist: + | activity | name | course | idnumber | + | quiz | Test quiz | C1 | quiz1 | + And the following "question categories" exist: + | contextlevel | reference | name | + | Course | C1 | Test questions | + And the following "questions" exist: + | questioncategory | qtype | name | questiontext | + | Test questions | truefalse | First question | Answer the first question | + + @javascript + Scenario: Enable/disable question history column from the base view + Given I log in as "admin" + When I navigate to "Plugins > Question bank plugins > Manage question bank plugins" in site administration + And I should see "Question history" + And I click on "Disable" "link" in the "Question history" "table_row" + And I am on the "Test quiz" "quiz activity" page + And I navigate to "Question bank" in current page administration + And I click on ".dropdown-toggle" "css_element" in the "First question" "table_row" + Then I should not see "History" in the "region-main" "region" + And I navigate to "Plugins > Question bank plugins > Manage question bank plugins" in site administration + And I click on "Enable" "link" in the "Question history" "table_row" + And I am on the "Test quiz" "quiz activity" page + And I navigate to "Question bank" in current page administration + And I click on ".dropdown-toggle" "css_element" in the "First question" "table_row" + And I should see "History" in the "region-main" "region" + + Scenario: History page shows only the specified features and questions + Given I log in as "admin" + And I am on the "Test quiz" "quiz activity" page + When I navigate to "Question bank" in current page administration + And I choose "History" action for "First question" in the question bank + Then I should not see "Select a category" + And I should see "No tag filters applied" + And I should see "Question" + And I should see "Actions" + And I should see "Status" + And I should see "Version" + And I should see "Created by" + And I should see "First question" + And I click on ".dropdown-toggle" "css_element" in the "First question" "table_row" + But I should not see "History" + And I click on "#qbank-history-close" "css_element" + And I click on ".dropdown-toggle" "css_element" in the "First question" "table_row" + And I should see "History" in the "region-main" "region" diff --git a/question/bank/history/tests/behat/question_version_column.feature b/question/bank/history/tests/behat/question_version_column.feature new file mode 100644 index 00000000000..87d365d375f --- /dev/null +++ b/question/bank/history/tests/behat/question_version_column.feature @@ -0,0 +1,31 @@ +@qbank @qbank_history +Feature: Use the qbank plugin manager page for version column + In order to check the plugin behaviour with enable and disable + + Background: + Given the following "courses" exist: + | fullname | shortname | category | + | Course 1 | C1 | 0 | + And the following "activities" exist: + | activity | name | course | idnumber | + | quiz | Test quiz | C1 | quiz1 | + And the following "question categories" exist: + | contextlevel | reference | name | + | Course | C1 | Test questions | + And the following "questions" exist: + | questioncategory | qtype | name | questiontext | + | Test questions | truefalse | First question | Answer the first question | + + Scenario: Enable/disable version column from the base view + Given I log in as "admin" + And I navigate to "Plugins > Question bank plugins > Manage question bank plugins" in site administration + And I should see "Question history" + When I click on "Disable" "link" in the "Question history" "table_row" + And I am on the "Test quiz" "quiz activity" page + And I navigate to "Question bank" in current page administration + Then I should not see "Version" in the "region-main" "region" + And I navigate to "Plugins > Question bank plugins > Manage question bank plugins" in site administration + And I click on "Enable" "link" in the "Question history" "table_row" + And I am on the "Test quiz" "quiz activity" page + And I navigate to "Question bank" in current page administration + And I should see "Version" in the "region-main" "region" diff --git a/question/bank/history/tests/helper_test.php b/question/bank/history/tests/helper_test.php new file mode 100644 index 00000000000..cdc37dd823f --- /dev/null +++ b/question/bank/history/tests/helper_test.php @@ -0,0 +1,90 @@ +. + +namespace qbank_history; + +use question_bank; + +/** + * Helper class test. + * + * @package qbank_history + * @copyright 2022 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @coversDefaultClass \qbank_history\helper + */ +class helper_test extends \advanced_testcase { + /** + * @var bool|\context|\context_course $context + */ + public $context; + + /** + * @var object $questiondata; + */ + public $questiondata; + + /** + * @var \moodle_url $returnurl + */ + public $returnurl; + + /** + * @var int $courseid + */ + public $courseid; + + /** + * Test set up. + * + * This is executed before running any test in this file. + */ + public function setUp(): void { + $this->setAdminUser(); + $generator = $this->getDataGenerator(); + $questiongenerator = $generator->get_plugin_generator('core_question'); + // Create a course. + $course = $generator->create_course(); + $this->courseid = $course->id; + $this->context = \context_course::instance($course->id); + // Create a question in the default category. + $contexts = new \core_question\local\bank\question_edit_contexts($this->context); + $cat = question_make_default_categories($contexts->all()); + $question = $questiongenerator->create_question('numerical', null, + ['name' => 'Example question', 'category' => $cat->id]); + $this->questiondata = question_bank::load_question($question->id); + $this->returnurl = new \moodle_url('/question/edit.php'); + } + + /** + * Test the history action url from the helper class. + * + * @covers ::question_history_url + */ + public function test_question_history_url() { + $this->resetAfterTest(); + $actionurl = helper::question_history_url($this->questiondata->questionbankentryid, $this->returnurl, $this->courseid); + $params = [ + 'entryid' => $this->questiondata->questionbankentryid, + 'returnurl' => $this->returnurl, + 'courseid' => $this->courseid + ]; + $expectedurl = new \moodle_url('/question/bank/history/history.php', $params); + $this->assertEquals($expectedurl, $actionurl); + } + +} diff --git a/question/bank/history/tests/question_history_view_test.php b/question/bank/history/tests/question_history_view_test.php new file mode 100644 index 00000000000..5c5c561c968 --- /dev/null +++ b/question/bank/history/tests/question_history_view_test.php @@ -0,0 +1,123 @@ +. + +namespace qbank_history; + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->dirroot . '/question/editlib.php'); + +/** + * Custom history view - qbank api test. + * + * @package qbank_history + * @copyright 2022 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @coversDefaultClass \qbank_history\question_history_view + */ +class question_history_view_test extends \advanced_testcase { + + /** + * Test that the history page shows all the versions of a question. + * + * @covers ::display + */ + public function test_question_history_shows_all_versions() { + $this->resetAfterTest(); + $this->setAdminUser(); + $generator = $this->getDataGenerator(); + $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); + + // Create a course. + $course = $generator->create_course(); + $context = \context_course::instance($course->id); + + // Create a question in the default category. + $contexts = new \core_question\local\bank\question_edit_contexts($context); + $cat = $questiongenerator->create_question_category(); + $questiondata1 = $questiongenerator->create_question('numerical', null, + ['name' => 'Example question', 'category' => $cat->id]); + + // Create a new version. + $questiondata2 = $questiongenerator->update_question($questiondata1, null, + ['name' => 'Example question second version']); + + $entry = get_question_bank_entry($questiondata1->id); + + // Generate the view. + $view = new question_history_view($contexts, new \moodle_url('/'), $course, $entry->id, '/'); + ob_start(); + $pagevars = [ + 'qpage' => 0, + 'qperpage' => 20, + 'cat' => $cat->id . ',' . $cat->contextid, + 'recurse' => false, + 'showhidden' => false, + 'qbshowtext' => false + ]; + $view->display($pagevars, 'questions'); + $html = ob_get_clean(); + + // Verify the output includes the first version. + $this->assertStringContainsString($questiondata1->name, $html); + + // Verify the output includes the second version. + $this->assertStringContainsString($questiondata2->name, $html); + } + + /** + * Test that the question bank header in the history page shows the latest question. + * + * @covers ::display_question_bank_header + */ + public function test_display_question_bank_header() { + $this->resetAfterTest(); + $this->setAdminUser(); + $generator = $this->getDataGenerator(); + $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); + + // Create a course. + $course = $generator->create_course(); + $context = \context_course::instance($course->id); + + // Create a question in the default category. + $contexts = new \core_question\local\bank\question_edit_contexts($context); + $cat = $questiongenerator->create_question_category(); + $questiondata1 = $questiongenerator->create_question('numerical', null, + ['name' => 'First version', 'category' => $cat->id]); + + $entry = get_question_bank_entry($questiondata1->id); + + // Generate the view. + $view = new question_history_view($contexts, new \moodle_url('/'), $course, $entry->id, '/'); + ob_start(); + $view->display_question_bank_header(); + $headerhtml = ob_get_clean(); + // Verify the output includes the latest version. + $this->assertStringContainsString($questiondata1->name, $headerhtml); + + $questiondata2 = $questiongenerator->update_question($questiondata1, null, + ['name' => 'Second version']); + $view = new question_history_view($contexts, new \moodle_url('/'), $course, $entry->id, new \moodle_url('/')); + ob_start(); + $view->display_question_bank_header(); + $headerhtml = ob_get_clean(); + + $this->assertStringContainsString($questiondata2->name, $headerhtml); + } +} diff --git a/question/bank/history/version.php b/question/bank/history/version.php new file mode 100644 index 00000000000..5e2387fadef --- /dev/null +++ b/question/bank/history/version.php @@ -0,0 +1,31 @@ +. + +/** + * Version information for qbank_history. + * + * @package qbank_history + * @copyright 2022 Catalyst IT Australia Pty Ltd + * @author Safat Shahin + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$plugin->component = 'qbank_history'; +$plugin->version = 2022020700; +$plugin->requires = 2021052500; +$plugin->maturity = MATURITY_STABLE; diff --git a/question/classes/local/bank/view.php b/question/classes/local/bank/view.php index d04fb34d49d..1babed2e83c 100644 --- a/question/classes/local/bank/view.php +++ b/question/classes/local/bank/view.php @@ -242,9 +242,11 @@ class view { 'copy_action_column', 'tags_action_column', 'preview_action_column', + 'history_action_column', 'delete_action_column', 'export_xml_action_column', 'question_status_column', + 'version_number_column', 'creator_name_column', 'comment_count_column' ];