MDL-79174 availability: Allow group condition to use hidden groups

Previously, groups with GROUP_VISIBILITY_NONE could be selected for an
availability condition, but as the group API did not return a user's own
groups with this visibility, the condition's is_available check always
failed.

This change uses the new $includehidden parameter to get all of a user's
groups from groups_get_user_groups when evaluating the condition, so
these groups work as expected. Due to the enforced hiding of conditions
containing these groups, they will never be seen by the user.
This commit is contained in:
Mark Johnson 2024-02-21 14:16:40 +00:00
parent ce706292bf
commit 238ea3d1a3
No known key found for this signature in database
GPG key ID: EB30E1468CFAE242
4 changed files with 77 additions and 2 deletions

View file

@ -49,6 +49,9 @@ abstract class info {
/** @var tree Availability configuration, decoded from JSON; null if unset */
protected $availabilitytree;
/** @var array The groups the current user belongs to. */
protected $groups;
/** @var array|null Array of information about current restore if any */
protected static $restoreinfo = null;
@ -65,6 +68,7 @@ abstract class info {
$this->course = $course;
$this->visible = (bool)$visible;
$this->availability = $availability;
$this->groups = null;
}
/**
@ -800,4 +804,28 @@ abstract class info {
}
return false;
}
/**
* Returns groups that the current user belongs to on the course. Note: If not already
* available, this may make a database query.
*
* This will include groups the user is not allowed to see themselves, so check visibility
* before displaying groups to the user.
*
* @param int $groupingid Grouping ID or 0 (default) for all groups
* @return int[] Array of int (group id) => int (same group id again); empty array if none
*/
public function get_groups(int $groupingid = 0): array {
global $USER;
if (is_null($this->groups)) {
$allgroups = groups_get_user_groups($this->course->id, $USER->id, true);
$this->groups = $allgroups;
} else {
$allgroups = $this->groups;
}
if (!isset($allgroups[$groupingid])) {
return [];
}
return $allgroups[$groupingid];
}
}

View file

@ -71,7 +71,7 @@ class condition extends \core_availability\condition {
$allow = true;
if (!has_capability('moodle/site:accessallgroups', $context, $userid)) {
// Get all groups the user belongs to.
$groups = $info->get_modinfo()->get_groups();
$groups = $info->get_groups();
if ($this->groupid) {
$allow = in_array($this->groupid, $groups);
} else {

View file

@ -108,3 +108,49 @@ Feature: availability_group
When I am on the "C1" "Course" page logged in as "student1"
Then I should see "Not available unless: You belong to G-One"
And I should not see "G-Un"
@javascript
Scenario: Condition using a hidden group
And the following "groups" exist:
| name | course | idnumber | visibility |
| Hidden Group | C1 | GA | 3 |
And I log in as "teacher1"
And I add a page activity to course "Course 1" section "1"
And I expand all fieldsets
# Page P1 any group.
And I am on the "P1" "page activity editing" page
And I expand all fieldsets
And I click on "Add restriction..." "button"
Then "Group" "button" should exist in the "Add restriction..." "dialogue"
Given I click on "Group" "button" in the "Add restriction..." "dialogue"
And I set the field "Group" to "(Any group)"
And I click on ".availability-item .availability-eye img" "css_element"
And I click on "Save and return to course" "button"
# Page P2 with hidden group.
And I am on the "P2" "page activity editing" page
And I expand all fieldsets
And I click on "Add restriction..." "button"
And I click on "Group" "button" in the "Add restriction..." "dialogue"
And I set the field "Group" to "Hidden Group"
And I click on "Save and return to course" "button"
# Log back in as student.
When I am on the "Course 1" "course" page logged in as "student1"
# No pages should appear yet.
Then I should not see "P1" in the "region-main" "region"
And I should not see "P2" in the "region-main" "region"
And I should not see "Hidden Group"
# Add to groups and log out/in again.
Given the following "group members" exist:
| user | group |
| student1 | GA |
And I am on "Course 1" course homepage
# P1 (any groups) and P2 should show. The user should not see the hidden group mentioned anywhere.
Then I should see "P1" in the "region-main" "region"
And I should see "P2" in the "region-main" "region"
And I should not see "Hidden Group"

View file

@ -49,6 +49,7 @@ class condition_test extends \advanced_testcase {
$course = $generator->create_course();
$user = $generator->create_user();
$generator->enrol_user($user->id, $course->id);
$this->setUser($user);
$info = new \core_availability\mock_info($course, $user->id);
// Make 2 test groups, one in a grouping and one not.
@ -70,7 +71,7 @@ class condition_test extends \advanced_testcase {
// Add user to groups and refresh cache.
groups_add_member($group1, $user);
groups_add_member($group2, $user);
get_fast_modinfo($course->id, 0, true);
$info = new \core_availability\mock_info($course, $user->id);
// Recheck.
$this->assertTrue($cond->is_available(false, $info, true, $user->id));