From 142012d312d593a0ae855f31f29df042a8bdcf0a Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Fri, 6 Dec 2024 16:10:30 +0000 Subject: [PATCH] MDL-83941 tags: prevent users from browsing unsearchable collections --- blocks/tags/edit_form.php | 16 ++------ blocks/tags/tests/behat/tagcloud.feature | 30 +++++++++++++++ tag/classes/collection.php | 10 ++++- tag/tests/taglib_test.php | 48 ++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 15 deletions(-) diff --git a/blocks/tags/edit_form.php b/blocks/tags/edit_form.php index 4ea82094984..4c56802f997 100644 --- a/blocks/tags/edit_form.php +++ b/blocks/tags/edit_form.php @@ -77,24 +77,14 @@ class block_tags_edit_form extends block_edit_form { * @param object $mform the form being built. */ protected function add_collection_selector($mform) { - $tagcolls = core_tag_collection::get_collections_menu(false, false, get_string('anycollection', 'block_tags')); + $tagcolls = core_tag_collection::get_collections_menu(false, true, get_string('anycollection', 'block_tags')); if (count($tagcolls) <= 1) { + $mform->addElement('hidden', 'config_tagcoll', 0); + $mform->setType('config_tagcoll', PARAM_INT); return; } - $tagcollssearchable = core_tag_collection::get_collections_menu(false, true); - $hasunsearchable = false; - foreach ($tagcolls as $id => $name) { - if ($id && !array_key_exists($id, $tagcollssearchable)) { - $hasunsearchable = true; - $tagcolls[$id] = $name . '*'; - } - } - $mform->addElement('select', 'config_tagcoll', get_string('tagcollection', 'block_tags'), $tagcolls); - if ($hasunsearchable) { - $mform->addHelpButton('config_tagcoll', 'tagcollection', 'block_tags'); - } $mform->setDefault('config_tagcoll', 0); } } diff --git a/blocks/tags/tests/behat/tagcloud.feature b/blocks/tags/tests/behat/tagcloud.feature index dbe47565bed..9fbd945744f 100644 --- a/blocks/tags/tests/behat/tagcloud.feature +++ b/blocks/tags/tests/behat/tagcloud.feature @@ -47,3 +47,33 @@ Feature: Block tags displaying tag cloud And I should see "User interests" in the ".tag-index-items h3" "css_element" And I should see "Teacher 1" And I log out + + @javascript + Scenario: Tag block configuration allows to select from searchable tag collections only + When I log in as "student1" + And I turn editing mode on + And I add the "Tags" block + And I configure the "Tags" block + Then I should not see "Tag collection" + And I press "Save changes" + And I log out + And I log in as "admin" + And I navigate to "Appearance > Manage tags" in site administration + And I follow "Add tag collection" + And I set the following fields to these values: + | Name | Collection1 | + | Searchable | 1 | + And I press "Create" + And I follow "Add tag collection" + And I set the following fields to these values: + | Name | Collection2 | + | Searchable | 0 | + And I press "Create" + And I log out + And I log in as "student1" + And I turn editing mode on + And I am on homepage + And I configure the "Tags" block + And the "Tag collection" select box should contain "Collection1" + And the "Tag collection" select box should not contain "Collection2" + And I press "Save changes" diff --git a/tag/classes/collection.php b/tag/classes/collection.php index 97147b23c8c..dd32ab6b63c 100644 --- a/tag/classes/collection.php +++ b/tag/classes/collection.php @@ -359,9 +359,15 @@ class core_tag_collection { $fromclause = 'FROM {tag_instance} ti JOIN {tag} tg ON tg.id = ti.tagid'; $whereclause = 'WHERE ti.itemtype <> \'tag\''; - list($sql, $params) = $DB->get_in_or_equal($tagcollid ? array($tagcollid) : - array_keys(self::get_collections(true))); + + // Get tags from all searchable tag collections, if $tagcollid is specifid, limit only to this collection. + $tagcollids = array_keys(self::get_collections(true)); + if ($tagcollid) { + $tagcollids = array_intersect($tagcollids, [$tagcollid]); + } + list($sql, $params) = $DB->get_in_or_equal($tagcollids, SQL_PARAMS_QM, 'param', true, -1); $whereclause .= ' AND tg.tagcollid ' . $sql; + if ($isstandard) { $whereclause .= ' AND tg.isstandard = 1'; } diff --git a/tag/tests/taglib_test.php b/tag/tests/taglib_test.php index baeb277283a..0e27d721754 100644 --- a/tag/tests/taglib_test.php +++ b/tag/tests/taglib_test.php @@ -19,6 +19,7 @@ namespace core_tag; use core_tag_area; use core_tag_collection; use core_tag_tag; +use core_tag; /** * Tag related unit tests. @@ -1940,4 +1941,51 @@ final class taglib_test extends \advanced_testcase { $record['id'] = $DB->insert_record('tag_instance', $record); return (object) $record; } + + /** + * Checks the contents of the a tagcloud + * + * @param array $tags + * @param \core_tag\output\tagcloud $tagcloud + */ + protected function assert_tag_cloud_contains_tags(array $tags, \core_tag\output\tagcloud $tagcloud) { + global $PAGE; + $renderer = $PAGE->get_renderer('core', 'tag'); + $result = $tagcloud->export_for_template($renderer); + $result = json_decode(json_encode($result), true); + $this->assertEqualsCanonicalizing($tags, array_values(array_column($result['tags'], 'name'))); + } + + public function test_get_tag_cloud(): void { + global $DB, $PAGE; + $this->resetAfterTest(); + + // Create a course and a user with tags. + $this->getDataGenerator()->create_course(['tags' => 'cats,animals']); + $this->getDataGenerator()->create_user(['interests' => 'dogs,animals']); + + // Default tag cloud contains all three tags. + $tagcloud = core_tag_collection::get_tag_cloud(0); + $this->assert_tag_cloud_contains_tags(['animals', 'cats', 'dogs'], $tagcloud); + + // Create two new tag collections, move course tags to C1 and user tags to C2. + $c1 = core_tag_collection::create((object)['name' => 'C1', 'searchable' => 1]); + $c2 = core_tag_collection::create((object)['name' => 'C2', 'searchable' => 1]); + $tagareacourse = $DB->get_record('tag_area', ['component' => 'core', 'itemtype' => 'course'], '*', MUST_EXIST); + core_tag_area::update($tagareacourse, ['tagcollid' => $c1->id]); + $tagareauser = $DB->get_record('tag_area', ['component' => 'core', 'itemtype' => 'user'], '*', MUST_EXIST); + core_tag_area::update($tagareauser, ['tagcollid' => $c2->id]); + + // Tag cloud still has all tags and you can also search by a collection. Tag 'animals' now has two different view links. + $this->assert_tag_cloud_contains_tags(['animals', 'animals', 'cats', 'dogs'], core_tag_collection::get_tag_cloud(0)); + $this->assert_tag_cloud_contains_tags(['animals', 'cats'], core_tag_collection::get_tag_cloud($c1->id)); + $this->assert_tag_cloud_contains_tags(['animals', 'dogs'], core_tag_collection::get_tag_cloud($c2->id)); + + // Make user interest tag area not searchable. + core_tag_collection::update($c2, ['searchable' => 0]); + // Check that the user interest tags do not appear in the tagclouds. + $this->assert_tag_cloud_contains_tags(['animals', 'cats'], core_tag_collection::get_tag_cloud(0)); + $this->assert_tag_cloud_contains_tags(['animals', 'cats'], core_tag_collection::get_tag_cloud($c1->id)); + $this->assert_tag_cloud_contains_tags([], core_tag_collection::get_tag_cloud($c2->id)); + } }