Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]

   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  /**
  18   * Contains the tests for the content_item_service class.
  19   *
  20   * @package    core
  21   * @subpackage course
  22   * @copyright  2020 Jake Dallimore <jrhdallimore@gmail.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  namespace core_course;
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  use core_course\local\service\content_item_service;
  30  use core_course\local\repository\content_item_readonly_repository;
  31  
  32  /**
  33   * The tests for the content_item_service class.
  34   *
  35   * @copyright  2020 Jake Dallimore <jrhdallimore@gmail.com>
  36   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37   */
  38  class services_content_item_service_test extends \advanced_testcase {
  39  
  40      /**
  41       * Test confirming that content items are returned by the service.
  42       */
  43      public function test_get_content_items_for_user_in_course_basic() {
  44          $this->resetAfterTest();
  45  
  46          // Create a user in a course.
  47          $course = $this->getDataGenerator()->create_course();
  48          $user = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
  49  
  50          $cis = new content_item_service(new content_item_readonly_repository());
  51          $contentitems = $cis->get_content_items_for_user_in_course($user, $course);
  52  
  53          foreach ($contentitems as $key => $contentitem) {
  54              $this->assertObjectHasAttribute('id', $contentitem);
  55              $this->assertObjectHasAttribute('name', $contentitem);
  56              $this->assertObjectHasAttribute('title', $contentitem);
  57              $this->assertObjectHasAttribute('link', $contentitem);
  58              $this->assertObjectHasAttribute('icon', $contentitem);
  59              $this->assertObjectHasAttribute('help', $contentitem);
  60              $this->assertObjectHasAttribute('archetype', $contentitem);
  61              $this->assertObjectHasAttribute('componentname', $contentitem);
  62          }
  63      }
  64  
  65      /**
  66       * Test confirming that access control is performed when asking the service to return content items for a user in a course.
  67       */
  68      public function test_get_content_items_for_user_in_course_permissions() {
  69          $this->resetAfterTest();
  70          global $DB;
  71  
  72          // Create a user in a course.
  73          $course = $this->getDataGenerator()->create_course();
  74          $user = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
  75  
  76          // No cap override, so assign should be returned.
  77          $cis = new content_item_service(new content_item_readonly_repository());
  78          $contentitems = $cis->get_content_items_for_user_in_course($user, $course);
  79          $this->assertContains('assign', array_column($contentitems, 'name'));
  80  
  81          // Override the capability 'mod/assign:addinstance' for the 'editing teacher' role.
  82          $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
  83          assign_capability('mod/assign:addinstance', CAP_PROHIBIT, $teacherrole->id, \context_course::instance($course->id));
  84  
  85          $contentitems = $cis->get_content_items_for_user_in_course($user, $course);
  86          $this->assertArrayNotHasKey('assign', $contentitems);
  87      }
  88  
  89      /**
  90       * Test confirming that params can be added to the content item's link.
  91       */
  92      public function test_get_content_item_for_user_in_course_link_params() {
  93          $this->resetAfterTest();
  94  
  95          // Create a user in a course.
  96          $course = $this->getDataGenerator()->create_course();
  97          $user = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
  98  
  99          $cis = new content_item_service(new content_item_readonly_repository());
 100          $contentitems = $cis->get_content_items_for_user_in_course($user, $course, ['sr' => 7]);
 101  
 102          foreach ($contentitems as $item) {
 103              $this->assertStringContainsString('sr=7', $item->link);
 104          }
 105      }
 106  
 107      /**
 108       * Test confirming that all content items can be fetched irrespective of permissions.
 109       */
 110      public function test_get_all_content_items() {
 111          $this->resetAfterTest();
 112          global $DB;
 113  
 114          // Create a user in a course and set up a site-level LTI tool, configured to display in the activity chooser.
 115          $course = $this->getDataGenerator()->create_course();
 116          $user = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
 117          /** @var \mod_lti_generator $ltigenerator */
 118          $ltigenerator = $this->getDataGenerator()->get_plugin_generator('mod_lti');
 119          $ltigenerator->create_tool_types([
 120              'name' => 'site tool',
 121              'baseurl' => 'http://example.com',
 122              'coursevisible' => LTI_COURSEVISIBLE_ACTIVITYCHOOSER,
 123              'state' => LTI_TOOL_STATE_CONFIGURED
 124          ]);
 125          $cis = new content_item_service(new content_item_readonly_repository());
 126          $this->setUser($user); // This is needed since the underlying lti code needs the global user despite the api accepting user.
 127  
 128          // The call to get_all_content_items() should return the same items as for the course,
 129          // given the user is an editing teacher and can add preconfigured lti instances.
 130          $allcontentitems = $cis->get_all_content_items($user);
 131          $coursecontentitems = $cis->get_content_items_for_user_in_course($user, $course);
 132          $this->assertContains('site tool', array_column($coursecontentitems, 'title'));
 133          $this->assertContains('site tool', array_column($allcontentitems, 'title'));
 134  
 135          // Now removing the cap 'mod/lti:addpreconfiguredinstance', restricting those items returned by the course-specific method.
 136          $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
 137          assign_capability('mod/lti:addpreconfiguredinstance', CAP_PROHIBIT, $teacherrole->id,
 138              \core\context\course::instance($course->id));
 139  
 140          // Verify that all items, including the tool, are still returned by the get_all_content_items() call.
 141          $allcontentitems = $cis->get_all_content_items($user);
 142          $coursecontentitems = $cis->get_content_items_for_user_in_course($user, $course);
 143          $this->assertNotContains('site tool', array_column($coursecontentitems, 'title'));
 144          $this->assertContains('site tool', array_column($allcontentitems, 'title'));
 145      }
 146  
 147      /**
 148       * Test confirming that content items which title match a certain pattern can be fetched irrespective of permissions.
 149       */
 150      public function test_get_content_items_by_name_pattern() {
 151          $this->resetAfterTest();
 152  
 153          // Create a user in a course.
 154          $course = $this->getDataGenerator()->create_course();
 155          $user = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
 156  
 157          // Pattern that does exist.
 158          $pattern1 = "assign";
 159          // Pattern that does not exist.
 160          $pattern2 = "random string";
 161  
 162          $cis = new content_item_service(new content_item_readonly_repository());
 163          $matchingcontentitems1 = $cis->get_content_items_by_name_pattern($user, $pattern1);
 164          $matchingcontentitems2 = $cis->get_content_items_by_name_pattern($user, $pattern2);
 165  
 166          // The pattern "assign" should return at least 1 content item (ex. "Assignment").
 167          $this->assertGreaterThanOrEqual(1, count($matchingcontentitems1));
 168          // Verify the pattern "assign" can be found in the title of each returned content item.
 169          foreach ($matchingcontentitems1 as $contentitem) {
 170              $this->assertEquals(1, preg_match("/$pattern1/i", $contentitem->title));
 171          }
 172          // The pattern "random string" should not return any content items.
 173          $this->assertEmpty($matchingcontentitems2);
 174      }
 175  
 176      /**
 177       * Test confirming that a content item can be added to a user's favourites.
 178       */
 179      public function test_add_to_user_favourites() {
 180          $this->resetAfterTest();
 181  
 182          // Create a user in a course.
 183          $course = $this->getDataGenerator()->create_course();
 184          $user = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
 185          $cis = new content_item_service(new content_item_readonly_repository());
 186  
 187          // Grab a the assign content item, which we'll favourite for the user.
 188          $items = $cis->get_all_content_items($user);
 189          $assign = $items[array_search('assign', array_column($items, 'name'))];
 190          $contentitem = $cis->add_to_user_favourites($user, 'mod_assign', $assign->id);
 191  
 192          // Verify the exported result is marked as a favourite.
 193          $this->assertEquals('assign', $contentitem->name);
 194          $this->assertTrue($contentitem->favourite);
 195  
 196          // Verify the item is marked as a favourite when returned from the other service methods.
 197          $allitems = $cis->get_all_content_items($user);
 198          $allitemsassign = $allitems[array_search('assign', array_column($allitems, 'name'))];
 199  
 200          $courseitems = $cis->get_content_items_for_user_in_course($user, $course);
 201          $courseitemsassign = $courseitems[array_search('assign', array_column($courseitems, 'name'))];
 202          $this->assertTrue($allitemsassign->favourite);
 203          $this->assertTrue($courseitemsassign->favourite);
 204      }
 205  
 206      /**
 207       * Test verifying that content items can be removed from a user's favourites.
 208       */
 209      public function test_remove_from_user_favourites() {
 210          $this->resetAfterTest();
 211  
 212          // Create a user in a course.
 213          $course = $this->getDataGenerator()->create_course();
 214          $user = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
 215          $cis = new content_item_service(new content_item_readonly_repository());
 216  
 217          // Grab a the assign content item, which we'll favourite for the user.
 218          $items = $cis->get_all_content_items($user);
 219          $assign = $items[array_search('assign', array_column($items, 'name'))];
 220          $cis->add_to_user_favourites($user, 'mod_assign', $assign->id);
 221  
 222          // Now, remove the favourite, and verify it.
 223          $contentitem = $cis->remove_from_user_favourites($user, 'mod_assign', $assign->id);
 224  
 225          // Verify the exported result is not marked as a favourite.
 226          $this->assertEquals('assign', $contentitem->name);
 227          $this->assertFalse($contentitem->favourite);
 228  
 229          // Verify the item is not marked as a favourite when returned from the other service methods.
 230          $allitems = $cis->get_all_content_items($user);
 231          $allitemsassign = $allitems[array_search('assign', array_column($allitems, 'name'))];
 232          $courseitems = $cis->get_content_items_for_user_in_course($user, $course);
 233          $courseitemsassign = $courseitems[array_search('assign', array_column($courseitems, 'name'))];
 234          $this->assertFalse($allitemsassign->favourite);
 235          $this->assertFalse($courseitemsassign->favourite);
 236      }
 237  
 238      /**
 239       * Test that toggling a recommendation works as anticipated.
 240       */
 241      public function test_toggle_recommendation() {
 242          $this->resetAfterTest();
 243  
 244          // Create a user in a course.
 245          $course = $this->getDataGenerator()->create_course();
 246          $user = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
 247          $cis = new content_item_service(new content_item_readonly_repository());
 248  
 249          // Grab a the assign content item, which we'll recommend for the user.
 250          $items = $cis->get_all_content_items($user);
 251          $assign = $items[array_search('assign', array_column($items, 'name'))];
 252          $result = $cis->toggle_recommendation($assign->componentname, $assign->id);
 253          $this->assertTrue($result);
 254  
 255          $courseitems = $cis->get_all_content_items($user);
 256          $courseitemsassign = $courseitems[array_search('assign', array_column($courseitems, 'name'))];
 257          $this->assertTrue($courseitemsassign->recommended);
 258  
 259          // Let's toggle the recommendation off.
 260          $result = $cis->toggle_recommendation($assign->componentname, $assign->id);
 261          $this->assertFalse($result);
 262  
 263          $courseitems = $cis->get_all_content_items($user);
 264          $courseitemsassign = $courseitems[array_search('assign', array_column($courseitems, 'name'))];
 265          $this->assertFalse($courseitemsassign->recommended);
 266      }
 267  }