MDL-66767 forumreport_summary: Control groups filter content
authorMichael Hawkins <michaelh@moodle.com>
Tue, 1 Oct 2019 07:54:12 +0000 (15:54 +0800)
committerMichael Hawkins <michaelh@moodle.com>
Fri, 18 Oct 2019 04:23:49 +0000 (12:23 +0800)
Control the groups filter options based on forum groups mode and groups
visible to the user viewing the report.

mod/forum/report/summary/classes/output/filters.php
mod/forum/report/summary/classes/summary_table.php

index 054f55e..1c6be47 100644 (file)
@@ -93,35 +93,42 @@ class filters implements renderable, templatable {
      * @return void.
      */
     protected function prepare_groups_data(array $groupsdata): void {
+        global $DB, $USER;
+
+        $groupmode = groups_get_activity_groupmode($this->cm);
+        $context = \context_module::instance($this->cm->id);
+        $aag = has_capability('moodle/site:accessallgroups', $context);
         $groupsavailable = [];
-        $groupsselected = [];
 
-        // Only fetch groups user has access to.
-        $groups = groups_get_activity_allowed_groups($this->cm);
+        // If no groups mode enabled, nothing to prepare.
+        if (!in_array($groupmode, [VISIBLEGROUPS, SEPARATEGROUPS])) {
+            return;
+        }
 
-        // Include a 'no groups' option if groups exist.
-        if (!empty($groups)) {
+        if ($groupmode == VISIBLEGROUPS || $aag) {
+            // Any groups, and no groups.
+            $allowedgroupsobj = groups_get_all_groups($this->cm->course, 0, $this->cm->groupingid);
             $nogroups = new stdClass();
             $nogroups->id = -1;
             $nogroups->name = get_string('groupsnone');
-            array_push($groups, $nogroups);
+            $allowedgroupsobj[] = $nogroups;
+        } else {
+            // Only assigned groups.
+            $allowedgroupsobj = groups_get_all_groups($this->cm->course, $USER->id, $this->cm->groupingid);
         }
 
-        foreach ($groups as $group) {
+        foreach ($allowedgroupsobj as $group) {
             $groupsavailable[$group->id] = $group->name;
-
-            // Select provided groups if they are available.
-            if (in_array($group->id, $groupsdata)) {
-                $groupsselected[] = $group->id;
-            }
         }
 
+        // Set valid groups selected.
+        $groupsselected = array_intersect($groupsdata, array_keys($groupsavailable));
+
         // Overwrite groups properties.
         $this->groupsavailable = $groupsavailable;
         $this->groupsselected = $groupsselected;
     }
 
-
     /**
      * Export data for use as the context of a mustache template.
      *
index 3c2d3f3..ac93572 100644 (file)
@@ -313,20 +313,23 @@ class summary_table extends table_sql {
                 // Filter data to only include content within specified groups (and/or no groups).
                 // Additionally, only display users who can post within the selected option(s).
 
-                // Skip adding filter if not applied, or all options are selected.
-                if ($this->is_filtered_by_groups($values)) {
+                // Only filter by groups the user has access to.
+                $groups = $this->get_filter_groups($values);
+
+                // Skip adding filter if not applied, or all valid options are selected.
+                if (!empty($groups)) {
                     // Posts within selected groups and/or not in any groups (group ID -1) are included.
                     // No user filtering as anyone enrolled can potentially post to unrestricted discussions.
-                    if (array_search(-1, $values, true) !== false) {
-                        list($groupidin, $groupidparams) = $DB->get_in_or_equal($values, SQL_PARAMS_NAMED, 'groupid');
+                    if (array_search(-1, $groups) !== false) {
+                        list($groupidin, $groupidparams) = $DB->get_in_or_equal($groups, SQL_PARAMS_NAMED);
 
                         $this->sql->filterwhere .= " AND d.groupid {$groupidin}";
                         $this->sql->params += $groupidparams;
 
-                    } else if (!empty($values)) {
+                    } else {
                         // Only posts and users within selected groups are included.
-                        list($groupusersin, $groupusersparams) = $DB->get_in_or_equal($values, SQL_PARAMS_NAMED, 'groupusers');
-                        list($groupidin, $groupidparams) = $DB->get_in_or_equal($values, SQL_PARAMS_NAMED, 'groupid');
+                        list($groupusersin, $groupusersparams) = $DB->get_in_or_equal($groups, SQL_PARAMS_NAMED);
+                        list($groupidin, $groupidparams) = $DB->get_in_or_equal($groups, SQL_PARAMS_NAMED);
 
                         // No joins required (handled by where to prevent data duplication).
                         $this->sql->filterwhere .= "
@@ -607,25 +610,57 @@ class summary_table extends table_sql {
     }
 
     /**
-     * Check whether the groups filter will be applied by checking whether the number of groups selected
-     * matches the total number of options available (all groups plus no groups option).
+     * Get the final list of groups to filter by, based on the groups submitted,
+     * and those the user has access to.
+     *
      *
-     * @param array $groups The group IDs selected.
-     * @return bool
+     * @param array $groups The group IDs submitted.
+     * @return array Group objects of groups to use in groups filter.
+     *                If no filtering required (all groups selected), returns [].
      */
-    protected function is_filtered_by_groups(array $groups): bool {
-        static $groupsavailablecount = null;
+    protected function get_filter_groups(array $groups): array {
+        global $USER;
 
-        if (empty($groups)) {
-            return false;
-        }
+        $groupmode = groups_get_activity_groupmode($this->cm);
+        $aag = has_capability('moodle/site:accessallgroups', $this->context);
+        $allowedgroups = [];
+        $filtergroups = [];
+
+        // Filtering only valid if a forum groups mode is enabled.
+        if (in_array($groupmode, [VISIBLEGROUPS, SEPARATEGROUPS])) {
+            $allgroupsobj = groups_get_all_groups($this->cm->course, 0, $this->cm->groupingid);
+            $allgroups = [];
+
+            foreach ($allgroupsobj as $group) {
+                $allgroups[] = $group->id;
+            }
 
-        // Find total number of options available (groups plus 'no groups'), if not already fetched.
-        if (is_null($groupsavailablecount)) {
-            $groupsavailablecount = 1 + count(groups_get_activity_allowed_groups($this->cm));
+            if ($groupmode == VISIBLEGROUPS || $aag) {
+                $nogroups = new \stdClass();
+                $nogroups->id = -1;
+                $nogroups->name = get_string('groupsnone');
+
+                // Any groups and no groups.
+                $allowedgroupsobj = $allgroupsobj + [$nogroups];
+            } else {
+                // Only assigned groups.
+                $allowedgroupsobj = groups_get_all_groups($this->cm->course, $USER->id, $this->cm->groupingid);
+            }
+
+            foreach ($allowedgroupsobj as $group) {
+                $allowedgroups[] = $group->id;
+            }
+
+            // If not all groups in course are selected, filter by allowed groups submitted.
+            if (!empty($groups) && !empty(array_diff($allowedgroups, $groups))) {
+                $filtergroups = array_intersect($groups, $allowedgroups);
+            } else if (!empty(array_diff($allgroups, $allowedgroups))) {
+                // If user's 'all groups' is a subset of the course groups, filter by all groups available to them.
+                $filtergroups = $allowedgroups;
+            }
         }
 
-        return (count($groups) < $groupsavailablecount);
+        return $filtergroups;
     }
 
     /**