diff --git a/enrol/externallib.php b/enrol/externallib.php
index 0497bc3fcf3..98788cb3de3 100644
--- a/enrol/externallib.php
+++ b/enrol/externallib.php
@@ -629,6 +629,7 @@ class core_enrol_external extends external_api {
'searchanywhere' => new external_value(PARAM_BOOL, 'find a match anywhere, or only at the beginning'),
'page' => new external_value(PARAM_INT, 'Page number'),
'perpage' => new external_value(PARAM_INT, 'Number per page'),
+ 'contextid' => new external_value(PARAM_INT, 'Context ID', VALUE_DEFAULT, null),
]
);
}
@@ -641,11 +642,12 @@ class core_enrol_external extends external_api {
* @param bool $searchanywhere Match anywhere in the string
* @param int $page Page number
* @param int $perpage Max per page
+ * @param ?int $contextid Context ID we are in - we might use search on activity level and its group mode can be different from course group mode.
* @return array An array of users
* @throws moodle_exception
*/
- public static function search_users(int $courseid, string $search, bool $searchanywhere, int $page, int $perpage): array {
- global $PAGE, $DB, $CFG;
+ public static function search_users(int $courseid, string $search, bool $searchanywhere, int $page, int $perpage, ?int $contextid = null): array {
+ global $PAGE, $CFG;
require_once($CFG->dirroot.'/enrol/locallib.php');
require_once($CFG->dirroot.'/user/lib.php');
@@ -657,10 +659,15 @@ class core_enrol_external extends external_api {
'search' => $search,
'searchanywhere' => $searchanywhere,
'page' => $page,
- 'perpage' => $perpage
- ]
+ 'perpage' => $perpage,
+ 'contextid' => $contextid,
+ ],
);
- $context = context_course::instance($params['courseid']);
+ if (isset($contextid)) {
+ $context = context::instance_by_id($params['contextid']);
+ } else {
+ $context = context_course::instance($params['courseid']);
+ }
try {
self::validate_context($context);
} catch (Exception $e) {
@@ -674,10 +681,14 @@ class core_enrol_external extends external_api {
$course = get_course($params['courseid']);
$manager = new course_enrolment_manager($PAGE, $course);
- $users = $manager->search_users($params['search'],
- $params['searchanywhere'],
- $params['page'],
- $params['perpage']);
+ $users = $manager->search_users(
+ $params['search'],
+ $params['searchanywhere'],
+ $params['page'],
+ $params['perpage'],
+ false,
+ $params['contextid']
+ );
$results = [];
// Add also extra user fields.
diff --git a/enrol/locallib.php b/enrol/locallib.php
index 91accbf8d1f..65a92f765c3 100644
--- a/enrol/locallib.php
+++ b/enrol/locallib.php
@@ -563,26 +563,40 @@ class course_enrolment_manager {
* @param int $page Starting at 0.
* @param int $perpage Number of users returned per page.
* @param bool $returnexactcount Return the exact total users using count_record or not.
+ * @param ?int $contextid Context ID we are in - we might use search on activity level and its group mode can be different from course group mode.
* @return array with two or three elements:
* int totalusers Number users matching the search. (This element only exist if $returnexactcount was set to true)
* array users List of user objects returned by the query.
* boolean moreusers True if there are still more users, otherwise is False.
*/
public function search_users(string $search = '', bool $searchanywhere = false, int $page = 0, int $perpage = 25,
- bool $returnexactcount = false) {
+ bool $returnexactcount = false, ?int $contextid = null) {
global $USER;
[$ufields, $joins, $params, $wherecondition] = $this->get_basic_search_conditions($search, $searchanywhere);
- $groupmode = groups_get_course_groupmode($this->course);
- if ($groupmode == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', $this->context)) {
+ if (isset($contextid)) {
+ // If contextid is set, we need to determine the group mode that should be used (module or course).
+ [$context, $course, $cm] = get_context_info_array($contextid);
+ // If cm instance is returned, then use the group mode from the module, otherwise get the course group mode.
+ $groupmode = $cm ? groups_get_activity_groupmode($cm, $course) : groups_get_course_groupmode($this->course);
+ } else {
+ // Otherwise, default to the group mode of the course.
+ $context = $this->context;
+ $groupmode = groups_get_course_groupmode($this->course);
+ }
+
+ if ($groupmode == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', $context)) {
$groups = groups_get_all_groups($this->course->id, $USER->id, 0, 'g.id');
$groupids = array_column($groups, 'id');
+ if (!$groupids) {
+ return ['totalusers' => 0, 'users' => [], 'moreusers' => false];
+ }
} else {
$groupids = [];
}
- [$enrolledsql, $enrolledparams] = get_enrolled_sql($this->context, '', $groupids);
+ [$enrolledsql, $enrolledparams] = get_enrolled_sql($context, '', $groupids);
$fields = 'SELECT ' . $ufields;
$countfields = 'SELECT COUNT(u.id)';
diff --git a/enrol/tests/course_enrolment_manager_test.php b/enrol/tests/course_enrolment_manager_test.php
index 91b90edae1a..01fb9a6b983 100644
--- a/enrol/tests/course_enrolment_manager_test.php
+++ b/enrol/tests/course_enrolment_manager_test.php
@@ -18,6 +18,7 @@ namespace core_enrol;
use context_course;
use course_enrolment_manager;
+use stdClass;
/**
* Test course_enrolment_manager parts.
@@ -557,11 +558,18 @@ class course_enrolment_manager_test extends \advanced_testcase {
$this->resetAfterTest();
+ // Create the forum.
+ $record = new stdClass();
+ $record->introformat = FORMAT_HTML;
+ $record->course = $this->course->id;
+ $forum = self::getDataGenerator()->create_module('forum', $record, ['groupmode' => SEPARATEGROUPS]);
+ $contextid = $DB->get_field('context', 'id', ['instanceid' => $forum->cmid, 'contextlevel' => CONTEXT_MODULE]);
+
$teacher = $this->getDataGenerator()->create_and_enrol($this->course, 'teacher');
$this->getDataGenerator()->create_group_member(['groupid' => $this->groups['group1']->id, 'userid' => $teacher->id]);
$this->setUser($teacher);
- $users = (new course_enrolment_manager($PAGE, $this->course))->search_users('', false, 0, 25, true);
+ $courseusers = (new course_enrolment_manager($PAGE, $this->course))->search_users('', false, 0, 25, true);
$this->assertEqualsCanonicalizing([
$teacher->username,
$this->users['user0']->username,
@@ -570,26 +578,49 @@ class course_enrolment_manager_test extends \advanced_testcase {
$this->users['user22']->username,
$this->users['userall']->username,
$this->users['usertch']->username,
- ], array_column($users['users'], 'username'));
- $this->assertEquals(7, $users['totalusers']);
+ ], array_column($courseusers['users'], 'username'));
+ $this->assertEquals(7, $courseusers['totalusers']);
- // Switch course to separate groups.
- $this->course->groupmode = SEPARATEGROUPS;
- update_course($this->course);
-
- $users = (new course_enrolment_manager($PAGE, $this->course))->search_users('', false, 0, 25, true);
+ $forumusers = (new course_enrolment_manager($PAGE, $this->course))->search_users('', false, 0, 25, true, $contextid);
$this->assertEqualsCanonicalizing([
$teacher->username,
$this->users['user1']->username,
$this->users['userall']->username,
- ], array_column($users['users'], 'username'));
- $this->assertEquals(3, $users['totalusers']);
+ ], array_column($forumusers['users'], 'username'));
+ $this->assertEquals(3, $forumusers['totalusers']);
+
+ // Switch course to separate groups and forum to no group.
+ $this->course->groupmode = SEPARATEGROUPS;
+ update_course($this->course);
+ set_coursemodule_groupmode($forum->cmid, NOGROUPS);
+
+ $courseusers = (new course_enrolment_manager($PAGE, $this->course))->search_users('', false, 0, 25, true);
+ $this->assertEqualsCanonicalizing([
+ $teacher->username,
+ $this->users['user1']->username,
+ $this->users['userall']->username,
+ ], array_column($courseusers['users'], 'username'));
+ $this->assertEquals(3, $courseusers['totalusers']);
+
+ $forumusers = (new course_enrolment_manager($PAGE, $this->course))->search_users('', false, 0, 25, true, $contextid);
+ $this->assertEqualsCanonicalizing([
+ $teacher->username,
+ $this->users['user0']->username,
+ $this->users['user1']->username,
+ $this->users['user21']->username,
+ $this->users['user22']->username,
+ $this->users['userall']->username,
+ $this->users['usertch']->username,
+ ], array_column($forumusers['users'], 'username'));
+ $this->assertEquals(7, $forumusers['totalusers']);
+
+ set_coursemodule_groupmode($forum->cmid, SEPARATEGROUPS);
// Allow teacher to access all groups.
$roleid = $DB->get_field('role', 'id', ['shortname' => 'teacher']);
assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $roleid, context_course::instance($this->course->id)->id);
- $users = (new course_enrolment_manager($PAGE, $this->course))->search_users('', false, 0, 25, true);
+ $courseusers = (new course_enrolment_manager($PAGE, $this->course))->search_users('', false, 0, 25, true);
$this->assertEqualsCanonicalizing([
$teacher->username,
$this->users['user0']->username,
@@ -598,7 +629,19 @@ class course_enrolment_manager_test extends \advanced_testcase {
$this->users['user22']->username,
$this->users['userall']->username,
$this->users['usertch']->username,
- ], array_column($users['users'], 'username'));
- $this->assertEquals(7, $users['totalusers']);
+ ], array_column($courseusers['users'], 'username'));
+ $this->assertEquals(7, $courseusers['totalusers']);
+
+ $forumusers = (new course_enrolment_manager($PAGE, $this->course))->search_users('', false, 0, 25, true, $contextid);
+ $this->assertEqualsCanonicalizing([
+ $teacher->username,
+ $this->users['user0']->username,
+ $this->users['user1']->username,
+ $this->users['user21']->username,
+ $this->users['user22']->username,
+ $this->users['userall']->username,
+ $this->users['usertch']->username,
+ ], array_column($forumusers['users'], 'username'));
+ $this->assertEquals(7, $forumusers['totalusers']);
}
}
diff --git a/enrol/tests/externallib_test.php b/enrol/tests/externallib_test.php
index 868b444ceb2..0a13b95ab5f 100644
--- a/enrol/tests/externallib_test.php
+++ b/enrol/tests/externallib_test.php
@@ -20,6 +20,7 @@ use core_enrol_external;
use core_external\external_api;
use enrol_user_enrolment_form;
use externallib_advanced_testcase;
+use stdClass;
defined('MOODLE_INTERNAL') || die();
@@ -1421,6 +1422,71 @@ class externallib_test extends externallib_advanced_testcase {
$this->assertCount(0, $result);
}
+ /**
+ * Test for core_enrol_external::search_users() when group mode is active.
+ * @covers ::search_users
+ */
+ public function test_search_users_groupmode() {
+ global $DB;
+
+ $this->resetAfterTest();
+ $datagen = $this->getDataGenerator();
+
+ $studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student'], MUST_EXIST);
+ $teacherroleid = $DB->get_field('role', 'id', ['shortname' => 'teacher'], MUST_EXIST);
+
+ $course = $datagen->create_course();
+
+ $student1 = $datagen->create_and_enrol($course);
+ $student2 = $datagen->create_and_enrol($course);
+ $student3 = $datagen->create_and_enrol($course);
+ $teacher1 = $datagen->create_and_enrol($course, 'teacher');
+ $teacher2 = $datagen->create_and_enrol($course, 'teacher');
+ $teacher3 = $datagen->create_and_enrol($course, 'teacher');
+ $teacher4 = $datagen->create_and_enrol($course, 'editingteacher');
+
+ // Create 2 groups.
+ $group1 = $datagen->create_group(['courseid' => $course->id]);
+ $group2 = $datagen->create_group(['courseid' => $course->id]);
+
+ // Add the users to the groups.
+ $datagen->create_group_member(['groupid' => $group1->id, 'userid' => $student1->id]);
+ $datagen->create_group_member(['groupid' => $group2->id, 'userid' => $student2->id]);
+ $datagen->create_group_member(['groupid' => $group2->id, 'userid' => $student3->id]);
+ $datagen->create_group_member(['groupid' => $group1->id, 'userid' => $teacher1->id]);
+ $datagen->create_group_member(['groupid' => $group2->id, 'userid' => $teacher1->id]);
+ $datagen->create_group_member(['groupid' => $group1->id, 'userid' => $teacher2->id]);
+
+ // Create the forum.
+ $record = new stdClass();
+ $record->introformat = FORMAT_HTML;
+ $record->course = $course->id;
+ $forum = self::getDataGenerator()->create_module('forum', $record, ['groupmode' => SEPARATEGROUPS]);
+ $contextid = $DB->get_field('context', 'id', ['instanceid' => $forum->cmid, 'contextlevel' => CONTEXT_MODULE]);
+
+ $this->setUser($teacher1);
+ $result = core_enrol_external::search_users($course->id, 'user', true, 0, 30, $contextid);
+ $this->assertCount(5, $result);
+
+ $this->setUser($teacher2);
+ $result = core_enrol_external::search_users($course->id, 'user', true, 0, 30, $contextid);
+ $this->assertCount(3, $result);
+
+ $this->setUser($teacher3);
+ $result = core_enrol_external::search_users($course->id, 'user', true, 0, 30, $contextid);
+ $this->assertCount(0, $result);
+
+ $this->setUser($teacher4);
+ $result = core_enrol_external::search_users($course->id, 'user', true, 0, 30, $contextid);
+ $this->assertCount(7, $result);
+
+ // Now change the group mode to no groups.
+ set_coursemodule_groupmode($forum->cmid, NOGROUPS);
+ $this->setUser($teacher1);
+ $result = core_enrol_external::search_users($course->id, 'user', true, 0, 30, $contextid);
+ $this->assertCount(7, $result);
+ }
+
/**
* Tests the get_potential_users external function (not too much detail because the back-end
* is covered in another test).
diff --git a/enrol/upgrade.txt b/enrol/upgrade.txt
index 5bf66904d68..d1723b3dc40 100644
--- a/enrol/upgrade.txt
+++ b/enrol/upgrade.txt
@@ -1,6 +1,11 @@
This files describes API changes in /enrol/* - plugins,
information provided here is intended especially for developers.
+=== 4.2.6 ===
+
+* Functions core_enrol_external::search_users and course_enrolment_manager::search_users now have extra optional parameter
+ contextid which allows to search users in a specific activity context. When omitted it searches in the whole course.
+
=== 4.2 ===
* New is_self_enrol_available() function has been created. Similar to can_self_enrol but without checking user capabilities.
diff --git a/mod/forum/amd/build/form-user-selector.min.js b/mod/forum/amd/build/form-user-selector.min.js
index 5a1da302875..19447f7cdb6 100644
--- a/mod/forum/amd/build/form-user-selector.min.js
+++ b/mod/forum/amd/build/form-user-selector.min.js
@@ -5,6 +5,6 @@
* @copyright 2019 Shamim Rezaie
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-define("mod_forum/form-user-selector",["jquery","core/ajax","core/templates"],(function($,Ajax,Templates){return{processResults:function(selector,results){var users=[];return $.each(results,(function(index,user){users.push({value:user.id,label:user._label})})),users},transport:function(selector,query,success,failure){var courseid=$(selector).attr("courseid");Ajax.call([{methodname:"core_enrol_search_users",args:{courseid:courseid,search:query,searchanywhere:!0,page:0,perpage:30}}])[0].then((function(results){var promises=[],i=0;return $.each(results,(function(index,user){promises.push(Templates.render("mod_forum/form-user-selector-suggestion",user))})),$.when.apply($.when,promises).then((function(){var args=arguments;$.each(results,(function(index,user){user._label=args[i],i++})),success(results)}))})).fail(failure)}}}));
+define("mod_forum/form-user-selector",["jquery","core/ajax","core/templates"],(function($,Ajax,Templates){return{processResults:function(selector,results){var users=[];return $.each(results,(function(index,user){users.push({value:user.id,label:user._label})})),users},transport:function(selector,query,success,failure){var courseid=$(selector).attr("courseid"),contextid=$(selector).attr("data-contextid");Ajax.call([{methodname:"core_enrol_search_users",args:{courseid:courseid,search:query,searchanywhere:!0,page:0,perpage:30,contextid:contextid}}])[0].then((function(results){var promises=[],i=0;return $.each(results,(function(index,user){promises.push(Templates.render("mod_forum/form-user-selector-suggestion",user))})),$.when.apply($.when,promises).then((function(){var args=arguments;$.each(results,(function(index,user){user._label=args[i],i++})),success(results)}))})).fail(failure)}}}));
//# sourceMappingURL=form-user-selector.min.js.map
\ No newline at end of file
diff --git a/mod/forum/amd/build/form-user-selector.min.js.map b/mod/forum/amd/build/form-user-selector.min.js.map
index 5bf0dae6e27..f97eb3c6230 100644
--- a/mod/forum/amd/build/form-user-selector.min.js.map
+++ b/mod/forum/amd/build/form-user-selector.min.js.map
@@ -1 +1 @@
-{"version":3,"file":"form-user-selector.min.js","sources":["../src/form-user-selector.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Enrolled user selector module.\n *\n * @module mod_forum/form-user-selector\n * @copyright 2019 Shamim Rezaie\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['jquery', 'core/ajax', 'core/templates'], function($, Ajax, Templates) {\n return /** @alias module:mod_forum/form-user-selector */ {\n processResults: function(selector, results) {\n var users = [];\n $.each(results, function(index, user) {\n users.push({\n value: user.id,\n label: user._label\n });\n });\n return users;\n },\n\n transport: function(selector, query, success, failure) {\n var promise;\n var courseid = $(selector).attr('courseid');\n\n promise = Ajax.call([{\n methodname: 'core_enrol_search_users',\n args: {\n courseid: courseid,\n search: query,\n searchanywhere: true,\n page: 0,\n perpage: 30\n }\n }]);\n\n promise[0].then(function(results) {\n var promises = [],\n i = 0;\n\n // Render the label.\n $.each(results, function(index, user) {\n promises.push(Templates.render('mod_forum/form-user-selector-suggestion', user));\n });\n\n // Apply the label to the results.\n return $.when.apply($.when, promises).then(function() {\n var args = arguments;\n $.each(results, function(index, user) {\n user._label = args[i];\n i++;\n });\n success(results);\n return;\n });\n\n }).fail(failure);\n }\n\n };\n\n});\n"],"names":["define","$","Ajax","Templates","processResults","selector","results","users","each","index","user","push","value","id","label","_label","transport","query","success","failure","courseid","attr","call","methodname","args","search","searchanywhere","page","perpage","then","promises","i","render","when","apply","arguments","fail"],"mappings":";;;;;;;AAuBAA,sCAAO,CAAC,SAAU,YAAa,mBAAmB,SAASC,EAAGC,KAAMC,iBACP,CACrDC,eAAgB,SAASC,SAAUC,aAC3BC,MAAQ,UACZN,EAAEO,KAAKF,SAAS,SAASG,MAAOC,MAC5BH,MAAMI,KAAK,CACPC,MAAOF,KAAKG,GACZC,MAAOJ,KAAKK,YAGbR,OAGXS,UAAW,SAASX,SAAUY,MAAOC,QAASC,aAEtCC,SAAWnB,EAAEI,UAAUgB,KAAK,YAEtBnB,KAAKoB,KAAK,CAAC,CACjBC,WAAY,0BACZC,KAAM,CACFJ,SAAUA,SACVK,OAAQR,MACRS,gBAAgB,EAChBC,KAAM,EACNC,QAAS,OAIT,GAAGC,MAAK,SAASvB,aACjBwB,SAAW,GACXC,EAAI,SAGR9B,EAAEO,KAAKF,SAAS,SAASG,MAAOC,MAC5BoB,SAASnB,KAAKR,UAAU6B,OAAO,0CAA2CtB,UAIvET,EAAEgC,KAAKC,MAAMjC,EAAEgC,KAAMH,UAAUD,MAAK,eACnCL,KAAOW,UACXlC,EAAEO,KAAKF,SAAS,SAASG,MAAOC,MAC5BA,KAAKK,OAASS,KAAKO,GACnBA,OAEJb,QAAQZ,eAIb8B,KAAKjB"}
\ No newline at end of file
+{"version":3,"file":"form-user-selector.min.js","sources":["../src/form-user-selector.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Enrolled user selector module.\n *\n * @module mod_forum/form-user-selector\n * @copyright 2019 Shamim Rezaie\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['jquery', 'core/ajax', 'core/templates'], function($, Ajax, Templates) {\n return /** @alias module:mod_forum/form-user-selector */ {\n processResults: function(selector, results) {\n var users = [];\n $.each(results, function(index, user) {\n users.push({\n value: user.id,\n label: user._label\n });\n });\n return users;\n },\n\n transport: function(selector, query, success, failure) {\n var promise;\n var courseid = $(selector).attr('courseid');\n var contextid = $(selector).attr('data-contextid');\n\n promise = Ajax.call([{\n methodname: 'core_enrol_search_users',\n args: {\n courseid: courseid,\n search: query,\n searchanywhere: true,\n page: 0,\n perpage: 30,\n contextid: contextid,\n }\n }]);\n\n promise[0].then(function(results) {\n var promises = [],\n i = 0;\n\n // Render the label.\n $.each(results, function(index, user) {\n promises.push(Templates.render('mod_forum/form-user-selector-suggestion', user));\n });\n\n // Apply the label to the results.\n return $.when.apply($.when, promises).then(function() {\n var args = arguments;\n $.each(results, function(index, user) {\n user._label = args[i];\n i++;\n });\n success(results);\n return;\n });\n\n }).fail(failure);\n }\n\n };\n\n});\n"],"names":["define","$","Ajax","Templates","processResults","selector","results","users","each","index","user","push","value","id","label","_label","transport","query","success","failure","courseid","attr","contextid","call","methodname","args","search","searchanywhere","page","perpage","then","promises","i","render","when","apply","arguments","fail"],"mappings":";;;;;;;AAuBAA,sCAAO,CAAC,SAAU,YAAa,mBAAmB,SAASC,EAAGC,KAAMC,iBACP,CACrDC,eAAgB,SAASC,SAAUC,aAC3BC,MAAQ,UACZN,EAAEO,KAAKF,SAAS,SAASG,MAAOC,MAC5BH,MAAMI,KAAK,CACPC,MAAOF,KAAKG,GACZC,MAAOJ,KAAKK,YAGbR,OAGXS,UAAW,SAASX,SAAUY,MAAOC,QAASC,aAEtCC,SAAWnB,EAAEI,UAAUgB,KAAK,YAC5BC,UAAYrB,EAAEI,UAAUgB,KAAK,kBAEvBnB,KAAKqB,KAAK,CAAC,CACjBC,WAAY,0BACZC,KAAM,CACFL,SAAUA,SACVM,OAAQT,MACRU,gBAAgB,EAChBC,KAAM,EACNC,QAAS,GACTP,UAAWA,cAIX,GAAGQ,MAAK,SAASxB,aACjByB,SAAW,GACXC,EAAI,SAGR/B,EAAEO,KAAKF,SAAS,SAASG,MAAOC,MAC5BqB,SAASpB,KAAKR,UAAU8B,OAAO,0CAA2CvB,UAIvET,EAAEiC,KAAKC,MAAMlC,EAAEiC,KAAMH,UAAUD,MAAK,eACnCL,KAAOW,UACXnC,EAAEO,KAAKF,SAAS,SAASG,MAAOC,MAC5BA,KAAKK,OAASU,KAAKO,GACnBA,OAEJd,QAAQZ,eAIb+B,KAAKlB"}
\ No newline at end of file
diff --git a/mod/forum/amd/src/form-user-selector.js b/mod/forum/amd/src/form-user-selector.js
index 3c69c3210ee..910c847d15d 100644
--- a/mod/forum/amd/src/form-user-selector.js
+++ b/mod/forum/amd/src/form-user-selector.js
@@ -37,6 +37,7 @@ define(['jquery', 'core/ajax', 'core/templates'], function($, Ajax, Templates) {
transport: function(selector, query, success, failure) {
var promise;
var courseid = $(selector).attr('courseid');
+ var contextid = $(selector).attr('data-contextid');
promise = Ajax.call([{
methodname: 'core_enrol_search_users',
@@ -45,7 +46,8 @@ define(['jquery', 'core/ajax', 'core/templates'], function($, Ajax, Templates) {
search: query,
searchanywhere: true,
page: 0,
- perpage: 30
+ perpage: 30,
+ contextid: contextid,
}
}]);
diff --git a/mod/forum/classes/form/export_form.php b/mod/forum/classes/form/export_form.php
index f589e9f4af0..a6936d208df 100644
--- a/mod/forum/classes/form/export_form.php
+++ b/mod/forum/classes/form/export_form.php
@@ -53,6 +53,7 @@ class export_form extends \moodleform {
'ajax' => 'mod_forum/form-user-selector',
'multiple' => true,
'noselectionstring' => get_string('allusers', 'mod_forum'),
+ 'data-contextid' => $forum->get_context()->id,
'courseid' => $forum->get_course_id(),
'valuehtmlcallback' => function($value) {
global $OUTPUT;
@@ -69,7 +70,6 @@ class export_form extends \moodleform {
];
$mform->addElement('autocomplete', 'useridsselected', get_string('users'), [], $options);
- // Get the discussions on this forum.
$vaultfactory = \mod_forum\local\container::get_vault_factory();
$discussionvault = $vaultfactory->get_discussion_vault();
$discussions = array_map(function($discussion) {
diff --git a/mod/forum/classes/local/vaults/discussion.php b/mod/forum/classes/local/vaults/discussion.php
index 128c365d2d1..5b93f0596d8 100644
--- a/mod/forum/classes/local/vaults/discussion.php
+++ b/mod/forum/classes/local/vaults/discussion.php
@@ -26,6 +26,7 @@ namespace mod_forum\local\vaults;
defined('MOODLE_INTERNAL') || die();
+use mod_forum\local\container;
use mod_forum\local\entities\forum as forum_entity;
use mod_forum\local\entities\discussion as discussion_entity;
@@ -93,9 +94,23 @@ class discussion extends db_table_vault {
* @return array
*/
public function get_all_discussions_in_forum(forum_entity $forum, string $sort = null): ?array {
- $records = $this->get_db()->get_records(self::TABLE, [
- 'forum' => $forum->get_id(),
- ], $sort ?? '');
+ global $USER;
+ $options = ['forum' => $forum->get_id()];
+
+ $managerfactory = container::get_manager_factory();
+ $capabilitymanager = $managerfactory->get_capability_manager($forum);
+
+ $select = "forum = :forum";
+
+ if ($forum->is_in_group_mode() && !$capabilitymanager->can_access_all_groups($USER)) {
+ $allowedgroups = groups_get_activity_allowed_groups($forum->get_course_module_record());
+ $allowedgroups = implode(",", array_keys($allowedgroups));
+ if (!$allowedgroups) {
+ return [];
+ }
+ $select .= " AND groupid IN ($allowedgroups)";
+ }
+ $records = $this->get_db()->get_records_select(self::TABLE, $select, $options, $sort ?? '');
return $this->transform_db_records_to_entities($records);
}
diff --git a/mod/forum/export.php b/mod/forum/export.php
index 9d0c48d35b8..e9eb8fef6e1 100644
--- a/mod/forum/export.php
+++ b/mod/forum/export.php
@@ -192,8 +192,7 @@ if (!$PAGE->has_secondary_navigation()) {
// It is possible that the following fields have been provided in the URL.
$userids = array_filter($userids, static function(int $userid) use ($course, $cm): bool {
- $user = core_user::get_user($userid, '*', MUST_EXIST);
- return $cm->effectivegroupmode != SEPARATEGROUPS || user_can_view_profile($user, $course);
+ return $cm->effectivegroupmode != SEPARATEGROUPS || groups_user_groups_visible($course, $userid, $cm);
});
$form->set_data(['useridsselected' => $userids, 'discussionids' => $discussionids, 'from' => $from, 'to' => $to]);
diff --git a/mod/forum/tests/behat/forum_export.feature b/mod/forum/tests/behat/forum_export.feature
index 2b98f81f16e..05d8ae027a4 100644
--- a/mod/forum/tests/behat/forum_export.feature
+++ b/mod/forum/tests/behat/forum_export.feature
@@ -48,3 +48,125 @@ Feature: Export forum
# This will fail if an exception is thrown. This is the best we can do without the ability to use the download. Hence, there is no "Then" step.
And I click on "Export" "button"
And I log out
+
+ Scenario: Group mode is respected when exporting discussions
+ Given the following "groups" exist:
+ | name | course | idnumber |
+ | G1 | C1 | G1 |
+ | G2 | C1 | G2 |
+ And the following "users" exist:
+ | username | firstname | lastname | email |
+ | teachera | Teacher | A | teacherA@example.com |
+ | teacherb | Teacher | B | teacherB@example.com |
+ | teacherc | Teacher | C | teacherC@example.com |
+ | teacherd | Teacher | D | teacherD@example.com |
+ And the following "course enrolments" exist:
+ | user | course | role |
+ | teachera | C1 | teacher |
+ | teacherb | C1 | teacher |
+ | teacherc | C1 | teacher |
+ | teacherd | C1 | teacher |
+ And the following "group members" exist:
+ | user | group |
+ | teachera | G1 |
+ | teachera | G2 |
+ | teacherb | G1 |
+ | teacherc | G2 |
+ And the following "activities" exist:
+ | activity | course | idnumber | name | intro | type | section | groupmode |
+ | forum | C1 | 00001 | Separate groups forum | Standard forum description | general | 1 | 1 |
+ And the following "mod_forum > discussions" exist:
+ | user | forum | name | message | group |
+ | teachera | Separate groups forum | Discussion 1 Group 1 | Test post message | G1 |
+ | teacherb | Separate groups forum | Discussion 2 Group 1 | Test post message | G1 |
+ | teachera | Separate groups forum | Discussion 1 Group 2 | Test post message | G2 |
+ | teacherc | Separate groups forum | Discussion 2 Group 2 | Test post message | G2 |
+ And I am on the "Separate groups forum" "forum activity" page logged in as teacher1
+ And I navigate to "Export" in current page administration
+ When I expand the "Users" autocomplete
+ # Editing teacher can see all users and discussions.
+ Then I should see "Teacher A" in the "Users" "autocomplete"
+ And I should see "Teacher B" in the "Users" "autocomplete"
+ And I should see "Teacher C" in the "Users" "autocomplete"
+ And I should see "Teacher D" in the "Users" "autocomplete"
+ And I should see "Teacher 1" in the "Users" "autocomplete"
+ And I should see "Student 1" in the "Users" "autocomplete"
+ And I press the escape key
+ And I expand the "Discussions" autocomplete
+ And I should see "Discussion 1 Group 1" in the "Discussions" "autocomplete"
+ And I should see "Discussion 2 Group 1" in the "Discussions" "autocomplete"
+ And I should see "Discussion 1 Group 2" in the "Discussions" "autocomplete"
+ And I should see "Discussion 2 Group 2" in the "Discussions" "autocomplete"
+ And I click on "Export" "button"
+
+ And I am on the "Separate groups forum" "forum activity" page logged in as teachera
+ And I navigate to "Export" in current page administration
+ When I expand the "Users" autocomplete
+ # Teacher A is is in both groups.
+ Then I should see "Teacher A" in the "Users" "autocomplete"
+ And I should see "Teacher B" in the "Users" "autocomplete"
+ And I should see "Teacher C" in the "Users" "autocomplete"
+ And I should not see "Teacher D" in the "Users" "autocomplete"
+ And I should not see "Teacher 1" in the "Users" "autocomplete"
+ And I should not see "Student 1" in the "Users" "autocomplete"
+ And I press the escape key
+ And I expand the "Discussions" autocomplete
+ And I should see "Discussion 1 Group 1" in the "Discussions" "autocomplete"
+ And I should see "Discussion 2 Group 1" in the "Discussions" "autocomplete"
+ And I should see "Discussion 1 Group 2" in the "Discussions" "autocomplete"
+ And I should see "Discussion 2 Group 2" in the "Discussions" "autocomplete"
+ And I click on "Export" "button"
+
+ And I am on the "Separate groups forum" "forum activity" page logged in as teacherb
+ And I navigate to "Export" in current page administration
+ When I expand the "Users" autocomplete
+ # Teacher B is in group 1.
+ Then I should see "Teacher A" in the "Users" "autocomplete"
+ And I should see "Teacher B" in the "Users" "autocomplete"
+ And I should not see "Teacher C" in the "Users" "autocomplete"
+ And I should not see "Teacher D" in the "Users" "autocomplete"
+ And I should not see "Teacher 1" in the "Users" "autocomplete"
+ And I should not see "Student 1" in the "Users" "autocomplete"
+ And I press the escape key
+ And I expand the "Discussions" autocomplete
+ And I should see "Discussion 1 Group 1" in the "Discussions" "autocomplete"
+ And I should see "Discussion 2 Group 1" in the "Discussions" "autocomplete"
+ And I should not see "Discussion 1 Group 2" in the "Discussions" "autocomplete"
+ And I should not see "Discussion 2 Group 2" in the "Discussions" "autocomplete"
+ And I click on "Export" "button"
+
+ And I am on the "Separate groups forum" "forum activity" page logged in as teacherc
+ And I navigate to "Export" in current page administration
+ When I expand the "Users" autocomplete
+ # Teacher C is in group 2.
+ Then I should see "Teacher A" in the "Users" "autocomplete"
+ And I should not see "Teacher B" in the "Users" "autocomplete"
+ And I should see "Teacher C" in the "Users" "autocomplete"
+ And I should not see "Teacher D" in the "Users" "autocomplete"
+ And I should not see "Teacher 1" in the "Users" "autocomplete"
+ And I should not see "Student 1" in the "Users" "autocomplete"
+ And I press the escape key
+ And I expand the "Discussions" autocomplete
+ And I should not see "Discussion 1 Group 1" in the "Discussions" "autocomplete"
+ And I should not see "Discussion 2 Group 1" in the "Discussions" "autocomplete"
+ And I should see "Discussion 1 Group 2" in the "Discussions" "autocomplete"
+ And I should see "Discussion 2 Group 2" in the "Discussions" "autocomplete"
+ And I click on "Export" "button"
+
+ And I am on the "Separate groups forum" "forum activity" page logged in as teacherd
+ And I navigate to "Export" in current page administration
+ When I expand the "Users" autocomplete
+ # Teacher D is in no group.
+ Then I should not see "Teacher A" in the "Users" "autocomplete"
+ And I should not see "Teacher B" in the "Users" "autocomplete"
+ And I should not see "Teacher C" in the "Users" "autocomplete"
+ And I should not see "Teacher D" in the "Users" "autocomplete"
+ And I should not see "Teacher 1" in the "Users" "autocomplete"
+ And I should not see "Student 1" in the "Users" "autocomplete"
+ And I press the escape key
+ And I expand the "Discussions" autocomplete
+ And I should not see "Discussion 1 Group 1" in the "Discussions" "autocomplete"
+ And I should not see "Discussion 2 Group 1" in the "Discussions" "autocomplete"
+ And I should not see "Discussion 1 Group 2" in the "Discussions" "autocomplete"
+ And I should not see "Discussion 2 Group 2" in the "Discussions" "autocomplete"
+ And I click on "Export" "button"