MDL-58768 coursecat: coursecat::get to accept a $user parameter
authorShamim Rezaie <shamim@moodle.com>
Wed, 4 Apr 2018 14:17:40 +0000 (00:17 +1000)
committerShamim Rezaie <shamim@moodle.com>
Fri, 27 Jul 2018 21:51:32 +0000 (07:51 +1000)
lib/coursecatlib.php
lib/tests/coursecatlib_test.php
lib/upgrade.txt

index 5ad20b7..8833387 100644 (file)
@@ -212,7 +212,7 @@ class coursecat implements renderable, cacheable_object, IteratorAggregate {
     /**
      * Returns coursecat object for requested category
      *
-     * If category is not visible to user it is treated as non existing
+     * If category is not visible to the given user, it is treated as non existing
      * unless $alwaysreturnhidden is set to true
      *
      * If id is 0, the pseudo object for root category is returned (convenient
@@ -226,10 +226,11 @@ class coursecat implements renderable, cacheable_object, IteratorAggregate {
      *     returned even if this category is not visible to the current user
      *     (category is hidden and user does not have
      *     'moodle/category:viewhiddencategories' capability). Use with care!
+     * @param int|stdClass $user The user id or object. By default (null) checks the visibility to the current user.
      * @return null|coursecat
      * @throws moodle_exception
      */
-    public static function get($id, $strictness = MUST_EXIST, $alwaysreturnhidden = false) {
+    public static function get($id, $strictness = MUST_EXIST, $alwaysreturnhidden = false, $user = null) {
         if (!$id) {
             if (!isset(self::$coursecat0)) {
                 $record = new stdClass();
@@ -251,7 +252,7 @@ class coursecat implements renderable, cacheable_object, IteratorAggregate {
                 $coursecatrecordcache->set($id, $coursecat);
             }
         }
-        if ($coursecat && ($alwaysreturnhidden || $coursecat->is_uservisible())) {
+        if ($coursecat && ($alwaysreturnhidden || $coursecat->is_uservisible($user))) {
             return $coursecat;
         } else {
             if ($strictness == MUST_EXIST) {
@@ -580,17 +581,18 @@ class coursecat implements renderable, cacheable_object, IteratorAggregate {
     }
 
     /**
-     * Checks if this course category is visible to current user
+     * Checks if this course category is visible to a user.
      *
      * Please note that methods coursecat::get (without 3rd argumet),
      * coursecat::get_children(), etc. return only visible categories so it is
      * usually not needed to call this function outside of this class
      *
+     * @param int|stdClass $user The user id or object. By default (null) checks the visibility to the current user.
      * @return bool
      */
-    public function is_uservisible() {
+    public function is_uservisible($user = null) {
         return !$this->id || $this->visible ||
-                has_capability('moodle/category:viewhiddencategories', $this->get_context());
+                has_capability('moodle/category:viewhiddencategories', $this->get_context(), $user);
     }
 
     /**
index 54b1099..1b7e280 100644 (file)
@@ -797,6 +797,83 @@ class core_coursecatlib_testcase extends advanced_testcase {
         $this->assertEquals("{$cat1name} / {$cat2name} / {$cat4name}", $category4->get_nested_name(false));
     }
 
+    public function test_coursecat_is_uservisible() {
+        global $USER;
+
+        // Create category 1 as visible.
+        $category1 = coursecat::create(array('name' => 'Cat1', 'visible' => 1));
+        // Create category 2 as hidden.
+        $category2 = coursecat::create(array('name' => 'Cat2', 'visible' => 0));
+
+        $this->assertTrue($category1->is_uservisible());
+        $this->assertFalse($category2->is_uservisible());
+
+        $this->assign_capability('moodle/category:viewhiddencategories');
+
+        $this->assertTrue($category1->is_uservisible());
+        $this->assertTrue($category2->is_uservisible());
+
+        // First, store current user's id, then login as another user.
+        $userid = $USER->id;
+        $this->setUser($this->getDataGenerator()->create_user());
+
+        // User $user should still have the moodle/category:viewhiddencategories capability.
+        $this->assertTrue($category1->is_uservisible($userid));
+        $this->assertTrue($category2->is_uservisible($userid));
+
+        $this->assign_capability('moodle/category:viewhiddencategories', CAP_INHERIT);
+
+        $this->assertTrue($category1->is_uservisible());
+        $this->assertFalse($category2->is_uservisible());
+    }
+
+    public function test_current_user_coursecat_get() {
+        $this->assign_capability('moodle/category:viewhiddencategories');
+
+        // Create category 1 as visible.
+        $category1 = coursecat::create(array('name' => 'Cat1', 'visible' => 1));
+        // Create category 2 as hidden.
+        $category2 = coursecat::create(array('name' => 'Cat2', 'visible' => 0));
+
+        $this->assertEquals($category1->id, coursecat::get($category1->id)->id);
+        $this->assertEquals($category2->id, coursecat::get($category2->id)->id);
+
+        // Login as another user to test coursecat::get.
+        $this->setUser($this->getDataGenerator()->create_user());
+        $this->assertEquals($category1->id, coursecat::get($category1->id)->id);
+
+        // Expecting to get an exception as this new user does not have the moodle/category:viewhiddencategories capability.
+        $this->expectException('moodle_exception');
+        $this->expectExceptionMessage('unknowncategory');
+        coursecat::get($category2->id);
+    }
+
+    public function test_another_user_coursecat_get() {
+        global $USER;
+
+        $this->assign_capability('moodle/category:viewhiddencategories');
+
+        // Create category 1 as visible.
+        $category1 = coursecat::create(array('name' => 'Cat1', 'visible' => 1));
+        // Create category 2 as hidden.
+        $category2 = coursecat::create(array('name' => 'Cat2', 'visible' => 0));
+
+        // First, store current user's object, then login as another user.
+        $user1 = $USER;
+        $user2 = $this->getDataGenerator()->create_user();
+        $this->setUser($user2);
+
+        $this->assertEquals($category1->id, coursecat::get($category1->id, MUST_EXIST, false, $user1)->id);
+        $this->assertEquals($category2->id, coursecat::get($category2->id, MUST_EXIST, false, $user1)->id);
+
+        $this->setUser($user1);
+
+        $this->assertEquals($category1->id, coursecat::get($category1->id, MUST_EXIST, false, $user2)->id);
+        $this->expectException('moodle_exception');
+        $this->expectExceptionMessage('unknowncategory');
+        coursecat::get($category2->id, MUST_EXIST, false, $user2);
+    }
+
     /**
      * Creates a draft area for current user and fills it with fake files
      *
index f2e8d0b..9cf3386 100644 (file)
@@ -23,6 +23,9 @@ information provided here is intended especially for developers.
     - I follow "<link_string>"" in the open menu
 * Removed the lib/password_compat/lib/password.php file.
 
+* coursecat::get() now has optional $user parameter.
+* coursecat::is_uservisible() now has optional $user parameter.
+
 === 3.5 ===
 
 * There is a new privacy API that every subsystem and plugin has to implement so that the site can become GDPR