MDL-43130 access: fix user counting when retrieving assignable roles.
authorPaul Holden <pholden@greenhead.ac.uk>
Fri, 8 Mar 2019 12:32:24 +0000 (12:32 +0000)
committerPaul Holden <pholden@greenhead.ac.uk>
Fri, 8 Mar 2019 12:32:24 +0000 (12:32 +0000)
Previously users assigned the same role in a context via multiple
components would be counted multiple times.

lib/accesslib.php
lib/tests/accesslib_test.php

index ad1960b..238feaf 100644 (file)
@@ -3043,7 +3043,7 @@ function get_assignable_roles(context $context, $rolenamedisplay = ROLENAME_ALIA
     $extrafields = '';
 
     if ($withusercounts) {
-        $extrafields = ', (SELECT count(u.id)
+        $extrafields = ', (SELECT COUNT(DISTINCT u.id)
                              FROM {role_assignments} cra JOIN {user} u ON cra.userid = u.id
                             WHERE cra.roleid = r.id AND cra.contextid = :conid AND u.deleted = 0
                           ) AS usercount';
index 9951121..0d7f24b 100644 (file)
@@ -1174,6 +1174,39 @@ class core_accesslib_testcase extends advanced_testcase {
         }
     }
 
+    /**
+     * Test user count of assignable roles in context where users are assigned the role via different components.
+     */
+    public function test_get_assignable_roles_distinct_usercount() {
+        global $DB;
+
+        $this->resetAfterTest(true);
+
+        $this->setAdminUser();
+
+        $course = $this->getDataGenerator()->create_course();
+        $context = \context_course::instance($course->id);
+
+        $user1 = $this->getDataGenerator()->create_user();
+        $user2 = $this->getDataGenerator()->create_user();
+
+        $studentrole = $DB->get_record('role', ['shortname' => 'student']);
+
+        // Assign each user the student role in course.
+        role_assign($studentrole->id, $user1->id, $context->id);
+        role_assign($studentrole->id, $user2->id, $context->id);
+
+        list($rolenames, $rolecounts, $nameswithcounts) = get_assignable_roles($context, ROLENAME_SHORT, true);
+        $this->assertEquals(2, $rolecounts[$studentrole->id]);
+
+        // Assign first user the student role in course again (this time via 'enrol_self' component).
+        role_assign($studentrole->id, $user1->id, $context->id, 'enrol_self', 1);
+
+        // There are still only two distinct users.
+        list($rolenames, $rolecounts, $nameswithcounts) = get_assignable_roles($context, ROLENAME_SHORT, true);
+        $this->assertEquals(2, $rolecounts[$studentrole->id]);
+    }
+
     /**
      * Test getting of all switchable roles.
      */