MDL-35637 group: Fix form submission error that occurs when GD version is not set.
[moodle.git] / group / lib.php
CommitLineData
f3f7610c 1<?php
4d8e2417
AG
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
17
f3f7610c 18/**
ddff2fa8 19 * Extra library for groups and groupings.
f3f7610c 20 *
4d8e2417
AG
21 * @copyright 2006 The Open University, J.White AT open.ac.uk, Petr Skoda (skodak)
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 * @package core_group
f3f7610c
ML
24 */
25
ddff2fa8 26/*
27 * INTERNAL FUNCTIONS - to be used by moodle core only
28 * require_once $CFG->dirroot.'/group/lib.php' must be used
29 */
30
778918fd 31/**
32 * Adds a specified user to a group
4d8e2417
AG
33 *
34 * @param mixed $grouporid The group id or group object
35 * @param mixed $userorid The user id or user object
36 * @return bool True if user added successfully or the user is already a
f16fa0a3 37 * member of the group, false otherwise.
778918fd 38 */
9a0df45a 39function groups_add_member($grouporid, $userorid) {
dfdaabd6 40 global $DB;
41
9a0df45a 42 if (is_object($userorid)) {
43 $userid = $userorid->id;
44 $user = $userorid;
45 } else {
46 $userid = $userorid;
b18e25d5 47 $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
2061e59c 48 }
49
9a0df45a 50 if (is_object($grouporid)) {
51 $groupid = $grouporid->id;
52 $group = $grouporid;
53 } else {
54 $groupid = $grouporid;
55 $group = $DB->get_record('groups', array('id'=>$groupid), '*', MUST_EXIST);
778918fd 56 }
57
0d4723ee 58 //check if the user a participant of the group course
4f0c2d00 59 if (!is_enrolled(get_context_instance(CONTEXT_COURSE, $group->courseid), $userid)) {
9a0df45a 60 return false;
0d4723ee 61 }
62
778918fd 63 if (groups_is_member($groupid, $userid)) {
64 return true;
65 }
66
ace9051c 67 $member = new stdClass();
778918fd 68 $member->groupid = $groupid;
69 $member->userid = $userid;
70 $member->timeadded = time();
71
b25263ff 72 $DB->insert_record('groups_members', $member);
778918fd 73
74 //update group info
dfdaabd6 75 $DB->set_field('groups', 'timemodified', $member->timeadded, array('id'=>$groupid));
778918fd 76
2942a5cd 77 //trigger groups events
ace9051c 78 $eventdata = new stdClass();
778918fd 79 $eventdata->groupid = $groupid;
2942a5cd 80 $eventdata->userid = $userid;
81 events_trigger('groups_member_added', $eventdata);
778918fd 82
83 return true;
84}
85
86/**
87 * Deletes the link between the specified user and group.
4d8e2417
AG
88 *
89 * @param mixed $grouporid The group id or group object
90 * @param mixed $userorid The user id or user object
91 * @return bool True if deletion was successful, false otherwise
778918fd 92 */
9a0df45a 93function groups_remove_member($grouporid, $userorid) {
dfdaabd6 94 global $DB;
95
9a0df45a 96 if (is_object($userorid)) {
97 $userid = $userorid->id;
98 $user = $userorid;
99 } else {
100 $userid = $userorid;
b18e25d5 101 $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
2061e59c 102 }
103
9a0df45a 104 if (is_object($grouporid)) {
105 $groupid = $grouporid->id;
106 $group = $grouporid;
107 } else {
108 $groupid = $grouporid;
109 $group = $DB->get_record('groups', array('id'=>$groupid), '*', MUST_EXIST);
778918fd 110 }
111
112 if (!groups_is_member($groupid, $userid)) {
113 return true;
114 }
115
b25263ff 116 $DB->delete_records('groups_members', array('groupid'=>$groupid, 'userid'=>$userid));
117
778918fd 118 //update group info
dfdaabd6 119 $DB->set_field('groups', 'timemodified', time(), array('id'=>$groupid));
778918fd 120
2942a5cd 121 //trigger groups events
ace9051c 122 $eventdata = new stdClass();
2942a5cd 123 $eventdata->groupid = $groupid;
124 $eventdata->userid = $userid;
125 events_trigger('groups_member_removed', $eventdata);
126
778918fd 127 return true;
128}
129
ddff2fa8 130/**
131 * Add a new group
4d8e2417
AG
132 *
133 * @param stdClass $data group properties
134 * @param stdClass $editform
135 * @param array $editoroptions
ddff2fa8 136 * @return id of group or false if error
137 */
e88dd876 138function groups_create_group($data, $editform = false, $editoroptions = false) {
dfdaabd6 139 global $CFG, $DB;
6f5e0852 140
2061e59c 141 //check that courseid exists
9a0df45a 142 $course = $DB->get_record('course', array('id' => $data->courseid), '*', MUST_EXIST);
e88dd876 143 $context = get_context_instance(CONTEXT_COURSE, $course->id);
ddff2fa8 144
dfdaabd6 145 $data->timecreated = time();
ddff2fa8 146 $data->timemodified = $data->timecreated;
dfdaabd6 147 $data->name = trim($data->name);
74b714df
ARN
148 if (isset($data->idnumber)) {
149 $data->idnumber = trim($data->idnumber);
150 if (groups_get_group_by_idnumber($course->id, $data->idnumber)) {
151 throw new moodle_exception('idnumbertaken');
152 }
153 }
8bdc9cac 154
e88dd876 155 if ($editform and $editoroptions) {
8bdc9cac
SH
156 $data->description = $data->description_editor['text'];
157 $data->descriptionformat = $data->description_editor['format'];
158 }
159
e88dd876
PS
160 $data->id = $DB->insert_record('groups', $data);
161
162 if ($editform and $editoroptions) {
163 // Update description from editor with fixed files
164 $data = file_postupdate_standard_editor($data, 'description', $editoroptions, $context, 'group', 'description', $data->id);
ace9051c 165 $upd = new stdClass();
e88dd876
PS
166 $upd->id = $data->id;
167 $upd->description = $data->description;
168 $upd->descriptionformat = $data->descriptionformat;
169 $DB->update_record('groups', $upd);
170 }
171
172 $group = $DB->get_record('groups', array('id'=>$data->id));
ddff2fa8 173
b25263ff 174 if ($editform) {
e88dd876 175 groups_update_group_icon($group, $data, $editform);
ddff2fa8 176 }
177
b25263ff 178 //trigger groups events
e88dd876 179 events_trigger('groups_group_created', $group);
b25263ff 180
e88dd876 181 return $group->id;
ddff2fa8 182}
183
184/**
f16fa0a3 185 * Add a new grouping
4d8e2417
AG
186 *
187 * @param stdClass $data grouping properties
188 * @param array $editoroptions
f16fa0a3 189 * @return id of grouping or false if error
190 */
8bdc9cac 191function groups_create_grouping($data, $editoroptions=null) {
dfdaabd6 192 global $DB;
f16fa0a3 193
dfdaabd6 194 $data->timecreated = time();
f16fa0a3 195 $data->timemodified = $data->timecreated;
dfdaabd6 196 $data->name = trim($data->name);
74b714df
ARN
197 if (isset($data->idnumber)) {
198 $data->idnumber = trim($data->idnumber);
199 if (groups_get_grouping_by_idnumber($data->courseid, $data->idnumber)) {
200 throw new moodle_exception('idnumbertaken');
201 }
202 }
8bdc9cac
SH
203
204 if ($editoroptions !== null) {
205 $data->description = $data->description_editor['text'];
206 $data->descriptionformat = $data->description_editor['format'];
207 }
208
2942a5cd 209 $id = $DB->insert_record('groupings', $data);
210
b25263ff 211 //trigger groups events
212 $data->id = $id;
8bdc9cac
SH
213
214 if ($editoroptions !== null) {
215 $description = new stdClass;
216 $description->id = $data->id;
217 $description->description_editor = $data->description_editor;
64f93798 218 $description = file_postupdate_standard_editor($description, 'description', $editoroptions, $editoroptions['context'], 'grouping', 'description', $description->id);
8bdc9cac
SH
219 $DB->update_record('groupings', $description);
220 }
221
b25263ff 222 events_trigger('groups_grouping_created', $data);
2942a5cd 223
224 return $id;
f16fa0a3 225}
226
e88dd876
PS
227/**
228 * Update the group icon from form data
4d8e2417
AG
229 *
230 * @param stdClass $group group information
231 * @param stdClass $data
232 * @param stdClass $editform
e88dd876
PS
233 */
234function groups_update_group_icon($group, $data, $editform) {
235 global $CFG, $DB;
236 require_once("$CFG->libdir/gdlib.php");
237
238 $fs = get_file_storage();
239 $context = get_context_instance(CONTEXT_COURSE, $group->courseid, MUST_EXIST);
240
241 //TODO: it would make sense to allow picture deleting too (skodak)
40755f95
MN
242 if (!empty($CFG->gdversion)) {
243 if ($iconfile = $editform->save_temp_file('imagefile')) {
244 if (process_new_icon($context, 'group', 'icon', $group->id, $iconfile)) {
245 $DB->set_field('groups', 'picture', 1, array('id'=>$group->id));
246 $group->picture = 1;
247 } else {
248 $fs->delete_area_files($context->id, 'group', 'icon', $group->id);
249 $DB->set_field('groups', 'picture', 0, array('id'=>$group->id));
250 $group->picture = 0;
251 }
252 @unlink($iconfile);
e88dd876 253 }
e88dd876
PS
254 }
255}
256
f16fa0a3 257/**
258 * Update group
4d8e2417
AG
259 *
260 * @param stdClass $data group properties (with magic quotes)
261 * @param stdClass $editform
e88dd876 262 * @param array $editoroptions
4d8e2417 263 * @return bool true or exception
ddff2fa8 264 */
e88dd876 265function groups_update_group($data, $editform = false, $editoroptions = false) {
dfdaabd6 266 global $CFG, $DB;
e88dd876
PS
267
268 $context = get_context_instance(CONTEXT_COURSE, $data->courseid);
ddff2fa8 269
270 $data->timemodified = time();
dfdaabd6 271 $data->name = trim($data->name);
74b714df
ARN
272 if (isset($data->idnumber)) {
273 $data->idnumber = trim($data->idnumber);
274 if (($existing = groups_get_group_by_idnumber($data->courseid, $data->idnumber)) && $existing->id != $data->id) {
275 throw new moodle_exception('idnumbertaken');
276 }
277 }
8bdc9cac 278
e88dd876
PS
279 if ($editform and $editoroptions) {
280 $data = file_postupdate_standard_editor($data, 'description', $editoroptions, $context, 'group', 'description', $data->id);
8bdc9cac
SH
281 }
282
b25263ff 283 $DB->update_record('groups', $data);
2942a5cd 284
e88dd876
PS
285 $group = $DB->get_record('groups', array('id'=>$data->id));
286
b25263ff 287 if ($editform) {
e88dd876 288 groups_update_group_icon($group, $data, $editform);
ddff2fa8 289 }
290
b25263ff 291 //trigger groups events
e88dd876
PS
292 events_trigger('groups_group_updated', $group);
293
b25263ff 294
295 return true;
ddff2fa8 296}
297
f16fa0a3 298/**
299 * Update grouping
4d8e2417
AG
300 *
301 * @param stdClass $data grouping properties (with magic quotes)
302 * @param array $editoroptions
303 * @return bool true or exception
f16fa0a3 304 */
8bdc9cac 305function groups_update_grouping($data, $editoroptions=null) {
dfdaabd6 306 global $DB;
f16fa0a3 307 $data->timemodified = time();
dfdaabd6 308 $data->name = trim($data->name);
74b714df
ARN
309 if (isset($data->idnumber)) {
310 $data->idnumber = trim($data->idnumber);
311 if (($existing = groups_get_grouping_by_idnumber($data->courseid, $data->idnumber)) && $existing->id != $data->id) {
312 throw new moodle_exception('idnumbertaken');
313 }
314 }
8bdc9cac 315 if ($editoroptions !== null) {
64f93798 316 $data = file_postupdate_standard_editor($data, 'description', $editoroptions, $editoroptions['context'], 'grouping', 'description', $data->id);
8bdc9cac 317 }
b25263ff 318 $DB->update_record('groupings', $data);
319 //trigger groups events
320 events_trigger('groups_grouping_updated', $data);
321
322 return true;
f16fa0a3 323}
324
ddff2fa8 325/**
326 * Delete a group best effort, first removing members and links with courses and groupings.
327 * Removes group avatar too.
4d8e2417 328 *
2942a5cd 329 * @param mixed $grouporid The id of group to delete or full group object
4d8e2417 330 * @return bool True if deletion was successful, false otherwise
ddff2fa8 331 */
2942a5cd 332function groups_delete_group($grouporid) {
b7e8cfb6 333 global $CFG, $DB;
334 require_once("$CFG->libdir/gdlib.php");
ddff2fa8 335
2942a5cd 336 if (is_object($grouporid)) {
337 $groupid = $grouporid->id;
338 $group = $grouporid;
339 } else {
340 $groupid = $grouporid;
341 if (!$group = $DB->get_record('groups', array('id'=>$groupid))) {
9a0df45a 342 //silently ignore attempts to delete missing already deleted groups ;-)
343 return true;
2942a5cd 344 }
ddff2fa8 345 }
346
0b5a80a1 347 // delete group calendar events
dfdaabd6 348 $DB->delete_records('event', array('groupid'=>$groupid));
ddff2fa8 349 //first delete usage in groupings_groups
dfdaabd6 350 $DB->delete_records('groupings_groups', array('groupid'=>$groupid));
ddff2fa8 351 //delete members
dfdaabd6 352 $DB->delete_records('groups_members', array('groupid'=>$groupid));
ddff2fa8 353 //group itself last
b25263ff 354 $DB->delete_records('groups', array('id'=>$groupid));
8bdc9cac
SH
355
356 // Delete all files associated with this group
70e0f41e 357 $context = get_context_instance(CONTEXT_COURSE, $group->courseid);
8bdc9cac 358 $fs = get_file_storage();
e88dd876
PS
359 $fs->delete_area_files($context->id, 'group', 'description', $groupid);
360 $fs->delete_area_files($context->id, 'group', 'icon', $groupid);
8bdc9cac 361
b25263ff 362 //trigger groups events
363 events_trigger('groups_group_deleted', $group);
2942a5cd 364
b25263ff 365 return true;
ddff2fa8 366}
367
f16fa0a3 368/**
369 * Delete grouping
4d8e2417 370 *
16ef46e7 371 * @param int $groupingorid
f16fa0a3 372 * @return bool success
373 */
2942a5cd 374function groups_delete_grouping($groupingorid) {
dfdaabd6 375 global $DB;
376
2942a5cd 377 if (is_object($groupingorid)) {
378 $groupingid = $groupingorid->id;
379 $grouping = $groupingorid;
380 } else {
381 $groupingid = $groupingorid;
382 if (!$grouping = $DB->get_record('groupings', array('id'=>$groupingorid))) {
9a0df45a 383 //silently ignore attempts to delete missing already deleted groupings ;-)
384 return true;
2942a5cd 385 }
ddff2fa8 386 }
387
388 //first delete usage in groupings_groups
dfdaabd6 389 $DB->delete_records('groupings_groups', array('groupingid'=>$groupingid));
ddff2fa8 390 // remove the default groupingid from course
dfdaabd6 391 $DB->set_field('course', 'defaultgroupingid', 0, array('defaultgroupingid'=>$groupingid));
ddff2fa8 392 // remove the groupingid from all course modules
dfdaabd6 393 $DB->set_field('course_modules', 'groupingid', 0, array('groupingid'=>$groupingid));
ddff2fa8 394 //group itself last
b25263ff 395 $DB->delete_records('groupings', array('id'=>$groupingid));
8bdc9cac 396
70e0f41e 397 $context = get_context_instance(CONTEXT_COURSE, $grouping->courseid);
8bdc9cac 398 $fs = get_file_storage();
64f93798 399 $files = $fs->get_area_files($context->id, 'grouping', 'description', $groupingid);
8bdc9cac
SH
400 foreach ($files as $file) {
401 $file->delete();
402 }
403
b25263ff 404 //trigger groups events
405 events_trigger('groups_grouping_deleted', $grouping);
2942a5cd 406
b25263ff 407 return true;
ddff2fa8 408}
409
f16fa0a3 410/**
ffc670d9 411 * Remove all users (or one user) from all groups in course
4d8e2417 412 *
f16fa0a3 413 * @param int $courseid
ffc670d9 414 * @param int $userid 0 means all users
f16fa0a3 415 * @param bool $showfeedback
416 * @return bool success
417 */
ffc670d9 418function groups_delete_group_members($courseid, $userid=0, $showfeedback=false) {
a1c54f7a 419 global $DB, $OUTPUT;
ddff2fa8 420
ffc670d9 421 if (is_bool($userid)) {
422 debugging('Incorrect userid function parameter');
423 return false;
424 }
425
426 $params = array('courseid'=>$courseid);
427
428 if ($userid) {
429 $usersql = "AND userid = :userid";
430 $params['userid'] = $userid;
431 } else {
432 $usersql = "";
433 }
434
435 $groupssql = "SELECT id FROM {groups} g WHERE g.courseid = :courseid";
436 $DB->delete_records_select('groups_members', "groupid IN ($groupssql) $usersql", $params);
ddff2fa8 437
2942a5cd 438 //trigger groups events
ace9051c 439 $eventdata = new stdClass();
ffc670d9 440 $eventdata->courseid = $courseid;
441 $eventdata->userid = $userid;
442 events_trigger('groups_members_removed', $eventdata);
2942a5cd 443
ddff2fa8 444 if ($showfeedback) {
16ef46e7 445 echo $OUTPUT->notification(get_string('deleted').' - '.get_string('groupmembers', 'group'), 'notifysuccess');
ddff2fa8 446 }
447
448 return true;
449}
450
0b5a80a1 451/**
452 * Remove all groups from all groupings in course
4d8e2417 453 *
0b5a80a1 454 * @param int $courseid
455 * @param bool $showfeedback
456 * @return bool success
457 */
458function groups_delete_groupings_groups($courseid, $showfeedback=false) {
a1c54f7a 459 global $DB, $OUTPUT;
0b5a80a1 460
dfdaabd6 461 $groupssql = "SELECT id FROM {groups} g WHERE g.courseid = ?";
462 $DB->delete_records_select('groupings_groups', "groupid IN ($groupssql)", array($courseid));
0b5a80a1 463
2942a5cd 464 //trigger groups events
465 events_trigger('groups_groupings_groups_removed', $courseid);
466
16ef46e7 467 // no need to show any feedback here - we delete usually first groupings and then groups
0b5a80a1 468
469 return true;
470}
471
f16fa0a3 472/**
473 * Delete all groups from course
4d8e2417 474 *
f16fa0a3 475 * @param int $courseid
476 * @param bool $showfeedback
477 * @return bool success
478 */
ddff2fa8 479function groups_delete_groups($courseid, $showfeedback=false) {
a1c54f7a 480 global $CFG, $DB, $OUTPUT;
ddff2fa8 481
0b5a80a1 482 // delete any uses of groups
8bdc9cac 483 // Any associated files are deleted as part of groups_delete_groupings_groups
0b5a80a1 484 groups_delete_groupings_groups($courseid, $showfeedback);
ffc670d9 485 groups_delete_group_members($courseid, 0, $showfeedback);
ddff2fa8 486
d08787af
PS
487 // delete group pictures and descriptions
488 $context = get_context_instance(CONTEXT_COURSE, $courseid);
489 $fs = get_file_storage();
490 $fs->delete_area_files($context->id, 'group');
ddff2fa8 491
0b5a80a1 492 // delete group calendar events
dfdaabd6 493 $groupssql = "SELECT id FROM {groups} g WHERE g.courseid = ?";
494 $DB->delete_records_select('event', "groupid IN ($groupssql)", array($courseid));
0b5a80a1 495
64f93798
PS
496 $context = get_context_instance(CONTEXT_COURSE, $courseid);
497 $fs = get_file_storage();
498 $fs->delete_area_files($context->id, 'group');
499
dfdaabd6 500 $DB->delete_records('groups', array('courseid'=>$courseid));
2942a5cd 501
16ef46e7 502 // trigger groups events
2942a5cd 503 events_trigger('groups_groups_deleted', $courseid);
504
ddff2fa8 505 if ($showfeedback) {
16ef46e7 506 echo $OUTPUT->notification(get_string('deleted').' - '.get_string('groups', 'group'), 'notifysuccess');
ddff2fa8 507 }
508
509 return true;
510}
511
f16fa0a3 512/**
513 * Delete all groupings from course
4d8e2417 514 *
f16fa0a3 515 * @param int $courseid
516 * @param bool $showfeedback
517 * @return bool success
518 */
ddff2fa8 519function groups_delete_groupings($courseid, $showfeedback=false) {
a1c54f7a 520 global $DB, $OUTPUT;
ddff2fa8 521
522 // delete any uses of groupings
dfdaabd6 523 $sql = "DELETE FROM {groupings_groups}
524 WHERE groupingid in (SELECT id FROM {groupings} g WHERE g.courseid = ?)";
525 $DB->execute($sql, array($courseid));
ddff2fa8 526
527 // remove the default groupingid from course
dfdaabd6 528 $DB->set_field('course', 'defaultgroupingid', 0, array('id'=>$courseid));
ddff2fa8 529 // remove the groupingid from all course modules
dfdaabd6 530 $DB->set_field('course_modules', 'groupingid', 0, array('course'=>$courseid));
ddff2fa8 531
8bdc9cac 532 // Delete all files associated with groupings for this course
70e0f41e 533 $context = get_context_instance(CONTEXT_COURSE, $courseid);
8bdc9cac 534 $fs = get_file_storage();
64f93798
PS
535 $fs->delete_area_files($context->id, 'grouping');
536
537 $DB->delete_records('groupings', array('courseid'=>$courseid));
8bdc9cac 538
16ef46e7 539 // trigger groups events
2942a5cd 540 events_trigger('groups_groupings_deleted', $courseid);
541
ddff2fa8 542 if ($showfeedback) {
16ef46e7 543 echo $OUTPUT->notification(get_string('deleted').' - '.get_string('groupings', 'group'), 'notifysuccess');
ddff2fa8 544 }
545
546 return true;
547}
548
549/* =================================== */
550/* various functions used by groups UI */
551/* =================================== */
552
e254aa34 553/**
554 * Obtains a list of the possible roles that group members might come from,
df997f84 555 * on a course. Generally this includes only profile roles.
4d8e2417
AG
556 *
557 * @param context $context Context of course
e254aa34 558 * @return Array of role ID integers, or false if error/none.
559 */
560function groups_get_possible_roles($context) {
df997f84
PS
561 $roles = get_profile_roles($context);
562 return array_keys($roles);
acf000b0 563}
564
565
566/**
567 * Gets potential group members for grouping
4d8e2417 568 *
acf000b0 569 * @param int $courseid The id of the course
570 * @param int $roleid The role to select users from
92343cd2 571 * @param int $cohortid restrict to cohort id
64fa9aa7 572 * @param string $orderby The column to sort users by
acf000b0 573 * @return array An array of the users
574 */
92343cd2 575function groups_get_potential_members($courseid, $roleid = null, $cohortid = null, $orderby = 'lastname ASC, firstname ASC') {
4454447d 576 global $DB;
f16fa0a3 577
acf000b0 578 $context = get_context_instance(CONTEXT_COURSE, $courseid);
acf000b0 579
580 // we are looking for all users with this role assigned in this context or higher
4f0c2d00 581 $listofcontexts = get_related_contexts_string($context);
f16fa0a3 582
4f0c2d00 583 list($esql, $params) = get_enrolled_sql($context);
64f93798 584
acf000b0 585 if ($roleid) {
dfdaabd6 586 $params['roleid'] = $roleid;
4f0c2d00
PS
587 $where = "WHERE u.id IN (SELECT userid
588 FROM {role_assignments}
589 WHERE roleid = :roleid AND contextid $listofcontexts)";
acf000b0 590 } else {
4f0c2d00 591 $where = "";
acf000b0 592 }
f16fa0a3 593
92343cd2 594 if ($cohortid) {
d490ca81
PS
595 $cohortjoin = "JOIN {cohort_members} cm ON (cm.userid = u.id AND cm.cohortid = :cohortid)";
596 $params['cohortid'] = $cohortid;
92343cd2
PS
597 } else {
598 $cohortjoin = "";
599 }
600
dfdaabd6 601 $sql = "SELECT u.id, u.username, u.firstname, u.lastname, u.idnumber
602 FROM {user} u
4f0c2d00 603 JOIN ($esql) e ON e.id = u.id
92343cd2 604 $cohortjoin
4f0c2d00 605 $where
dfdaabd6 606 ORDER BY $orderby";
f16fa0a3 607
dfdaabd6 608 return $DB->get_records_sql($sql, $params);
f16fa0a3 609
acf000b0 610}
f3f7610c 611
acf000b0 612/**
613 * Parse a group name for characters to replace
4d8e2417 614 *
acf000b0 615 * @param string $format The format a group name will follow
616 * @param int $groupnumber The number of the group to be used in the parsed format string
617 * @return string the parsed format string
618 */
619function groups_parse_name($format, $groupnumber) {
acf000b0 620 if (strstr($format, '@') !== false) { // Convert $groupnumber to a character series
f16fa0a3 621 $letter = 'A';
622 for($i=0; $i<$groupnumber; $i++) {
623 $letter++;
acf000b0 624 }
f16fa0a3 625 $str = str_replace('@', $letter, $format);
acf000b0 626 } else {
4454447d 627 $str = str_replace('#', $groupnumber+1, $format);
acf000b0 628 }
629 return($str);
ddff2fa8 630}
f3f7610c 631
f16fa0a3 632/**
633 * Assigns group into grouping
4d8e2417 634 *
f16fa0a3 635 * @param int groupingid
636 * @param int groupid
b25263ff 637 * @return bool true or exception
f16fa0a3 638 */
639function groups_assign_grouping($groupingid, $groupid) {
dfdaabd6 640 global $DB;
641
642 if ($DB->record_exists('groupings_groups', array('groupingid'=>$groupingid, 'groupid'=>$groupid))) {
f16fa0a3 643 return true;
644 }
ace9051c 645 $assign = new stdClass();
f16fa0a3 646 $assign->groupingid = $groupingid;
dfdaabd6 647 $assign->groupid = $groupid;
648 $assign->timeadded = time();
b25263ff 649 $DB->insert_record('groupings_groups', $assign);
650
651 return true;
f16fa0a3 652}
653
654/**
655 * Unassigns group grom grouping
4d8e2417 656 *
f16fa0a3 657 * @param int groupingid
658 * @param int groupid
659 * @return bool success
660 */
661function groups_unassign_grouping($groupingid, $groupid) {
dfdaabd6 662 global $DB;
b25263ff 663 $DB->delete_records('groupings_groups', array('groupingid'=>$groupingid, 'groupid'=>$groupid));
dfdaabd6 664
b25263ff 665 return true;
f16fa0a3 666}
667
e254aa34 668/**
669 * Lists users in a group based on their role on the course.
6f5e0852 670 * Returns false if there's an error or there are no users in the group.
e254aa34 671 * Otherwise returns an array of role ID => role data, where role data includes:
672 * (role) $id, $shortname, $name
673 * $users: array of objects for each user which include the specified fields
674 * Users who do not have a role are stored in the returned array with key '-'
675 * and pseudo-role details (including a name, 'No role'). Users with multiple
676 * roles, same deal with key '*' and name 'Multiple roles'. You can find out
677 * which roles each has by looking in the $roles array of the user object.
4d8e2417 678 *
e254aa34 679 * @param int $groupid
680 * @param int $courseid Course ID (should match the group's course)
681 * @param string $fields List of fields from user table prefixed with u, default 'u.*'
682 * @param string $sort SQL ORDER BY clause, default 'u.lastname ASC'
97873016 683 * @param string $extrawheretest extra SQL conditions ANDed with the existing where clause.
4f0c2d00 684 * @param array $whereparams any parameters required by $extrawheretest (named parameters).
e254aa34 685 * @return array Complex array as described above
686 */
97873016 687function groups_get_members_by_role($groupid, $courseid, $fields='u.*',
688 $sort='u.lastname ASC', $extrawheretest='', $whereparams=array()) {
dfdaabd6 689 global $CFG, $DB;
e254aa34 690
691 // Retrieve information about all users and their roles on the course or
6f5e0852 692 // parent ('related') contexts
dfdaabd6 693 $context = get_context_instance(CONTEXT_COURSE, $courseid);
694
97873016 695 if ($extrawheretest) {
696 $extrawheretest = ' AND ' . $extrawheretest;
697 }
698
dfdaabd6 699 $sql = "SELECT r.id AS roleid, r.shortname AS roleshortname, r.name AS rolename,
700 u.id AS userid, $fields
701 FROM {groups_members} gm
702 JOIN {user} u ON u.id = gm.userid
1c7a2f84
PS
703 LEFT JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.contextid ".get_related_contexts_string($context).")
704 LEFT JOIN {role} r ON r.id = ra.roleid
4f0c2d00 705 WHERE gm.groupid=:mgroupid
1c7a2f84 706 ".$extrawheretest."
dfdaabd6 707 ORDER BY r.sortorder, $sort";
4f0c2d00 708 $whereparams['mgroupid'] = $groupid;
97873016 709 $rs = $DB->get_recordset_sql($sql, $whereparams);
dfdaabd6 710
711 return groups_calculate_role_people($rs, $context);
e254aa34 712}
713
714/**
715 * Internal function used by groups_get_members_by_role to handle the
716 * results of a database query that includes a list of users and possible
717 * roles on a course.
718 *
4d8e2417
AG
719 * @param moodle_recordset $rs The record set (may be false)
720 * @param int $context ID of course context
6f5e0852 721 * @return array As described in groups_get_members_by_role
e254aa34 722 */
dfdaabd6 723function groups_calculate_role_people($rs, $context) {
724 global $CFG, $DB;
725
726 if (!$rs) {
727 return array();
3540f2b3 728 }
e254aa34 729
dfdaabd6 730 $roles = $DB->get_records_menu('role', null, 'name', 'id, name');
731 $aliasnames = role_fix_names($roles, $context);
732
e254aa34 733 // Array of all involved roles
dfdaabd6 734 $roles = array();
e254aa34 735 // Array of all retrieved users
dfdaabd6 736 $users = array();
e254aa34 737 // Fill arrays
dfdaabd6 738 foreach ($rs as $rec) {
e254aa34 739 // Create information about user if this is a new one
dfdaabd6 740 if (!array_key_exists($rec->userid, $users)) {
e254aa34 741 // User data includes all the optional fields, but not any of the
742 // stuff we added to get the role details
1c7a2f84 743 $userdata = clone($rec);
e254aa34 744 unset($userdata->roleid);
745 unset($userdata->roleshortname);
746 unset($userdata->rolename);
747 unset($userdata->userid);
dfdaabd6 748 $userdata->id = $rec->userid;
e254aa34 749
750 // Make an array to hold the list of roles for this user
dfdaabd6 751 $userdata->roles = array();
752 $users[$rec->userid] = $userdata;
e254aa34 753 }
754 // If user has a role...
dfdaabd6 755 if (!is_null($rec->roleid)) {
e254aa34 756 // Create information about role if this is a new one
dfdaabd6 757 if (!array_key_exists($rec->roleid,$roles)) {
ace9051c 758 $roledata = new stdClass();
dfdaabd6 759 $roledata->id = $rec->roleid;
760 $roledata->shortname = $rec->roleshortname;
761 if (array_key_exists($rec->roleid, $aliasnames)) {
762 $roledata->name = $aliasnames[$rec->roleid];
3540f2b3 763 } else {
dfdaabd6 764 $roledata->name = $rec->rolename;
3540f2b3 765 }
dfdaabd6 766 $roledata->users = array();
767 $roles[$roledata->id] = $roledata;
e254aa34 768 }
769 // Record that user has role
770 $users[$rec->userid]->roles[] = $roles[$rec->roleid];
771 }
772 }
dfdaabd6 773 $rs->close();
e254aa34 774
775 // Return false if there weren't any users
1c7a2f84 776 if (count($users) == 0) {
e254aa34 777 return false;
778 }
779
780 // Add pseudo-role for multiple roles
ace9051c 781 $roledata = new stdClass();
dfdaabd6 782 $roledata->name = get_string('multipleroles','role');
783 $roledata->users = array();
784 $roles['*'] = $roledata;
e254aa34 785
1c7a2f84
PS
786 $roledata = new stdClass();
787 $roledata->name = get_string('noroles','role');
788 $roledata->users = array();
789 $roles[0] = $roledata;
790
e254aa34 791 // Now we rearrange the data to store users by role
dfdaabd6 792 foreach ($users as $userid=>$userdata) {
793 $rolecount = count($userdata->roles);
1c7a2f84
PS
794 if ($rolecount == 0) {
795 // does not have any roles
796 $roleid = 0;
797 } else if($rolecount > 1) {
dfdaabd6 798 $roleid = '*';
e254aa34 799 } else {
dfdaabd6 800 $roleid = $userdata->roles[0]->id;
e254aa34 801 }
dfdaabd6 802 $roles[$roleid]->users[$userid] = $userdata;
e254aa34 803 }
804
805 // Delete roles not used
dfdaabd6 806 foreach ($roles as $key=>$roledata) {
807 if (count($roledata->users)===0) {
e254aa34 808 unset($roles[$key]);
809 }
810 }
811
812 // Return list of roles containing their users
813 return $roles;
814}