mirror of
https://github.com/moodle/moodle.git
synced 2025-03-18 22:50:19 +01:00
Merge branch 'MDL-77713' of https://github.com/cwarwicker/moodle
This commit is contained in:
commit
eb2be9fede
10
.upgradenotes/MDL-77713-2024120511165062.yml
Normal file
10
.upgradenotes/MDL-77713-2024120511165062.yml
Normal file
@ -0,0 +1,10 @@
|
||||
issueNumber: MDL-77713
|
||||
notes:
|
||||
core_question:
|
||||
- message: >-
|
||||
Deprecated method
|
||||
`mod_quiz\question\bank\qbank_helper::get_version_options` in favour of
|
||||
`core_question\local\bank\version_options::get_version_options` so that
|
||||
the method is in core rather than a module, and can safely be used from
|
||||
anywhere as required.
|
||||
type: deprecated
|
@ -27,6 +27,7 @@ $string['addcategory'] = 'Add category';
|
||||
$string['adminreport'] = 'Report on possible problems in your question database.';
|
||||
$string['advancedsearchoptions'] = 'Search options';
|
||||
$string['alltries'] = 'All tries';
|
||||
$string['alwayslatest'] = 'Always latest';
|
||||
$string['answers'] = 'Answers';
|
||||
$string['availableq'] = 'Available?';
|
||||
$string['badbase'] = 'Bad base before **: {$a}**';
|
||||
@ -533,6 +534,7 @@ $string['version_selection'] = 'Version {$a->version}';
|
||||
$string['versioninfo'] = 'Version {$a->version} (of {$a->latestversion})';
|
||||
$string['versioninfolatest'] = 'Version {$a->version} (latest)';
|
||||
$string['question_version'] = 'Question version';
|
||||
|
||||
$string['question_versionshort'] = 'v{$a}';
|
||||
$string['versioninfolatestshort'] = 'v{$a} (latest)';
|
||||
// Deprecated since Moodle 5.0.
|
||||
$string['errordeletingquestionsfromcategory'] = 'Error deleting questions from category {$a}.';
|
||||
|
@ -17,6 +17,7 @@
|
||||
namespace mod_quiz\question\bank;
|
||||
|
||||
use context_module;
|
||||
use core_question\local\bank\version_options;
|
||||
use core_question\local\bank\question_version_status;
|
||||
use core_question\local\bank\random_question_loader;
|
||||
use core_question\question_reference_manager;
|
||||
@ -46,25 +47,14 @@ class qbank_helper {
|
||||
* @return stdClass[] other versions of this question. Each object has fields versionid,
|
||||
* version and questionid. Array is returned most recent version first.
|
||||
*/
|
||||
#[\core\attribute\deprecated(
|
||||
'core_question\local\bank::get_version_options',
|
||||
since: 5.0,
|
||||
mdl: 'MDL-77713')
|
||||
]
|
||||
public static function get_version_options(int $questionid): array {
|
||||
global $DB;
|
||||
|
||||
return $DB->get_records_sql("
|
||||
SELECT allversions.id AS versionid,
|
||||
allversions.version,
|
||||
allversions.questionid
|
||||
|
||||
FROM {question_versions} allversions
|
||||
|
||||
WHERE allversions.questionbankentryid = (
|
||||
SELECT givenversion.questionbankentryid
|
||||
FROM {question_versions} givenversion
|
||||
WHERE givenversion.questionid = ?
|
||||
)
|
||||
AND allversions.status <> ?
|
||||
|
||||
ORDER BY allversions.version DESC
|
||||
", [$questionid, question_version_status::QUESTION_STATUS_DRAFT]);
|
||||
\core\deprecation::emit_deprecation_if_present([self::class, __FUNCTION__]);
|
||||
return version_options::get_version_options($questionid);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,6 +19,7 @@ namespace mod_quiz;
|
||||
use coding_exception;
|
||||
use context_module;
|
||||
use core\output\inplace_editable;
|
||||
use core_question\local\bank\version_options;
|
||||
use mod_quiz\event\quiz_grade_item_created;
|
||||
use mod_quiz\event\quiz_grade_item_deleted;
|
||||
use mod_quiz\event\quiz_grade_item_updated;
|
||||
@ -813,32 +814,19 @@ class structure {
|
||||
$slot = $this->get_slot_by_number($slotnumber);
|
||||
|
||||
// Get all the versions which exist.
|
||||
$versions = qbank_helper::get_version_options($slot->questionid);
|
||||
$latestversion = reset($versions);
|
||||
$versions = version_options::get_version_menu_options($slot->questionid);
|
||||
$versioninfo = [];
|
||||
|
||||
// Format the choices for display.
|
||||
$versionoptions = [];
|
||||
foreach ($versions as $version) {
|
||||
$version->selected = $version->version === $slot->requestedversion;
|
||||
|
||||
if ($version->version === $latestversion->version) {
|
||||
$version->versionvalue = get_string('questionversionlatest', 'quiz', $version->version);
|
||||
} else {
|
||||
$version->versionvalue = get_string('questionversion', 'quiz', $version->version);
|
||||
}
|
||||
|
||||
$versionoptions[] = $version;
|
||||
// Loop through them and set which one is selected.
|
||||
foreach ($versions as $versionnumber => $version) {
|
||||
$versioninfo[] = (object)[
|
||||
'version' => $versionnumber,
|
||||
'versionvalue' => $version,
|
||||
'selected' => ($versionnumber == $slot->requestedversion),
|
||||
];
|
||||
}
|
||||
|
||||
// Make a choice for 'Always latest'.
|
||||
$alwaysuselatest = new stdClass();
|
||||
$alwaysuselatest->versionid = 0;
|
||||
$alwaysuselatest->version = 0;
|
||||
$alwaysuselatest->versionvalue = get_string('alwayslatest', 'quiz');
|
||||
$alwaysuselatest->selected = $slot->requestedversion === null;
|
||||
array_unshift($versionoptions, $alwaysuselatest);
|
||||
|
||||
return $versionoptions;
|
||||
return $versioninfo;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,6 +88,7 @@ final class qbank_helper_test extends \advanced_testcase {
|
||||
$slots = $structure->get_slots();
|
||||
$slot = reset($slots);
|
||||
$this->assertEquals(3, count(qbank_helper::get_version_options($question->id)));
|
||||
$this->assertDebuggingCalled();
|
||||
$this->assertEquals($question->id, qbank_helper::choose_question_for_redo(
|
||||
$quiz->id, $context, $slot->id, new \qubaid_list([])));
|
||||
|
||||
|
@ -97,6 +97,7 @@ final class quiz_question_version_test extends \advanced_testcase {
|
||||
$this->assertEquals(4, $slot->version);
|
||||
// Now change the version using the external service.
|
||||
$versions = qbank_helper::get_version_options($slot->questionid);
|
||||
$this->assertDebuggingCalled();
|
||||
// We don't want the current version.
|
||||
$selectversions = [];
|
||||
foreach ($versions as $version) {
|
||||
@ -157,6 +158,7 @@ final class quiz_question_version_test extends \advanced_testcase {
|
||||
$slot = reset($slots);
|
||||
// Now change the version using the external service.
|
||||
$versions = qbank_helper::get_version_options($slot->questionid);
|
||||
$this->assertDebuggingCalled();
|
||||
// We dont want the current version.
|
||||
$selectversions = [];
|
||||
foreach ($versions as $version) {
|
||||
|
@ -49,7 +49,6 @@ class preview_options_form extends moodleform {
|
||||
$mform->addElement('html', \html_writer::div(get_string('theoptionsyouselectonlyaffectthepreview',
|
||||
'qbank_previewquestion'), "col-md-12 row d-flex col-form-label mb-3"));
|
||||
$versions = $this->_customdata['versions'];
|
||||
$versions[question_preview_options::ALWAYS_LATEST] = get_string('alwayslatest', 'qbank_previewquestion');
|
||||
$currentversion = $this->_customdata['restartversion'];
|
||||
$select = $mform->addElement('select', 'restartversion', get_string('questionversion', 'qbank_previewquestion'), $versions);
|
||||
$select->setSelected($currentversion);
|
||||
|
@ -35,6 +35,7 @@ use \core\notification;
|
||||
use qbank_previewquestion\form\preview_options_form;
|
||||
use qbank_previewquestion\question_preview_options;
|
||||
use qbank_previewquestion\helper;
|
||||
use core_question\local\bank\version_options;
|
||||
|
||||
/**
|
||||
* The maximum number of variants previewable. If there are more variants than this for a question
|
||||
@ -130,13 +131,15 @@ if ($previewid) {
|
||||
$options->behaviour = $quba->get_preferred_behaviour();
|
||||
$options->maxmark = $quba->get_question_max_mark($slot);
|
||||
|
||||
// Load the question versions and convert to a simple array for select menu.
|
||||
$versions = version_options::get_version_menu_options($question->id);
|
||||
$versionids = helper::load_versions($question->questionbankentryid);
|
||||
// Create the settings form, and initialise the fields.
|
||||
$optionsform = new preview_options_form(helper::question_preview_form_url($question->id, $context, $previewid, $returnurl),
|
||||
[
|
||||
'quba' => $quba,
|
||||
'maxvariant' => $maxvariant,
|
||||
'versions' => array_combine(array_values($versionids), array_values($versionids)),
|
||||
'versions' => $versions,
|
||||
'restartversion' => $restartversion,
|
||||
]);
|
||||
$optionsform->set_data($options);
|
||||
|
@ -101,19 +101,17 @@ Feature: A teacher can preview questions in the question bank
|
||||
And I click on "submitbutton" "button"
|
||||
And I choose "Preview" action for "New version" in the question bank
|
||||
When I expand all fieldsets
|
||||
And I should see "Version 2"
|
||||
And I should see "(latest)"
|
||||
And I should see "Version 2 (latest)"
|
||||
And I should see "New version"
|
||||
And I should see "New text version"
|
||||
And I should not see "Test question to be previewed"
|
||||
And I should not see "Version 1"
|
||||
And I should see "1" in the "Question version" "select"
|
||||
And I should see "2" in the "Question version" "select"
|
||||
And I set the field "Question version" to "1"
|
||||
And I should see "v1" in the "Question version" "select"
|
||||
And I should see "v2" in the "Question version" "select"
|
||||
And I set the field "Question version" to "v1"
|
||||
And I press "Save preview options and start again"
|
||||
Then I should see "Version 1"
|
||||
And I should not see "Version 2"
|
||||
And I should not see "(latest)"
|
||||
And I should not see "Version 2 (latest)"
|
||||
|
||||
Scenario: The preview always uses the latest question version by default.
|
||||
Given the following "core_question > updated questions" exist:
|
||||
|
86
question/classes/local/bank/version_options.php
Normal file
86
question/classes/local/bank/version_options.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?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 core_question\local\bank;
|
||||
|
||||
/**
|
||||
* Helper methods for question version options.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2024 onwards Catalyst IT {@link http://www.catalyst-eu.net/}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @author Conn Warwicker <conn.warwicker@catalyst-eu.net>
|
||||
*/
|
||||
class version_options {
|
||||
|
||||
/**
|
||||
* Get the version options for display in dropdown menu
|
||||
* @param int $questionid
|
||||
* @return array
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public static function get_version_menu_options(int $questionid): array {
|
||||
|
||||
$versions = self::get_version_options($questionid);
|
||||
$latestversion = reset($versions);
|
||||
|
||||
$return = [];
|
||||
|
||||
// Add the "always latest" option to the beginning.
|
||||
$return[0] = get_string('alwayslatest', 'question');
|
||||
|
||||
foreach ($versions as $version) {
|
||||
if ($version->version === $latestversion->version) {
|
||||
$value = get_string('versioninfolatestshort', 'question', $version->version);
|
||||
} else {
|
||||
$value = get_string('question_versionshort', 'question', $version->version);
|
||||
}
|
||||
$return[$version->version] = $value;
|
||||
}
|
||||
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the available versions of a question where one of the version has the given question id.
|
||||
*
|
||||
* @param int $questionid id of a question.
|
||||
* @return stdClass[] other versions of this question. Each object has fields versionid,
|
||||
* version and questionid. Array is returned most recent version first.
|
||||
*/
|
||||
public static function get_version_options(int $questionid): array {
|
||||
global $DB;
|
||||
|
||||
return $DB->get_records_sql("
|
||||
SELECT allversions.id AS versionid,
|
||||
allversions.version,
|
||||
allversions.questionid
|
||||
|
||||
FROM {question_versions} allversions
|
||||
|
||||
WHERE allversions.questionbankentryid = (
|
||||
SELECT givenversion.questionbankentryid
|
||||
FROM {question_versions} givenversion
|
||||
WHERE givenversion.questionid = ?
|
||||
)
|
||||
AND allversions.status <> ?
|
||||
|
||||
ORDER BY allversions.version DESC
|
||||
", [$questionid, question_version_status::QUESTION_STATUS_DRAFT]);
|
||||
}
|
||||
|
||||
}
|
90
question/tests/local/bank/version_options_test.php
Normal file
90
question/tests/local/bank/version_options_test.php
Normal file
@ -0,0 +1,90 @@
|
||||
<?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 core_question\local\bank;
|
||||
|
||||
/**
|
||||
* Unit tests for the version_options class and associated methods.
|
||||
*
|
||||
* @package core_question
|
||||
* @copyright 2024 onwards Catalyst IT {@link http://www.catalyst-eu.net/}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @author Conn Warwicker <conn.warwicker@catalyst-eu.net>
|
||||
* @covers \core_question\local\bank\version_options
|
||||
*/
|
||||
final class version_options_test extends \advanced_testcase {
|
||||
|
||||
|
||||
/**
|
||||
* Tests the retrieval and correctness of version selection menu options for a given question.
|
||||
*
|
||||
* This method verifies that the correct version options are available for a specific question
|
||||
* within a course, ensuring that the options are accurately labeled and ordered. It includes
|
||||
* checks for version labeling, the presence of an "Always latest" option, and the correct count
|
||||
* and sequence of version numbers after creating multiple versions of a question.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_version_options(): void {
|
||||
|
||||
// Reset everything after this test completes.
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Load the generators we need.
|
||||
$questiongenerator = self::getDataGenerator()->get_plugin_generator('core_question');
|
||||
|
||||
// Create a test course we can use the question bank on.
|
||||
$category = self::getDataGenerator()->create_category();
|
||||
$course = self::getDataGenerator()->create_course(['category' => $category->id]);
|
||||
$coursecontext = \core\context\course::instance($course->id);
|
||||
|
||||
// Create a question category on the course.
|
||||
$cat = $questiongenerator->create_question_category(['contextid' => $coursecontext->id]);
|
||||
|
||||
// Create a question within that category.
|
||||
$question = $questiongenerator->create_question('essay', null,
|
||||
['category' => $cat->id, 'name' => 'This is the first version']);
|
||||
|
||||
// Get the select menu options for the question versions.
|
||||
$options = version_options::get_version_menu_options($question->id);
|
||||
|
||||
// Assert that there are 2 and that they "Always latest" is first.
|
||||
$this->assertCount(2, $options);
|
||||
$this->assertEquals('Always latest', $options[0]);
|
||||
$this->assertEquals('v1 (latest)', $options[1]);
|
||||
|
||||
// Create some new versions of the question.
|
||||
$questiongenerator->update_question($question, null, ['name' => 'This is the second version']);
|
||||
$questiongenerator->update_question($question, null, ['name' => 'This is the third version']);
|
||||
|
||||
// Get the options which would be used for the select menu.
|
||||
$options = version_options::get_version_menu_options($question->id);
|
||||
|
||||
// Assert that there are now 4.
|
||||
$this->assertCount(4, $options);
|
||||
|
||||
// Assert that they are keyed to their verison numbers.
|
||||
$this->assertEquals('Always latest', $options[0]);
|
||||
$this->assertEquals('v1', $options[1]);
|
||||
$this->assertEquals('v2', $options[2]);
|
||||
$this->assertEquals('v3 (latest)', $options[3]);
|
||||
|
||||
// Assert that they are in the correct order of "Always latest" first, then descending versions.
|
||||
$this->assertEquals(array_keys($options), [0, 3, 2, 1]);
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user