MDL-11462 fixed PARAM_URL inline focs, uncommented old regex in URL validation librar...
[moodle.git] / lib / grouplib.php
CommitLineData
2c386f82 1<?php //$Id$
2
13534ef7 3/**
ffc536af 4 * Groups not used in course or activity
13534ef7
ML
5 */
6define('NOGROUPS', 0);
7
8/**
ffc536af 9 * Groups used, users do not see other groups
13534ef7
ML
10 */
11define('SEPARATEGROUPS', 1);
5bf243d1 12
5bf243d1 13/**
ffc536af 14 * Groups used, students see other groups
13534ef7
ML
15 */
16define('VISIBLEGROUPS', 2);
17
18
19/**
20 * Determines if a group with a given groupid exists.
5bf243d1 21 * @param int $groupid The groupid to check for
13534ef7
ML
22 * @return boolean True if the group exists, false otherwise or if an error
23 * occurred.
5bf243d1 24 */
25function groups_group_exists($groupid) {
26 return record_exists('groups', 'id', $groupid);
27}
28
29/**
30 * Gets the name of a group with a specified id
31 * @param int $groupid The id of the group
32 * @return string The name of the group
33 */
34function groups_get_group_name($groupid) {
35 return get_field('groups', 'name', 'id', $groupid);
36}
2c386f82 37
4d8e3407 38/**
39 * Gets the name of a grouping with a specified id
40 * @param int $groupingid The id of the grouping
41 * @return string The name of the grouping
42 */
43function groups_get_grouping_name($groupingid) {
44 return get_field('groupings', 'name', 'id', $groupingid);
45}
46
2c386f82 47/**
48 * Returns the groupid of a group with the name specified for the course.
49 * Group names should be unique in course
50 * @param int $courseid The id of the course
51 * @param string $name name of group (without magic quotes)
52 * @return int $groupid
53 */
54function groups_get_group_by_name($courseid, $name) {
ddff2fa8 55 if ($groups = get_records_select('groups', "courseid=$courseid AND name='".addslashes($name)."'")) {
56 return key($groups);
2c386f82 57 }
ddff2fa8 58 return false;
59}
2c386f82 60
ddff2fa8 61/**
62 * Returns the groupingid of a grouping with the name specified for the course.
63 * Grouping names should be unique in course
64 * @param int $courseid The id of the course
65 * @param string $name name of group (without magic quotes)
66 * @return int $groupid
67 */
68function groups_get_grouping_by_name($courseid, $name) {
69 if ($groupings = get_records_select('groupings', "courseid=$courseid AND name='".addslashes($name)."'")) {
70 return key($groupings);
71 }
72 return false;
2c386f82 73}
74
75/**
76 * Get the group object
77 * @param groupid ID of the group.
78 * @return group object
79 */
80function groups_get_group($groupid) {
81 return get_record('groups', 'id', $groupid);
82}
83
84/**
85 * Gets array of all groups in a specified course.
86 * @param int $courseid The id of the course.
87 * @param int $userid optional user id, returns only groups of the user.
62d63838 88 * @param int $groupingid optional returns only groups in the specified grouping.
d15da061 89 * @return array | false Returns an array of the group objects or false if no records
2c386f82 90 * or an error occurred.
91 */
62d63838 92function groups_get_all_groups($courseid, $userid=0, $groupingid=0) {
2c386f82 93 global $CFG;
94
7e4fdf25 95 // groupings are ignored when not enabled
c0d4238d 96 if (empty($CFG->enablegroupings)) {
97 $groupingid = 0;
98 }
99
62d63838 100 if (!empty($userid)) {
101 $userfrom = ", {$CFG->prefix}groups_members gm";
102 $userwhere = "AND g.id = gm.groupid AND gm.userid = '$userid'";
103 } else {
104 $userfrom = "";
105 $userwhere = "";
106 }
2c386f82 107
62d63838 108 if (!empty($groupingid)) {
109 $groupingfrom = ", {$CFG->prefix}groupings_groups gg";
110 $groupingwhere = "AND g.id = gg.groupid AND gg.groupingid = '$groupingid'";
2c386f82 111 } else {
62d63838 112 $groupingfrom = "";
113 $groupingwhere = "";
2c386f82 114 }
62d63838 115
116 return get_records_sql("SELECT g.*
117 FROM {$CFG->prefix}groups g $userfrom $groupingfrom
acf000b0 118 WHERE g.courseid = $courseid $userwhere $groupingwhere
62d63838 119 ORDER BY name ASC");
2c386f82 120}
121
acf000b0 122/**
123 * Gets array of all groupings in a specified course.
18d43e96 124 * @param int $courseid return only groupings in this with this courseid
125 * @return array | false Returns an array of the grouping objects or false if no records
acf000b0 126 * or an error occurred.
127 */
128function groups_get_all_groupings($courseid) {
129 global $CFG;
130
131 // groupings are ignored when not enabled
132 if (empty($CFG->enablegroupings)) {
133 return(false);
134 }
135 return get_records_sql("SELECT *
136 FROM {$CFG->prefix}groupings
137 WHERE courseid = $courseid
138 ORDER BY name ASC");
139}
140
141
142
2c386f82 143/**
144 * Determines if the user is a member of the given group.
145 *
146 * @uses $USER If $userid is null, use the global object.
147 * @param int $groupid The group to check for membership.
148 * @param int $userid The user to check against the group.
149 * @return boolean True if the user is a member, false otherwise.
150 */
151function groups_is_member($groupid, $userid=null) {
152 global $USER;
153
154 if (!$userid) {
155 $userid = $USER->id;
156 }
157
158 return record_exists('groups_members', 'groupid', $groupid, 'userid', $userid);
159}
160
f8e3d5f0 161/**
162 * Determines if current or specified is member of any active group in activity
163 * @param object $cm coruse module object
164 * @param int $userid id of user, null menas $USER->id
165 * @return booelan true if user member of at least one group used in activity
166 */
167function groups_has_membership($cm, $userid=null) {
168 global $CFG, $USER;
e0bc99e4 169
170 static $cache = array();
171
7e4fdf25 172 // groupings are ignored when not enabled
c0d4238d 173 if (empty($CFG->enablegroupings)) {
174 $cm->groupingid = 0;
175 }
176
f8e3d5f0 177 if (empty($userid)) {
178 $userid = $USER->id;
179 }
180
e0bc99e4 181 $cachekey = $userid.'|'.$cm->course.'|'.$cm->groupingid;
182 if (isset($cache[$cachekey])) {
183 return($cache[$cachekey]);
184 }
185
f8e3d5f0 186 if ($cm->groupingid) {
187 // find out if member of any group in selected activity grouping
188 $sql = "SELECT 'x'
189 FROM {$CFG->prefix}groups_members gm, {$CFG->prefix}groupings_groups gg
190 WHERE gm.userid = $userid AND gm.groupid = gg.groupid AND gg.groupingid = {$cm->groupingid}";
191
192 } else {
193 // no grouping used - check all groups in course
194 $sql = "SELECT 'x'
195 FROM {$CFG->prefix}groups_members gm, {$CFG->prefix}groups g
196 WHERE gm.userid = $userid AND gm.groupid = g.id AND g.courseid = {$cm->course}";
197 }
e0bc99e4 198
199 $cache[$cachekey] = record_exists_sql($sql);
200
201 return $cache[$cachekey];
f8e3d5f0 202}
203
62d63838 204/**
205 * Returns the users in the specified group.
206 * @param int $groupid The groupid to get the users for
e6839677 207 * @param int $fields The fields to return
62d63838 208 * @param int $sort optional sorting of returned users
209 * @return array | false Returns an array of the users for the specified
210 * group or false if no users or an error returned.
211 */
e6839677 212function groups_get_members($groupid, $fields='u.*', $sort='lastname ASC') {
62d63838 213 global $CFG;
214
e6839677 215 return get_records_sql("SELECT $fields
62d63838 216 FROM {$CFG->prefix}user u, {$CFG->prefix}groups_members gm
217 WHERE u.id = gm.userid AND gm.groupid = '$groupid'
218 ORDER BY $sort");
219}
220
e6839677 221
222/**
223 * Returns the users in the specified grouping.
224 * @param int $groupingid The groupingid to get the users for
225 * @param int $fields The fields to return
226 * @param int $sort optional sorting of returned users
227 * @return array | false Returns an array of the users for the specified
228 * group or false if no users or an error returned.
229 */
230function groups_get_grouping_members($groupingid, $fields='u.*', $sort='lastname ASC') {
231 global $CFG;
232
233 return get_records_sql("SELECT $fields
234 FROM {$CFG->prefix}user u
235 INNER JOIN {$CFG->prefix}groups_members gm ON u.id = gm.userid
236 INNER JOIN {$CFG->prefix}groupings_groups gg ON gm.groupid = gg.groupid
237 WHERE gg.groupingid = $groupingid
238 ORDER BY $sort");
239}
240
b2bc96d1 241/**
242 * Returns effective groupmode used in course
243 * @return integer group mode
244 */
245function groups_get_course_groupmode($course) {
246 return $course->groupmode;
247}
248
13534ef7
ML
249/**
250 * Returns effective groupmode used in activity, course setting
251 * overrides activity setting if groupmodeforce enabled.
252 * @return integer group mode
253 */
254function groups_get_activity_groupmode($cm) {
255 global $COURSE;
256
257 // get course object (reuse COURSE if possible)
258 if ($cm->course == $COURSE->id) {
259 $course = $COURSE;
260 } else {
261 if (!$course = get_record('course', 'id', $cm->course)) {
262 error('Incorrect course id in cm');
263 }
264 }
265
266 return empty($course->groupmodeforce) ? $cm->groupmode : $course->groupmode;
267}
268
b2bc96d1 269/**
270 * Print group menu selector for course level.
271 * @param object $course course object
272 * @param string $urlroot return address
273 * @param boolean $return return as string instead of printing
274 * @return mixed void or string depending on $return param
275 */
276function groups_print_course_menu($course, $urlroot, $return=false) {
277 global $CFG, $USER;
278
279 if (!$groupmode = $course->groupmode) {
280 if ($return) {
281 return '';
282 } else {
283 return;
284 }
285 }
286
287 $context = get_context_instance(CONTEXT_COURSE, $course->id);
288 if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $context)) {
289 $allowedgroups = groups_get_all_groups($course->id, 0);
290 } else {
291 $allowedgroups = groups_get_all_groups($course->id, $USER->id);
292 }
293
294 $activegroup = groups_get_course_group($course, true);
295
296 $groupsmenu = array();
297 if (!$allowedgroups or $groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $context)) {
298 $groupsmenu[0] = get_string('allparticipants');
299 }
300
301 if ($allowedgroups) {
302 foreach ($allowedgroups as $group) {
303 $groupsmenu[$group->id] = format_string($group->name);
304 }
305 }
306
307 if ($groupmode == VISIBLEGROUPS) {
308 $grouplabel = get_string('groupsvisible');
309 } else {
310 $grouplabel = get_string('groupsseparate');
311 }
312
313 if (count($groupsmenu) == 1) {
314 $groupname = reset($groupsmenu);
315 $output = $grouplabel.': '.$groupname;
316 } else {
317 $output = popup_form($urlroot.'&amp;group=', $groupsmenu, 'selectgroup', $activegroup, '', '', '', true, 'self', $grouplabel);
318 }
319
320 $output = '<div class="groupselector">'.$output.'</div>';
321
322 if ($return) {
323 return $output;
324 } else {
325 echo $output;
326 }
327}
328
13534ef7
ML
329/**
330 * Print group menu selector for activity.
331 * @param object $cm course module object
18d43e96 332 * @param string $urlroot return address that users get to if they choose an option;
333 * should include any parameters needed, e.g. 'view.php?id=34'
13534ef7 334 * @param boolean $return return as string instead of printing
18d43e96 335 * @param boolean $hideallparticipants If true, this prevents the 'All participants'
336 * option from appearing in cases where it normally would. This is intended for
337 * use only by activities that cannot display all groups together. (Note that
338 * selecting this option does not prevent groups_get_activity_group from
339 * returning 0; it will still do that if the user has chosen 'all participants'
340 * in another activity, or not chosen anything.)
13534ef7
ML
341 * @return mixed void or string depending on $return param
342 */
18d43e96 343function groups_print_activity_menu($cm, $urlroot, $return=false, $hideallparticipants=false) {
c0d4238d 344 global $CFG, $USER;
345
7e4fdf25 346 // groupings are ignored when not enabled
c0d4238d 347 if (empty($CFG->enablegroupings)) {
348 $cm->groupingid = 0;
349 }
13534ef7
ML
350
351 if (!$groupmode = groups_get_activity_groupmode($cm)) {
352 if ($return) {
353 return '';
354 } else {
355 return;
356 }
357 }
358
359 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
360 if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $context)) {
361 $allowedgroups = groups_get_all_groups($cm->course, 0, $cm->groupingid); // any group in grouping (all if groupings not used)
362 } else {
363 $allowedgroups = groups_get_all_groups($cm->course, $USER->id, $cm->groupingid); // only assigned groups
364 }
365
366 $activegroup = groups_get_activity_group($cm, true);
367
368 $groupsmenu = array();
18d43e96 369 if ((!$allowedgroups or $groupmode == VISIBLEGROUPS or
370 has_capability('moodle/site:accessallgroups', $context)) and !$hideallparticipants) {
13534ef7
ML
371 $groupsmenu[0] = get_string('allparticipants');
372 }
373
374 if ($allowedgroups) {
375 foreach ($allowedgroups as $group) {
376 $groupsmenu[$group->id] = format_string($group->name);
377 }
378 }
379
380 if ($groupmode == VISIBLEGROUPS) {
381 $grouplabel = get_string('groupsvisible');
382 } else {
383 $grouplabel = get_string('groupsseparate');
384 }
385
386 if (count($groupsmenu) == 1) {
387 $groupname = reset($groupsmenu);
388 $output = $grouplabel.': '.$groupname;
389 } else {
390 $output = popup_form($urlroot.'&amp;group=', $groupsmenu, 'selectgroup', $activegroup, '', '', '', true, 'self', $grouplabel);
391 }
392
393 $output = '<div class="groupselector">'.$output.'</div>';
394
395 if ($return) {
396 return $output;
397 } else {
398 echo $output;
399 }
400}
401
b2bc96d1 402/**
403 * Returns group active in course, changes the group by default if 'group' page param present
404 *
405 * @param object $course course bject
406 * @param boolean $update change active group if group param submitted
407 * @return mixed false if groups not used, int if groups used, 0 means all groups (access must be verified in SEPARATE mode)
408 */
409function groups_get_course_group($course, $update=false) {
410 global $CFG, $USER, $SESSION;
411
412 if (!$groupmode = $course->groupmode) {
413 // NOGROUPS used
414 return false;
415 }
416
417 // init activegroup array
418 if (!array_key_exists('activegroup', $SESSION)) {
419 $SESSION->activegroup = array();
420 }
421 if (!array_key_exists($course->id, $SESSION->activegroup)) {
422 $SESSION->activegroup[$course->id] = array(SEPARATEGROUPS=>array(), VISIBLEGROUPS=>array());
423 }
424
425 // grouping used the first time - add first user group as default
426 if (!array_key_exists(0, $SESSION->activegroup[$course->id][$groupmode])) {
427 if ($usergroups = groups_get_all_groups($course->id, $USER->id, 0)) {
428 $fistgroup = reset($usergroups);
429 $SESSION->activegroup[$course->id][$groupmode][0] = $fistgroup->id;
430 } else {
431 // this happen when user not assigned into group in SEPARATEGROUPS mode or groups do not exist yet
432 // mod authors must add extra checks for this when SEPARATEGROUPS mode used (such as when posting to forum)
433 $SESSION->activegroup[$course->id][$groupmode][0] = 0;
434 }
435 }
436
437 // set new active group if requested
438 $changegroup = optional_param('group', -1, PARAM_INT);
439 if ($update and $changegroup != -1) {
440 $context = get_context_instance(CONTEXT_COURSE, $course->id);
441
442 if ($changegroup == 0) {
443 // do not allow changing to all groups without accessallgroups capability
444 if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $context)) {
445 $SESSION->activegroup[$course->id][$groupmode][0] = 0;
446 }
447
448 } else {
449 // first make list of allowed groups
450 if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $context)) {
451 $allowedgroups = groups_get_all_groups($course->id, 0, 0);
452 } else {
453 $allowedgroups = groups_get_all_groups($course->id, $USER->id, 0);
454 }
455
456 if ($allowedgroups and array_key_exists($changegroup, $allowedgroups)) {
457 $SESSION->activegroup[$course->id][$groupmode][0] = $changegroup;
458 }
459 }
460 }
461
462 return $SESSION->activegroup[$course->id][$groupmode][0];
463}
464
13534ef7
ML
465/**
466 * Returns group active in activity, changes the group by default if 'group' page param present
467 *
468 * @param object $cm course module object
469 * @param boolean $update change active group if group param submitted
470 * @return mixed false if groups not used, int if groups used, 0 means all groups (access must be verified in SEPARATE mode)
471 */
472function groups_get_activity_group($cm, $update=false) {
c0d4238d 473 global $CFG, $USER, $SESSION;
474
7e4fdf25 475 // groupings are ignored when not enabled
c0d4238d 476 if (empty($CFG->enablegroupings)) {
477 $cm->groupingid = 0;
478 }
13534ef7
ML
479
480 if (!$groupmode = groups_get_activity_groupmode($cm)) {
481 // NOGROUPS used
482 return false;
483 }
484
b2bc96d1 485 // init activegroup array
13534ef7
ML
486 if (!array_key_exists('activegroup', $SESSION)) {
487 $SESSION->activegroup = array();
488 }
489 if (!array_key_exists($cm->course, $SESSION->activegroup)) {
490 $SESSION->activegroup[$cm->course] = array(SEPARATEGROUPS=>array(), VISIBLEGROUPS=>array());
491 }
492
493 // grouping used the first time - add first user group as default
494 if (!array_key_exists($cm->groupingid, $SESSION->activegroup[$cm->course][$groupmode])) {
495 if ($usergroups = groups_get_all_groups($cm->course, $USER->id, $cm->groupingid)) {
496 $fistgroup = reset($usergroups);
497 $SESSION->activegroup[$cm->course][$groupmode][$cm->groupingid] = $fistgroup->id;
498 } else {
499 // this happen when user not assigned into group in SEPARATEGROUPS mode or groups do not exist yet
500 // mod authors must add extra checks for this when SEPARATEGROUPS mode used (such as when posting to forum)
501 $SESSION->activegroup[$cm->course][$groupmode][$cm->groupingid] = 0;
502 }
503 }
504
505 // set new active group if requested
506 $changegroup = optional_param('group', -1, PARAM_INT);
507 if ($update and $changegroup != -1) {
508 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
509
510 if ($changegroup == 0) {
511 // do not allow changing to all groups without accessallgroups capability
512 if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $context)) {
513 $SESSION->activegroup[$cm->course][$groupmode][$cm->groupingid] = 0;
514 }
515
516 } else {
517 // first make list of allowed groups
518 if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $context)) {
519 $allowedgroups = groups_get_all_groups($cm->course, 0, $cm->groupingid); // any group in grouping (all if groupings not used)
520 } else {
521 $allowedgroups = groups_get_all_groups($cm->course, $USER->id, $cm->groupingid); // only assigned groups
522 }
523
524 if ($allowedgroups and array_key_exists($changegroup, $allowedgroups)) {
525 $SESSION->activegroup[$cm->course][$groupmode][$cm->groupingid] = $changegroup;
526 }
527 }
528 }
529
530 return $SESSION->activegroup[$cm->course][$groupmode][$cm->groupingid];
531}
62d63838 532
18d43e96 533/**
534 * Gets a list of groups that the user is allowed to access within the
535 * specified activity.
536 * @param object $cm Course-module
537 * @param int $userid User ID (defaults to current user)
538 * @return array An array of group objects, or false if none
539 */
cdaa9410 540function groups_get_activity_allowed_groups($cm,$userid=0) {
18d43e96 541 // Use current user by default
542 global $USER;
543 if(!$userid) {
544 $userid=$USER->id;
545 }
546
547 // Get groupmode for activity, taking into account course settings
548 $groupmode=groups_get_activity_groupmode($cm);
549
550 // If visible groups mode, or user has the accessallgroups capability,
551 // then they can access all groups for the activity...
552 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
553 if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $context)) {
554 return groups_get_all_groups($cm->course, 0, $cm->groupingid);
555 } else {
556 // ...otherwise they can only access groups they belong to
557 return groups_get_all_groups($cm->course, $userid, $cm->groupingid);
558 }
559}
560
dcd8db68 561/**
562 * Determine if a course module is currently visible to a user
563 * @uses $USER If $userid is null, use the global object.
564 * @param int $cm The course module
565 * @param int $userid The user to check against the group.
566 * @return boolean True if the user can view the course module, false otherwise.
567 */
568function groups_course_module_visible($cm, $userid=null) {
569 global $CFG, $USER;
570
571 if (empty($userid)) {
572 $userid = $USER->id;
573 }
574 if (empty($CFG->enablegroupings)) {
575 return(true);
576 }
577 if (empty($cm->groupmembersonly)) {
578 return(true);
579 }
e0bc99e4 580 if (groups_has_membership($cm, $userid) || has_capability('moodle/site:accessallgroups', get_context_instance(CONTEXT_MODULE, $cm->id), $userid)) {
dcd8db68 581 return(true);
582 }
583 return(false);
584}
585
2c386f82 586?>