From 97e90f2210838b9af101879d9747a9e5d8439565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luca=20B=C3=B6sch?= Date: Tue, 26 Mar 2024 18:16:54 +0100 Subject: [PATCH 1/2] MDL-80965 mod_quiz: Put back random q category on the question page. --- mod/quiz/classes/output/edit_renderer.php | 3 +- mod/quiz/classes/structure.php | 124 ++++++++++++++++++ mod/quiz/lang/en/quiz.php | 2 + .../tests/behat/editing_add_random.feature | 8 +- .../tests/behat/editing_edit_random.feature | 8 +- .../editing_remove_multiple_questions.feature | 6 +- mod/quiz/tests/behat/random_question.feature | 12 +- 7 files changed, 144 insertions(+), 19 deletions(-) diff --git a/mod/quiz/classes/output/edit_renderer.php b/mod/quiz/classes/output/edit_renderer.php index 23878367b50..24abecc6ede 100644 --- a/mod/quiz/classes/output/edit_renderer.php +++ b/mod/quiz/classes/output/edit_renderer.php @@ -25,7 +25,6 @@ namespace mod_quiz\output; use core_question\local\bank\question_version_status; -use mod_quiz\question\bank\qbank_helper; use \mod_quiz\structure; use \html_writer; use qbank_previewquestion\question_preview_options; @@ -1067,7 +1066,7 @@ class edit_renderer extends \plugin_renderer_base { $temp = clone($question); $temp->questiontext = ''; - $temp->name = qbank_helper::describe_random_question($slot); + $temp->name = $structure->describe_random_slot($slot->id); $instancename = quiz_question_tostring($temp); $configuretitle = get_string('configurerandomquestion', 'quiz'); diff --git a/mod/quiz/classes/structure.php b/mod/quiz/classes/structure.php index 0d772a0f4f9..7d2aaabdd52 100644 --- a/mod/quiz/classes/structure.php +++ b/mod/quiz/classes/structure.php @@ -69,6 +69,12 @@ class structure { /** @var bool caches the results of can_add_random_question. */ protected $canaddrandom = null; + /** @var array the slotids => question categories array for all slots containing a random question. */ + protected $randomslotcategories = null; + + /** @var array the slotids => question tags array for all slots containing a random question. */ + protected $randomslottags = null; + /** * Create an instance of this class representing an empty quiz. * @@ -1701,4 +1707,122 @@ class structure { $randomslot->insert($addonpage); } } + + /** + * Get a human-readable description of a random slot. + * + * @param int $slotid id of slot. + * @return string that can be used to display the random slot. + */ + public function describe_random_slot($slotid) { + $this->ensure_random_slot_info_loaded(); + + if (!isset($this->randomslotcategories[$slotid])) { + throw new coding_exception('Called describe_random_slot on slot id ' . + $slotid . ' which is not a random slot.'); + } + + // Build the random question name with categories and tags information and return. + $a = new stdClass(); + $a->category = $this->randomslotcategories[$slotid]; + $stringid = 'randomqnamecat'; + + if (!empty($this->randomslottags[$slotid])) { + $a->tags = $this->randomslottags[$slotid]; + $stringid = 'randomqnamecattags'; + } + + return shorten_text(get_string($stringid, 'quiz', $a), 255); + } + + /** + * Ensure that {@see load_random_slot_info()} has been called, so the data is available. + */ + protected function ensure_random_slot_info_loaded() { + if ($this->randomslotcategories == null) { + $this->load_random_slot_info(); + } + } + + /** + * Load information about the question categories and tags for all random slots, + */ + protected function load_random_slot_info() { + global $DB; + + // Find the random slots. + $allslots = $this->get_slots(); + foreach ($allslots as $key => $slot) { + if ($slot->qtype != 'random') { + unset($allslots[$key]); + } + } + if (empty($allslots)) { + // No random slots. Nothing to do. + $this->randomslotcategories = []; + $this->randomslottags = []; + return; + } + + // Loop over all random slots to build arrays of the data we will need. + $tagids = []; + $questioncategoriesids = []; + $randomcategoriesandtags = []; // An associative array of slotid => ['cat' => catid, 'tag' => [tagid, tagid, ...]]. + foreach ($allslots as $slotid => $slot) { + foreach ($slot->filtercondition as $name => $value) { + if ($name !== 'filter') { + continue; + } + + // Parse the filter condition. + foreach ($value as $filteroption => $filtervalue) { + if ($filteroption === 'category') { + $randomcategoriesandtags[$slotid]['cat'] = $filtervalue['values']; + $questioncategoriesids[] = $filtervalue['values'][0]; + } + + if ($filteroption === 'qtagids') { + foreach ($filtervalue as $qtagidsoption => $qtagidsvalue) { + if ($qtagidsoption !== 'values') { + continue; + } + foreach ($qtagidsvalue as $qtagidsvaluevalue) { + $randomcategoriesandtags[$slotid]['tag'][] = $qtagidsvaluevalue; + $tagids[] = $qtagidsvaluevalue; + } + } + } + } + } + } + + // Get names for all tags into a tagid => name array. + $tags = \core_tag_tag::get_bulk($tagids, 'id, rawname'); + $tagnames = array_map(fn($tag) => $tag->get_display_name(), $tags); + + // Get names for all question categories. + $categories = $DB->get_records_list('question_categories', 'id', $questioncategoriesids, + 'id', 'id, name, contextid, parent'); + $categorynames = []; + foreach ($categories as $id => $category) { + if ($category->name === 'top') { + $categoryname = $DB->get_field('question_categories', 'name', ['parent' => $id]); + } else { + $categoryname = $category->name; + } + $categorynames[$id] = $categoryname; + } + + // Now, put the data required for each slot into $this->randomslotcategories and $this->randomslottags. + foreach ($randomcategoriesandtags as $slotid => $catandtags) { + $this->randomslotcategories[$slotid] = $categorynames[$catandtags['cat'][0]]; + if (isset($catandtags['tag'])) { + $slottagnames = []; + foreach ($catandtags['tag'] as $tagid) { + $slottagnames[] = $tagnames[$tagid]; + } + $this->randomslottags[$slotid] = implode(', ', $slottagnames); + } + } + } } diff --git a/mod/quiz/lang/en/quiz.php b/mod/quiz/lang/en/quiz.php index f7909ff2efa..fb1aee95300 100644 --- a/mod/quiz/lang/en/quiz.php +++ b/mod/quiz/lang/en/quiz.php @@ -849,6 +849,8 @@ $string['randomfromunavailabletag'] = '{$a} (unavailable)'; $string['randomnumber'] = 'Number of random questions'; $string['randomnosubcat'] = 'Questions from this category only, not its subcategories.'; $string['randomqname'] = 'Random question based on filter condition'; +$string['randomqnamecat'] = 'Random ({$a->category}) based on filter condition'; +$string['randomqnamecattags'] = 'Random ({$a->category}) based on filter condition with tags: {$a->tags}';$string['randomquestion'] = 'Random question'; $string['randomqnametags'] = 'Random question based on filter condition with tags: {$a}'; $string['randomquestion'] = 'Random question'; $string['randomquestion_help'] = 'A random question is a way of inserting a randomly-chosen question from a specified category or by a specified tag into an activity.'; diff --git a/mod/quiz/tests/behat/editing_add_random.feature b/mod/quiz/tests/behat/editing_add_random.feature index 7dc16b6dcb4..79e2a7a169d 100644 --- a/mod/quiz/tests/behat/editing_add_random.feature +++ b/mod/quiz/tests/behat/editing_add_random.feature @@ -77,8 +77,8 @@ Feature: Adding random questions to a quiz based on category and tags And I apply question bank filter "Tag" with value "foo" And I select "1" from the "randomcount" singleselect And I press "Add random question" - And I should see "Random question based on filter condition with tags: foo" on quiz page "1" - When I click on "Configure question" "link" in the "Random question based on filter condition with tags: foo" "list_item" + And I should see "Random (Questions Category 1) based on filter condition with tags: foo" on quiz page "1" + When I click on "Configure question" "link" in the "Random (Questions Category 1) based on filter condition with tags: foo" "list_item" Then I should see "Questions Category 1" And I should see "foo" And I should see "question 1 name" @@ -115,6 +115,6 @@ Feature: Adding random questions to a quiz based on category and tags | Name | New Random category | | Parent category | Default for Quiz 1 | And I press "Create category and add random question" - And I should see "Random question based on filter condition" on quiz page "1" - And I click on "Configure question" "link" in the "Random question based on filter condition" "list_item" + And I should see "Random (New Random category) based on filter condition" on quiz page "1" + And I click on "Configure question" "link" in the "Random (New Random category) based on filter condition" "list_item" Then I should see "New Random category" diff --git a/mod/quiz/tests/behat/editing_edit_random.feature b/mod/quiz/tests/behat/editing_edit_random.feature index df05f8344a6..827463f7ac0 100644 --- a/mod/quiz/tests/behat/editing_edit_random.feature +++ b/mod/quiz/tests/behat/editing_edit_random.feature @@ -45,10 +45,10 @@ Feature: Editing random questions already in a quiz based on category and tags And I apply question bank filter "Tag" with value "hard" And I press "Add random question" And I follow "Add page break" - When I click on "Configure question" "link" in the "Random question based on filter condition with tags: easy" "list_item" + When I click on "Configure question" "link" in the "Random (Questions Category 1) based on filter condition with tags: easy" "list_item" And I apply question bank filter "Tag" with value "essay" And I press "Update filter conditions" - Then I should see "Random question based on filter condition with tags: essay" on quiz page "1" - And I should see "Random question based on filter condition with tags: hard" on quiz page "2" - And I click on "Configure question" "link" in the "Random question based on filter condition with tags: hard" "list_item" + Then I should see "Random (Questions Category 1) based on filter condition with tags: essay" on quiz page "1" + And I should see "Random (Questions Category 1) based on filter condition with tags: essay, hard" on quiz page "2" + And I click on "Configure question" "link" in the "Random (Questions Category 1) based on filter condition with tags: hard" "list_item" And "hard" "autocomplete_selection" should be visible diff --git a/mod/quiz/tests/behat/editing_remove_multiple_questions.feature b/mod/quiz/tests/behat/editing_remove_multiple_questions.feature index 47df9df9d63..7a87eafc1f4 100644 --- a/mod/quiz/tests/behat/editing_remove_multiple_questions.feature +++ b/mod/quiz/tests/behat/editing_remove_multiple_questions.feature @@ -261,9 +261,9 @@ Feature: Edit quiz page - remove multiple questions And I click on "selectquestion-2" "checkbox" And I click on "Delete selected" "button" And I click on "Yes" "button" in the "Confirm" "dialogue" - Then I should see "Random question based on filter condition" on quiz page "1" - And I should not see "Random question based on filter condition" on quiz page "2" - And I should not see "Random question based on filter condition" on quiz page "3" + Then I should see "Random (Test questions) based on filter condition" on quiz page "1" + And I should not see "Random (Test questions) based on filter condition" on quiz page "2" + And I should not see "Random (Test questions) based on filter condition" on quiz page "3" And I should see "Total of marks: 1.00" And I should see "Questions: 1" diff --git a/mod/quiz/tests/behat/random_question.feature b/mod/quiz/tests/behat/random_question.feature index c61d6a65547..ae5080fdd58 100644 --- a/mod/quiz/tests/behat/random_question.feature +++ b/mod/quiz/tests/behat/random_question.feature @@ -35,8 +35,8 @@ Feature: Moving a question to another category should not affect random question And I follow "a random question" And I apply question bank filter "Category" with value "Used category" And I press "Add random question" - And I should see "Random question based on filter condition" on quiz page "1" - And I click on "Configure question" "link" in the "Random question based on filter condition" "list_item" + And I should see "Random (Used category) based on filter condition" on quiz page "1" + And I click on "Configure question" "link" in the "Random (Used category) based on filter condition" "list_item" And I should see "Used category" And I am on "Course 1" course homepage And I navigate to "Question bank" in current page administration @@ -49,8 +49,8 @@ Feature: Moving a question to another category should not affect random question Then I should see "Test question to be moved" And I should see "Subcategory (1)" And I am on the "Quiz 1" "mod_quiz > Edit" page - And I should see "Random question based on filter condition" on quiz page "1" - And I click on "Configure question" "link" in the "Random question based on filter condition" "list_item" + And I should see "Random (Used category) based on filter condition" on quiz page "1" + And I click on "Configure question" "link" in the "Random (Used category) based on filter condition" "list_item" And I should see "Used category" @javascript @@ -60,7 +60,7 @@ Feature: Moving a question to another category should not affect random question And I follow "a random question" And I apply question bank filter "Category" with value "Used category" And I press "Add random question" - And I should see "Random question based on filter condition" on quiz page "1" + And I should see "Random (Used category) based on filter condition" on quiz page "1" And I am on the "Course 1" "core_question > course question categories" page And I open the action menu in "Used category" "list_item" And I choose "Edit" in the open action menu @@ -72,4 +72,4 @@ Feature: Moving a question to another category should not affect random question Then I should see "Used category new" And I should see "I was edited" in the "Used category new" "list_item" And I am on the "Quiz 1" "mod_quiz > Edit" page - And I should see "Random question based on filter condition" on quiz page "1" + And I should see "Random (Used category new) based on filter condition" on quiz page "1" From 9c0e3c85eb976b03677ccd3a7bfdc08e424f1368 Mon Sep 17 00:00:00 2001 From: Ilya Tregubov Date: Wed, 18 Sep 2024 15:24:43 +0800 Subject: [PATCH 2/2] MDL-80965 mod_quiz: Code style fixes. --- mod/quiz/classes/structure.php | 6 +++--- mod/quiz/lang/en/quiz.php | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/mod/quiz/classes/structure.php b/mod/quiz/classes/structure.php index 7d2aaabdd52..168cce51917 100644 --- a/mod/quiz/classes/structure.php +++ b/mod/quiz/classes/structure.php @@ -1714,7 +1714,7 @@ class structure { * @param int $slotid id of slot. * @return string that can be used to display the random slot. */ - public function describe_random_slot($slotid) { + public function describe_random_slot(int $slotid): string { $this->ensure_random_slot_info_loaded(); if (!isset($this->randomslotcategories[$slotid])) { @@ -1738,7 +1738,7 @@ class structure { /** * Ensure that {@see load_random_slot_info()} has been called, so the data is available. */ - protected function ensure_random_slot_info_loaded() { + protected function ensure_random_slot_info_loaded(): void { if ($this->randomslotcategories == null) { $this->load_random_slot_info(); } @@ -1747,7 +1747,7 @@ class structure { /** * Load information about the question categories and tags for all random slots, */ - protected function load_random_slot_info() { + protected function load_random_slot_info(): void { global $DB; // Find the random slots. diff --git a/mod/quiz/lang/en/quiz.php b/mod/quiz/lang/en/quiz.php index fb1aee95300..6772987adef 100644 --- a/mod/quiz/lang/en/quiz.php +++ b/mod/quiz/lang/en/quiz.php @@ -850,7 +850,8 @@ $string['randomnumber'] = 'Number of random questions'; $string['randomnosubcat'] = 'Questions from this category only, not its subcategories.'; $string['randomqname'] = 'Random question based on filter condition'; $string['randomqnamecat'] = 'Random ({$a->category}) based on filter condition'; -$string['randomqnamecattags'] = 'Random ({$a->category}) based on filter condition with tags: {$a->tags}';$string['randomquestion'] = 'Random question'; +$string['randomqnamecattags'] = 'Random ({$a->category}) based on filter condition with tags: {$a->tags}'; +$string['randomquestion'] = 'Random question'; $string['randomqnametags'] = 'Random question based on filter condition with tags: {$a}'; $string['randomquestion'] = 'Random question'; $string['randomquestion_help'] = 'A random question is a way of inserting a randomly-chosen question from a specified category or by a specified tag into an activity.';