Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  namespace repository_contentbank;
  18  
  19  defined('MOODLE_INTERNAL') || die();
  20  
  21  global $CFG;
  22  
  23  require_once("$CFG->dirroot/repository/lib.php");
  24  
  25  /**
  26   * Tests for the content bank browser class.
  27   *
  28   * @package    repository_contentbank
  29   * @copyright  2020 Mihail Geshoski <mihail@moodle.com>
  30   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  31   */
  32  class browser_test extends \advanced_testcase {
  33  
  34      /**
  35       * Test get_content() in the system context with users that have capability to access/view content bank content
  36       * within the system context. By default, every authenticated user should be able to access/view the content in
  37       * the system context.
  38       */
  39      public function test_get_content_system_context_user_has_capabilities() {
  40          global $DB, $CFG;
  41  
  42          $this->resetAfterTest(true);
  43  
  44          $systemcontext = \context_system::instance();
  45          // Create a course category $coursecategory.
  46          $coursecategory = $this->getDataGenerator()->create_category(['name' => 'Category']);
  47          $coursecatcontext = \context_coursecat::instance($coursecategory->id);
  48  
  49          // Get the default course category.
  50          $defaultcat = \core_course_category::get(1);
  51          $defaultcatcontext = \context_coursecat::instance($defaultcat->id);
  52  
  53          // Create course.
  54          $course = $this->getDataGenerator()->create_course(['category' => $coursecategory->id]);
  55  
  56          $admin = get_admin();
  57          // Create a user (not enrolled in a course).
  58          $user = $this->getDataGenerator()->create_user();
  59  
  60          // Add some content to the content bank.
  61          $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
  62          // Add some content bank files in the system context.
  63          $filepath = $CFG->dirroot . '/h5p/tests/fixtures/filltheblanks.h5p';
  64          $contentbankcontents = $generator->generate_contentbank_data('contenttype_h5p', 3, $admin->id,
  65              $systemcontext, true, $filepath);
  66  
  67          // Log in as admin.
  68          $this->setUser($admin);
  69          // Get the content bank nodes displayed to the admin in the system context.
  70          $browser = new \repository_contentbank\browser\contentbank_browser_context_system($systemcontext);
  71          $repositorycontentnodes = $browser->get_content();
  72          // All content nodes should be available to the admin user.
  73          // There should be a total of 5 nodes, 3 file nodes representing the existing content bank files in the
  74          // system context and 2 folder nodes representing the default course category and 'Category'.
  75          $this->assertCount(5, $repositorycontentnodes);
  76          $contextfolders = [
  77              [
  78                  'name' => get_string('defaultcategoryname'),
  79                  'contextid' => $defaultcatcontext->id
  80              ],
  81              [
  82                  'name' => 'Category',
  83                  'contextid' => $coursecatcontext->id
  84              ]
  85          ];
  86          $expected = $this->generate_expected_content($contextfolders, $contentbankcontents);
  87          $this->assertEqualsCanonicalizing($expected, $repositorycontentnodes);
  88  
  89          // Log in as a user.
  90          $this->setUser($user);
  91          // Get the content bank nodes displayed to an authenticated user in the system context.
  92          $browser = new \repository_contentbank\browser\contentbank_browser_context_system($systemcontext);
  93          $repositorycontentnodes = $browser->get_content();
  94          // There should be 3 nodes representing the existing content bank files in the system context.
  95          // The course category context folder node should be ignored as the user does not have an access to
  96          // the content of the category's courses.
  97          $this->assertCount(3, $repositorycontentnodes);
  98          $expected = $this->generate_expected_content([], $contentbankcontents);
  99          $this->assertEqualsCanonicalizing($expected, $repositorycontentnodes);
 100  
 101          // Enrol the user as an editing teacher in the course.
 102          $editingteacherrole = $DB->get_field('role', 'id', ['shortname' => 'editingteacher']);
 103          $this->getDataGenerator()->enrol_user($user->id, $course->id, $editingteacherrole);
 104  
 105           // Get the content bank nodes displayed to the editing teacher in the system context.
 106          $browser = new \repository_contentbank\browser\contentbank_browser_context_system($systemcontext);
 107          $repositorycontentnodes = $browser->get_content();
 108          // All content nodes should now be available to the editing teacher.
 109          // There should be a total of 4 nodes, 3 file nodes representing the existing content bank files in the
 110          // system context and 1 folder node representing the course category 'Category' (The editing teacher is now
 111          // enrolled in a course from the category).
 112          $this->assertCount(4, $repositorycontentnodes);
 113          $contextfolders = [
 114              [
 115                  'name' => 'Category',
 116                  'contextid' => $coursecatcontext->id
 117              ]
 118          ];
 119          $expected = $this->generate_expected_content($contextfolders, $contentbankcontents);
 120          $this->assertEqualsCanonicalizing($expected, $repositorycontentnodes);
 121      }
 122  
 123      /**
 124       * Test get_content() in the system context with users that do not have a capability to access/view content bank
 125       * content within the system context. By default, every non-authenticated user should not be able to access/view
 126       * the content in the system context.
 127       */
 128      public function test_get_content_system_context_user_missing_capabilities() {
 129          $this->resetAfterTest(true);
 130  
 131          $systemcontext = \context_system::instance();
 132  
 133          $admin = get_admin();
 134          // Add some content to the content bank.
 135          $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
 136          // Add some content bank files in the system context.
 137  
 138          $generator->generate_contentbank_data('contenttype_h5p', 3, $admin->id, $systemcontext, true);
 139          // Log out.
 140          $this->setUser();
 141          // Get the content bank nodes displayed to a non-authenticated user in the system context.
 142          $browser = new \repository_contentbank\browser\contentbank_browser_context_system($systemcontext);
 143          $repositorycontents = $browser->get_content();
 144          // Content nodes should not be available to the non-authenticated user in the system context.
 145          $this->assertCount(0, $repositorycontents);
 146      }
 147  
 148      /**
 149       * Test get_content() in the course category context with users that have capability to access/view content
 150       * bank content within the course category context. By default, every authenticated user that has access to
 151       * any category course should be able to access/view the content in the course category context.
 152       */
 153      public function test_get_content_course_category_context_user_has_capabilities() {
 154          global $CFG;
 155  
 156          $this->resetAfterTest(true);
 157  
 158          // Create a course category.
 159          $category = $this->getDataGenerator()->create_category(['name' => 'Category']);
 160          $coursecatcontext = \context_coursecat::instance($category->id);
 161          // Create course1.
 162          $course1 = $this->getDataGenerator()->create_course(['fullname' => 'Course1', 'category' => $category->id]);
 163          $course1context = \context_course::instance($course1->id);
 164          // Create course2.
 165          $course2 = $this->getDataGenerator()->create_course(['fullname' => 'Course2', 'category' => $category->id]);
 166          $course2context = \context_course::instance($course2->id);
 167  
 168          $admin = get_admin();
 169          // Create editing teacher enrolled in course1.
 170          $editingteacher = $this->getDataGenerator()->create_and_enrol($course1, 'editingteacher');
 171  
 172          // Add some content to the content bank.
 173          $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
 174          // Add some content bank files in the course category context.
 175          $filepath = $CFG->dirroot . '/h5p/tests/fixtures/filltheblanks.h5p';
 176          $contentbankcontents = $generator->generate_contentbank_data('contenttype_h5p', 3, $admin->id,
 177              $coursecatcontext, true, $filepath);
 178  
 179          $this->setUser($admin);
 180          // Get the content bank nodes displayed to the admin in the course category context.
 181          $browser = new \repository_contentbank\browser\contentbank_browser_context_coursecat($coursecatcontext);
 182          $repositorycontents = $browser->get_content();
 183          // All content nodes should be available to the admin user.
 184          // There should be a total of 5 nodes, 3 file nodes representing the existing content bank files in the
 185          // course category context and 2 folder nodes representing the courses 'Course1' and 'Course2'.
 186          $this->assertCount(5, $repositorycontents);
 187          $contextfolders = [
 188              [
 189                  'name' => 'Course1',
 190                  'contextid' => $course1context->id
 191              ],
 192              [
 193                  'name' => 'Course2',
 194                  'contextid' => $course2context->id
 195              ]
 196          ];
 197          $expected = $this->generate_expected_content($contextfolders, $contentbankcontents);
 198          $this->assertEqualsCanonicalizing($expected, $repositorycontents);
 199  
 200          // Log in as an editing teacher enrolled in a child course.
 201          $this->setUser($editingteacher);
 202          // Get the content bank nodes displayed to the editing teacher in the course category context.
 203          $browser = new \repository_contentbank\browser\contentbank_browser_context_coursecat($coursecatcontext);
 204          $repositorycontents = $browser->get_content();
 205          // There should be a total of 4 nodes, 3 file nodes representing the existing content bank files in the
 206          // course category context and 1 folder node representing the course 'Course1' (The editing teacher is only
 207          // enrolled in course1).
 208          $this->assertCount(4, $repositorycontents);
 209          $contextfolders = [
 210              [
 211                  'name' => 'Course1',
 212                  'contextid' => $course1context->id
 213              ]
 214          ];
 215          $expected = $this->generate_expected_content($contextfolders, $contentbankcontents);
 216          $this->assertEqualsCanonicalizing($expected, $repositorycontents);
 217      }
 218  
 219      /**
 220       * Test get_content() in the course category context with users that do not have capability to access/view content
 221       * bank content within the course category context. By default, every non-authenticated user or authenticated users
 222       * that cannot access/view course content from the course category should not be able to access/view the
 223       * content in the course category context.
 224       */
 225      public function test_get_content_course_category_context_user_missing_capabilities() {
 226          $this->resetAfterTest(true);
 227  
 228           // Create a course category 'Category'.
 229          $category = $this->getDataGenerator()->create_category(['name' => 'Category']);
 230          // Create course1 in 'Category'.
 231          $course1 = $this->getDataGenerator()->create_course(['fullname' => 'Course1', 'category' => $category->id]);
 232          // Create course2 in default category by default.
 233          $course2 = $this->getDataGenerator()->create_course(['fullname' => 'Course2']);
 234          // Create a teacher enrolled in course1.
 235          $teacher = $this->getDataGenerator()->create_and_enrol($course1, 'teacher');
 236          // Create an editing teacher enrolled in course2.
 237          $editingteacher = $this->getDataGenerator()->create_and_enrol($course2, 'editingteacher');
 238  
 239          $admin = get_admin();
 240          // Add some content to the content bank.
 241          $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
 242          // Add some content bank files in the 'Category' context.
 243          $coursecatcontext = \context_coursecat::instance($category->id);
 244          $generator->generate_contentbank_data('contenttype_h5p', 3, $admin->id,
 245              $coursecatcontext, true);
 246  
 247          // Log in as a non-editing teacher.
 248          $this->setUser($teacher);
 249          // Get the content bank nodes displayed to a non-editing teacher in the 'Category' context.
 250          $browser = new \repository_contentbank\browser\contentbank_browser_context_coursecat($coursecatcontext);
 251          $repositorycontents = $browser->get_content();
 252          // Content nodes should not be available to a non-editing teacher in the 'Category' context.
 253          $this->assertCount(0, $repositorycontents);
 254  
 255          // Log in as an editing teacher.
 256          $this->setUser($editingteacher);
 257          // Get the content bank nodes displayed to a an editing teacher in the 'Category' context.
 258          $browser = new \repository_contentbank\browser\contentbank_browser_context_coursecat($coursecatcontext);
 259          $repositorycontents = $browser->get_content();
 260          // Content nodes should not be available to an editing teacher in the 'Category' context.
 261          $this->assertCount(0, $repositorycontents);
 262  
 263          // Log out.
 264          $this->setUser();
 265          // Get the content bank nodes displayed to a non-authenticated user in the course category context.
 266          $browser = new \repository_contentbank\browser\contentbank_browser_context_coursecat($coursecatcontext);
 267          $repositorycontents = $browser->get_content();
 268          // Content nodes should not be available to the non-authenticated user in the course category context.
 269          $this->assertCount(0, $repositorycontents);
 270      }
 271  
 272      /**
 273       * Test get_content() in the course context with users that have capability to access/view content
 274       * bank content within the course context. By default, admin, managers, course creators, editing teachers enrolled
 275       * in the course should be able to access/view the content.
 276       */
 277      public function test_get_content_course_context_user_has_capabilities() {
 278          global $CFG;
 279  
 280          $this->resetAfterTest(true);
 281  
 282          // Create course1.
 283          $course = $this->getDataGenerator()->create_course(['fullname' => 'Course']);
 284          $coursecontext = \context_course::instance($course->id);
 285  
 286          $admin = get_admin();
 287          // Create editing teacher enrolled in course.
 288          $editingteacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
 289  
 290          // Add some content to the content bank.
 291          $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
 292          // Add some content bank files in the course context.
 293          $filepath = $CFG->dirroot . '/h5p/tests/fixtures/filltheblanks.h5p';
 294          $contentbankcontents = $generator->generate_contentbank_data('contenttype_h5p', 3, $admin->id,
 295              $coursecontext, true, $filepath);
 296  
 297          $this->setUser($admin);
 298          // Get the content bank nodes displayed to the admin in the course context.
 299          $browser = new \repository_contentbank\browser\contentbank_browser_context_course($coursecontext);
 300          $repositorycontents = $browser->get_content();
 301          // All content nodes should be available to the admin user.
 302          // There should be 3 file nodes representing the existing content bank files in the
 303          // course context.
 304          $this->assertCount(3, $repositorycontents);
 305          $expected = $this->generate_expected_content([], $contentbankcontents);
 306          $this->assertEqualsCanonicalizing($expected, $repositorycontents);
 307  
 308          // Log in as an editing teacher.
 309          $this->setUser($editingteacher);
 310          // All content nodes should also be available to the editing teacher.
 311          // Get the content bank nodes displayed to the editing teacher in the course context.
 312          $browser = new \repository_contentbank\browser\contentbank_browser_context_course($coursecontext);
 313          $repositorycontents = $browser->get_content();
 314          // There should be 3 file nodes representing the existing content bank files in the
 315          // course context.
 316          $this->assertCount(3, $repositorycontents);
 317          $expected = $this->generate_expected_content([], $contentbankcontents);
 318          $this->assertEqualsCanonicalizing($expected, $repositorycontents);
 319      }
 320  
 321      /**
 322       * Test get_content() in the course context with users that do not have capability to access/view content
 323       * bank content within the course context. By default, every user which is not an admin, manager, course creator,
 324       * editing teacher enrolled in the course should not be able to access/view the content.
 325       */
 326      public function test_get_content_course_context_user_missing_capabilities() {
 327          $this->resetAfterTest(true);
 328  
 329          // Create course1.
 330          $course1 = $this->getDataGenerator()->create_course(['fullname' => 'Course1']);
 331          $course1context = \context_course::instance($course1->id);
 332          // Create course2.
 333          $course2 = $this->getDataGenerator()->create_course(['fullname' => 'Course2']);
 334          $course2context = \context_course::instance($course2->id);
 335  
 336          $admin = get_admin();
 337          // Create non-editing teacher enrolled in course1.
 338          $teacher = $this->getDataGenerator()->create_and_enrol($course1, 'teacher');
 339           // Create editing teacher enrolled in course1.
 340          $editingteacher = $this->getDataGenerator()->create_and_enrol($course1, 'editingteacher');
 341  
 342          // Add some content to the content bank.
 343          $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
 344          // Add some content bank files in the course1 context.
 345          $generator->generate_contentbank_data('contenttype_h5p', 2, $admin->id,
 346              $course1context, true);
 347          // Add some content bank files in the course2 context.
 348          $generator->generate_contentbank_data('contenttype_h5p', 3, $admin->id,
 349              $course2context, true);
 350  
 351          // Log in as a non-editing teacher.
 352          $this->setUser($teacher);
 353          // Get the content bank nodes displayed to the non-editing teacher in the course1 context.
 354          $browser = new \repository_contentbank\browser\contentbank_browser_context_course($course1context);
 355          $repositorycontents = $browser->get_content();
 356          // Content nodes should not be available to the teacher in the course1 context.
 357          $this->assertCount(0, $repositorycontents);
 358  
 359          // Log in as editing teacher.
 360          $this->setUser($editingteacher);
 361          // Get the content bank nodes displayed to the editing teacher in the course2 context.
 362          $browser = new \repository_contentbank\browser\contentbank_browser_context_course($course2context);
 363          $repositorycontents = $browser->get_content();
 364          // Content nodes should not be available to the teacher in the course2 context. The editing teacher is not
 365          // enrolled in this course.
 366          $this->assertCount(0, $repositorycontents);
 367      }
 368  
 369      /**
 370       * Test get_navigation() in the system context.
 371       */
 372      public function test_get_navigation_system_context() {
 373          $this->resetAfterTest(true);
 374  
 375          $systemcontext = \context_system::instance();
 376  
 377          $browser = new \repository_contentbank\browser\contentbank_browser_context_system($systemcontext);
 378          $navigation = $browser->get_navigation();
 379          // The navigation array should contain only 1 element, representing the system navigation node.
 380          $this->assertCount(1, $navigation);
 381          $expected = [
 382              \repository_contentbank\helper::create_navigation_node($systemcontext)
 383          ];
 384          $this->assertEquals($expected, $navigation);
 385      }
 386  
 387      /**
 388       * Test get_navigation() in the course category context.
 389       */
 390      public function test_get_navigation_course_category_context() {
 391          $this->resetAfterTest(true);
 392  
 393          $systemcontext = \context_system::instance();
 394          // Create a course category.
 395          $category = $this->getDataGenerator()->create_category(['name' => 'category']);
 396          $categorycontext = \context_coursecat::instance($category->id);
 397          // Create a course subcategory.
 398          $subcategory = $this->getDataGenerator()->create_category(['name' => 'subcategory', 'parent' => $category->id]);
 399          $subcategorytcontext = \context_coursecat::instance($subcategory->id);
 400  
 401          // Get navigation nodes in the category context.
 402          $browser = new \repository_contentbank\browser\contentbank_browser_context_coursecat($categorycontext);
 403          $navigation = $browser->get_navigation();
 404          // The navigation array should contain 2 elements, representing the system and course category
 405          // navigation nodes.
 406          $this->assertCount(2, $navigation);
 407          $expected = [
 408              \repository_contentbank\helper::create_navigation_node($systemcontext),
 409              \repository_contentbank\helper::create_navigation_node($categorycontext)
 410          ];
 411          $this->assertEquals($expected, $navigation);
 412  
 413          // Get navigation nodes in the subcategory context.
 414          $browser = new \repository_contentbank\browser\contentbank_browser_context_coursecat($subcategorytcontext);
 415          $navigation = $browser->get_navigation();
 416          // The navigation array should contain 3 elements, representing the system, category and subcategory
 417          // navigation nodes.
 418          $this->assertCount(3, $navigation);
 419          $expected = [
 420              \repository_contentbank\helper::create_navigation_node($systemcontext),
 421              \repository_contentbank\helper::create_navigation_node($categorycontext),
 422              \repository_contentbank\helper::create_navigation_node($subcategorytcontext)
 423          ];
 424          $this->assertEquals($expected, $navigation);
 425      }
 426  
 427      /**
 428       * Test get_navigation() in the course context.
 429       */
 430      public function test_get_navigation_course_context() {
 431          $this->resetAfterTest(true);
 432  
 433          $systemcontext = \context_system::instance();
 434          // Create a category.
 435          $category = $this->getDataGenerator()->create_category(['name' => 'category']);
 436          $categorycontext = \context_coursecat::instance($category->id);
 437          // Create a subcategory.
 438          $subcategory = $this->getDataGenerator()->create_category(['name' => 'category', 'parent' => $category->id]);
 439          $subcategorycontext = \context_coursecat::instance($subcategory->id);
 440          // Create a course in category.
 441          $categorycourse = $this->getDataGenerator()->create_course(['category' => $category->id]);
 442          $categorycoursecontext = \context_course::instance($categorycourse->id);
 443          // Create a course in subcategory.
 444          $subcategorycourse = $this->getDataGenerator()->create_course(['category' => $subcategory->id]);
 445          $subcategorycoursecontext = \context_course::instance($subcategorycourse->id);
 446  
 447          // Get navigation nodes in the category course context.
 448          $browser = new \repository_contentbank\browser\contentbank_browser_context_course($categorycoursecontext);
 449          $navigation = $browser->get_navigation();
 450          // The navigation array should contain 3 elements, representing the system, category and course
 451          // navigation nodes.
 452          $this->assertCount(3, $navigation);
 453          $expected = [
 454              \repository_contentbank\helper::create_navigation_node($systemcontext),
 455              \repository_contentbank\helper::create_navigation_node($categorycontext),
 456              \repository_contentbank\helper::create_navigation_node($categorycoursecontext)
 457          ];
 458          $this->assertEquals($expected, $navigation);
 459  
 460          // Get navigation nodes in the subcategory course context.
 461          $browser = new \repository_contentbank\browser\contentbank_browser_context_course($subcategorycoursecontext);
 462          $navigation = $browser->get_navigation();
 463          // The navigation array should contain 4 elements, representing the system, category, subcategory and
 464          // subcategory course navigation nodes.
 465          $this->assertCount(4, $navigation);
 466          $expected = [
 467              \repository_contentbank\helper::create_navigation_node($systemcontext),
 468              \repository_contentbank\helper::create_navigation_node($categorycontext),
 469              \repository_contentbank\helper::create_navigation_node($subcategorycontext),
 470              \repository_contentbank\helper::create_navigation_node($subcategorycoursecontext)
 471          ];
 472          $this->assertEquals($expected, $navigation);
 473      }
 474  
 475      /**
 476       * Generate the expected array of content bank nodes.
 477       *
 478       * @param array $contextfolders The array containing the expected folder nodes
 479       * @param array $contentbankcontents The array containing the expected contents
 480       * @return array[] The expected array of content bank nodes
 481       */
 482      private function generate_expected_content(array $contextfolders = [], array $contentbankcontents = []): array {
 483  
 484          $expected = [];
 485          if (!empty($contextfolders)) {
 486              foreach ($contextfolders as $contextfolder) {
 487                  $expected[] = \repository_contentbank\helper::create_context_folder_node($contextfolder['name'],
 488                      base64_encode(json_encode(['contextid' => $contextfolder['contextid']])));
 489              }
 490          }
 491          if (!empty($contentbankcontents)) {
 492              foreach ($contentbankcontents as $content) {
 493                  $expected[] = \repository_contentbank\helper::create_contentbank_content_node($content);
 494              }
 495          }
 496          return $expected;
 497      }
 498  }