Commit | Line | Data |
---|---|---|
f3f7610c ML |
1 | <?php |
2 | /** | |
ddff2fa8 | 3 | * Extra library for groups and groupings. |
f3f7610c ML |
4 | * |
5 | * @copyright © 2006 The Open University | |
6 | * @author J.White AT open.ac.uk | |
7 | * @license http://www.gnu.org/copyleft/gpl.html GNU Public License | |
8 | * @package groups | |
9 | */ | |
10 | ||
ddff2fa8 | 11 | /* |
12 | * INTERNAL FUNCTIONS - to be used by moodle core only | |
13 | * require_once $CFG->dirroot.'/group/lib.php' must be used | |
14 | */ | |
15 | ||
778918fd | 16 | /** |
17 | * Adds a specified user to a group | |
18 | * @param int $userid The user id | |
19 | * @param int $groupid The group id | |
f16fa0a3 | 20 | * @return boolean True if user added successfully or the user is already a |
21 | * member of the group, false otherwise. | |
778918fd | 22 | */ |
23 | function groups_add_member($groupid, $userid) { | |
24 | if (!groups_group_exists($groupid)) { | |
25 | return false; | |
26 | } | |
27 | ||
28 | if (groups_is_member($groupid, $userid)) { | |
29 | return true; | |
30 | } | |
31 | ||
32 | $member = new object(); | |
33 | $member->groupid = $groupid; | |
34 | $member->userid = $userid; | |
35 | $member->timeadded = time(); | |
36 | ||
37 | if (!insert_record('groups_members', $member)) { | |
38 | return false; | |
39 | } | |
40 | ||
41 | //update group info | |
42 | set_field('groups', 'timemodified', $member->timeadded, 'id', $groupid); | |
43 | ||
44 | // MDL-9983 | |
45 | $eventdata = new object(); | |
46 | $eventdata->groupid = $groupid; | |
47 | $eventdata->userid = $userid; | |
f16fa0a3 | 48 | events_trigger('group_user_added', $eventdata); |
778918fd | 49 | |
50 | return true; | |
51 | } | |
52 | ||
53 | /** | |
54 | * Deletes the link between the specified user and group. | |
55 | * @param int $groupid The group to delete the user from | |
56 | * @param int $userid The user to delete | |
57 | * @return boolean True if deletion was successful, false otherwise | |
58 | */ | |
59 | function groups_remove_member($groupid, $userid) { | |
60 | if (!groups_group_exists($groupid)) { | |
61 | return false; | |
62 | } | |
63 | ||
64 | if (!groups_is_member($groupid, $userid)) { | |
65 | return true; | |
66 | } | |
67 | ||
68 | if (!delete_records('groups_members', 'groupid', $groupid, 'userid', $userid)) { | |
69 | return false; | |
f16fa0a3 | 70 | } |
778918fd | 71 | //update group info |
72 | set_field('groups', 'timemodified', time(), 'id', $groupid); | |
73 | ||
74 | return true; | |
75 | } | |
76 | ||
ddff2fa8 | 77 | /** |
78 | * Add a new group | |
f16fa0a3 | 79 | * @param object $data group properties (with magic quotes) |
ddff2fa8 | 80 | * @param object $um upload manager with group picture |
81 | * @return id of group or false if error | |
82 | */ | |
83 | function groups_create_group($data, $um=false) { | |
84 | global $CFG; | |
85 | require_once("$CFG->libdir/gdlib.php"); | |
86 | ||
87 | $data->timecreated = time(); | |
88 | $data->timemodified = $data->timecreated; | |
f16fa0a3 | 89 | $data->name = trim($data->name); |
ddff2fa8 | 90 | $id = insert_record('groups', $data); |
91 | ||
92 | if ($id and $um) { | |
93 | //update image | |
94 | if (save_profile_image($id, $um, 'groups')) { | |
95 | set_field('groups', 'picture', 1, 'id', $id); | |
96 | } | |
97 | } | |
98 | ||
99 | return $id; | |
100 | } | |
101 | ||
102 | /** | |
f16fa0a3 | 103 | * Add a new grouping |
104 | * @param object $data grouping properties (with magic quotes) | |
105 | * @return id of grouping or false if error | |
106 | */ | |
107 | function groups_create_grouping($data) { | |
108 | global $CFG; | |
109 | ||
110 | $data->timecreated = time(); | |
111 | $data->timemodified = $data->timecreated; | |
112 | $data->name = trim($data->name); | |
113 | return insert_record('groupings', $data); | |
114 | } | |
115 | ||
116 | /** | |
117 | * Update group | |
118 | * @param object $data group properties (with magic quotes) | |
ddff2fa8 | 119 | * @param object $um upload manager with group picture |
120 | * @return boolean success | |
121 | */ | |
122 | function groups_update_group($data, $um=false) { | |
123 | global $CFG; | |
124 | require_once("$CFG->libdir/gdlib.php"); | |
125 | ||
126 | $data->timemodified = time(); | |
f16fa0a3 | 127 | $data->name = trim($data->name); |
ddff2fa8 | 128 | $result = update_record('groups', $data); |
129 | ||
130 | if ($result and $um) { | |
131 | //update image | |
132 | if (save_profile_image($data->id, $um, 'groups')) { | |
133 | set_field('groups', 'picture', 1, 'id', $data->id); | |
134 | } | |
135 | } | |
136 | ||
137 | return $result; | |
138 | } | |
139 | ||
f16fa0a3 | 140 | /** |
141 | * Update grouping | |
142 | * @param object $data grouping properties (with magic quotes) | |
143 | * @return boolean success | |
144 | */ | |
145 | function groups_update_grouping($data) { | |
146 | global $CFG; | |
147 | $data->timemodified = time(); | |
148 | $data->name = trim($data->name); | |
149 | return update_record('groupings', $data); | |
150 | } | |
151 | ||
ddff2fa8 | 152 | /** |
153 | * Delete a group best effort, first removing members and links with courses and groupings. | |
154 | * Removes group avatar too. | |
155 | * @param int $groupid The group to delete | |
156 | * @return boolean True if deletion was successful, false otherwise | |
157 | */ | |
158 | function groups_delete_group($groupid) { | |
159 | global $CFG; | |
160 | require_once($CFG->libdir.'/gdlib.php'); | |
161 | ||
162 | if (empty($groupid)) { | |
163 | return false; | |
164 | } | |
165 | ||
0b5a80a1 | 166 | // delete group calendar events |
167 | delete_records('event', 'groupid', $groupid); | |
ddff2fa8 | 168 | //first delete usage in groupings_groups |
169 | delete_records('groupings_groups', 'groupid', $groupid); | |
170 | //delete members | |
171 | delete_records('groups_members', 'groupid', $groupid); | |
172 | //then imge | |
173 | delete_profile_image($groupid, 'groups'); | |
174 | //group itself last | |
175 | return delete_records('groups', 'id', $groupid); | |
176 | } | |
177 | ||
f16fa0a3 | 178 | /** |
179 | * Delete grouping | |
180 | * @param int $groupingid | |
181 | * @return bool success | |
182 | */ | |
ddff2fa8 | 183 | function groups_delete_grouping($groupingid) { |
184 | if (empty($groupingid)) { | |
185 | return false; | |
186 | ||
187 | } | |
188 | ||
189 | //first delete usage in groupings_groups | |
190 | delete_records('groupings_groups', 'groupingid', $groupingid); | |
191 | // remove the default groupingid from course | |
192 | set_field('course', 'defaultgroupingid', 0, 'defaultgroupingid', $groupingid); | |
193 | // remove the groupingid from all course modules | |
194 | set_field('course_modules', 'groupingid', 0, 'groupingid', $groupingid); | |
195 | //group itself last | |
196 | return delete_records('groupings', 'id', $groupingid); | |
197 | } | |
198 | ||
f16fa0a3 | 199 | /** |
0b5a80a1 | 200 | * Remove all users from all groups in course |
f16fa0a3 | 201 | * @param int $courseid |
202 | * @param bool $showfeedback | |
203 | * @return bool success | |
204 | */ | |
ddff2fa8 | 205 | function groups_delete_group_members($courseid, $showfeedback=false) { |
206 | global $CFG; | |
207 | ||
0b5a80a1 | 208 | $groupssql = "SELECT id FROM {$CFG->prefix}groups g WHERE g.courseid = $courseid"; |
209 | delete_records_select('groups_members', "groupid IN ($groupssql)"); | |
ddff2fa8 | 210 | |
ddff2fa8 | 211 | if ($showfeedback) { |
212 | notify(get_string('deleted').' groups_members'); | |
213 | } | |
214 | ||
215 | return true; | |
216 | } | |
217 | ||
0b5a80a1 | 218 | /** |
219 | * Remove all groups from all groupings in course | |
220 | * @param int $courseid | |
221 | * @param bool $showfeedback | |
222 | * @return bool success | |
223 | */ | |
224 | function groups_delete_groupings_groups($courseid, $showfeedback=false) { | |
225 | global $CFG; | |
226 | ||
227 | $groupssql = "SELECT id FROM {$CFG->prefix}groups g WHERE g.courseid = $courseid"; | |
228 | delete_records_select('groupings_groups', "groupid IN ($groupssql)"); | |
229 | ||
230 | if ($showfeedback) { | |
231 | notify(get_string('deleted').' groupings_groups'); | |
232 | } | |
233 | ||
234 | return true; | |
235 | } | |
236 | ||
f16fa0a3 | 237 | /** |
238 | * Delete all groups from course | |
239 | * @param int $courseid | |
240 | * @param bool $showfeedback | |
241 | * @return bool success | |
242 | */ | |
ddff2fa8 | 243 | function groups_delete_groups($courseid, $showfeedback=false) { |
244 | global $CFG; | |
245 | require_once($CFG->libdir.'/gdlib.php'); | |
246 | ||
0b5a80a1 | 247 | $groupssql = "SELECT id FROM {$CFG->prefix}groups g WHERE g.courseid = $courseid"; |
ddff2fa8 | 248 | |
0b5a80a1 | 249 | // delete any uses of groups |
250 | groups_delete_groupings_groups($courseid, $showfeedback); | |
251 | groups_delete_group_members($courseid, $showfeedback); | |
ddff2fa8 | 252 | |
253 | // delete group pictures | |
254 | if ($groups = get_records('groups', 'courseid', $courseid)) { | |
255 | foreach($groups as $group) { | |
256 | delete_profile_image($group->id, 'groups'); | |
257 | } | |
258 | } | |
259 | ||
0b5a80a1 | 260 | // delete group calendar events |
261 | delete_records_select('event', "groupid IN ($groupssql)"); | |
262 | ||
ddff2fa8 | 263 | delete_records('groups', 'courseid', $courseid); |
264 | if ($showfeedback) { | |
265 | notify(get_string('deleted').' groups'); | |
266 | } | |
267 | ||
268 | return true; | |
269 | } | |
270 | ||
f16fa0a3 | 271 | /** |
272 | * Delete all groupings from course | |
273 | * @param int $courseid | |
274 | * @param bool $showfeedback | |
275 | * @return bool success | |
276 | */ | |
ddff2fa8 | 277 | function groups_delete_groupings($courseid, $showfeedback=false) { |
278 | global $CFG; | |
279 | ||
280 | // delete any uses of groupings | |
281 | $sql = "DELETE FROM {$CFG->prefix}groupings_groups | |
282 | WHERE groupingid in (SELECT id FROM {$CFG->prefix}groupings g WHERE g.courseid = $courseid)"; | |
283 | execute_sql($sql, false); | |
284 | ||
285 | // remove the default groupingid from course | |
286 | set_field('course', 'defaultgroupingid', 0, 'id', $courseid); | |
287 | // remove the groupingid from all course modules | |
5f5faac0 | 288 | set_field('course_modules', 'groupingid', 0, 'course', $courseid); |
ddff2fa8 | 289 | |
290 | delete_records('groupings', 'courseid', $courseid); | |
291 | if ($showfeedback) { | |
292 | notify(get_string('deleted').' groupings'); | |
293 | } | |
294 | ||
295 | return true; | |
296 | } | |
297 | ||
298 | /* =================================== */ | |
299 | /* various functions used by groups UI */ | |
300 | /* =================================== */ | |
301 | ||
302 | /** | |
303 | * Gets the users for a course who are not in a specified group | |
304 | * @param int $groupid The id of the group | |
305 | * @param string searchtext similar to searchtext in role assign, search | |
306 | * @return array An array of the userids of the non-group members, or false if | |
307 | * an error occurred. | |
308 | * This function was changed to get_users_by_capability style | |
309 | * mostly because of the searchtext requirement | |
310 | */ | |
47d1ec41 | 311 | function groups_get_users_not_in_group($courseid, $groupid, $searchtext='', $sort = 'u.lastname ASC') { |
ddff2fa8 | 312 | |
313 | global $CFG; | |
314 | ||
315 | $context = get_context_instance(CONTEXT_COURSE, $courseid); | |
316 | ||
317 | if ($searchtext !== '') { // Search for a subset of remaining users | |
318 | $LIKE = sql_ilike(); | |
319 | $FULLNAME = sql_fullname(); | |
320 | $wheresearch = " AND u.id IN (SELECT id FROM {$CFG->prefix}user WHERE $FULLNAME $LIKE '%$searchtext%' OR email $LIKE '%$searchtext%' )"; | |
321 | } else { | |
322 | $wheresearch = ''; | |
323 | } | |
324 | ||
325 | $capability = 'moodle/course:view'; | |
326 | $doanything = false; | |
f3f7610c | 327 | |
ddff2fa8 | 328 | // find all possible "student" roles |
329 | if ($possibleroles = get_roles_with_capability($capability, CAP_ALLOW, $context)) { | |
330 | if (!$doanything) { | |
331 | if (!$sitecontext = get_context_instance(CONTEXT_SYSTEM)) { | |
332 | return false; // Something is seriously wrong | |
333 | } | |
334 | $doanythingroles = get_roles_with_capability('moodle/site:doanything', CAP_ALLOW, $sitecontext); | |
335 | } | |
f3f7610c | 336 | |
ddff2fa8 | 337 | $validroleids = array(); |
338 | foreach ($possibleroles as $possiblerole) { | |
339 | if (!$doanything) { | |
340 | if (isset($doanythingroles[$possiblerole->id])) { // We don't want these included | |
341 | continue; | |
342 | } | |
343 | } | |
344 | if ($caps = role_context_capabilities($possiblerole->id, $context, $capability)) { // resolved list | |
345 | if (isset($caps[$capability]) && $caps[$capability] > 0) { // resolved capability > 0 | |
346 | $validroleids[] = $possiblerole->id; | |
347 | } | |
348 | } | |
349 | } | |
350 | if (empty($validroleids)) { | |
351 | return false; | |
352 | } | |
353 | $roleids = '('.implode(',', $validroleids).')'; | |
354 | } else { | |
355 | return false; // No need to continue, since no roles have this capability set | |
356 | } | |
f3f7610c | 357 | |
ddff2fa8 | 358 | /// Construct the main SQL |
359 | $select = " SELECT u.id, u.firstname, u.lastname"; | |
360 | $from = " FROM {$CFG->prefix}user u | |
361 | INNER JOIN {$CFG->prefix}role_assignments ra ON ra.userid = u.id | |
362 | INNER JOIN {$CFG->prefix}role r ON r.id = ra.roleid"; | |
f16fa0a3 | 363 | |
ddff2fa8 | 364 | $where = " WHERE ra.contextid ".get_related_contexts_string($context)." |
365 | AND u.deleted = 0 | |
366 | AND ra.roleid in $roleids | |
367 | AND u.id NOT IN (SELECT userid | |
368 | FROM {$CFG->prefix}groups_members | |
369 | WHERE groupid = $groupid) | |
370 | $wheresearch"; | |
acf000b0 | 371 | $groupby = " GROUP BY u.id, u.firstname, u.lastname "; |
47d1ec41 | 372 | $orderby = " ORDER BY $sort"; |
f16fa0a3 | 373 | |
47d1ec41 | 374 | return get_records_sql($select.$from.$where.$groupby.$orderby); |
acf000b0 | 375 | } |
376 | ||
377 | ||
378 | /** | |
379 | * Gets potential group members for grouping | |
380 | * @param int $courseid The id of the course | |
381 | * @param int $roleid The role to select users from | |
382 | * @param string $orderby The colum to sort users by | |
383 | * @return array An array of the users | |
384 | */ | |
f16fa0a3 | 385 | function groups_get_potential_members($courseid, $roleid = null, $orderby = 'lastname,firstname') { |
acf000b0 | 386 | global $CFG; |
f16fa0a3 | 387 | |
acf000b0 | 388 | $context = get_context_instance(CONTEXT_COURSE, $courseid); |
389 | $sitecontext = get_context_instance(CONTEXT_SYSTEM); | |
390 | $rolenames = array(); | |
391 | $avoidroles = array(); | |
392 | ||
393 | if ($roles = get_roles_used_in_context($context, true)) { | |
394 | ||
395 | $canviewroles = get_roles_with_capability('moodle/course:view', CAP_ALLOW, $context); | |
396 | $doanythingroles = get_roles_with_capability('moodle/site:doanything', CAP_ALLOW, $sitecontext); | |
397 | ||
398 | foreach ($roles as $role) { | |
399 | if (!isset($canviewroles[$role->id])) { // Avoid this role (eg course creator) | |
400 | $avoidroles[] = $role->id; | |
401 | unset($roles[$role->id]); | |
402 | continue; | |
403 | } | |
404 | if (isset($doanythingroles[$role->id])) { // Avoid this role (ie admin) | |
405 | $avoidroles[] = $role->id; | |
406 | unset($roles[$role->id]); | |
407 | continue; | |
408 | } | |
409 | $rolenames[$role->id] = strip_tags(role_get_name($role, $context)); // Used in menus etc later on | |
410 | } | |
411 | } | |
f16fa0a3 | 412 | |
acf000b0 | 413 | $select = 'SELECT u.id, u.username, u.firstname, u.lastname, u.idnumber '; |
414 | $from = "FROM {$CFG->prefix}user u INNER JOIN | |
415 | {$CFG->prefix}role_assignments r on u.id=r.userid "; | |
416 | ||
417 | if ($avoidroles) { | |
418 | $adminroles = 'AND r.roleid NOT IN ('; | |
419 | $adminroles .= implode(',', $avoidroles); | |
420 | $adminroles .= ')'; | |
421 | } else { | |
422 | $adminroles = ''; | |
423 | } | |
424 | ||
425 | // we are looking for all users with this role assigned in this context or higher | |
426 | if ($usercontexts = get_parent_contexts($context)) { | |
427 | $listofcontexts = '('.implode(',', $usercontexts).')'; | |
428 | } else { | |
429 | $listofcontexts = '('.$sitecontext->id.')'; // must be site | |
430 | } | |
f16fa0a3 | 431 | |
acf000b0 | 432 | if ($roleid) { |
433 | $selectrole = " AND r.roleid = $roleid "; | |
434 | } else { | |
435 | $selectrole = " "; | |
436 | } | |
f16fa0a3 | 437 | |
acf000b0 | 438 | $where = "WHERE (r.contextid = $context->id OR r.contextid in $listofcontexts) |
f16fa0a3 | 439 | AND u.deleted = 0 $selectrole |
440 | AND u.username != 'guest' | |
441 | $adminroles "; | |
acf000b0 | 442 | $order = "ORDER BY $orderby "; |
f16fa0a3 | 443 | |
acf000b0 | 444 | return(get_records_sql($select.$from.$where.$order)); |
f16fa0a3 | 445 | |
acf000b0 | 446 | } |
f3f7610c | 447 | |
acf000b0 | 448 | /** |
449 | * Parse a group name for characters to replace | |
450 | * @param string $format The format a group name will follow | |
451 | * @param int $groupnumber The number of the group to be used in the parsed format string | |
452 | * @return string the parsed format string | |
453 | */ | |
454 | function groups_parse_name($format, $groupnumber) { | |
acf000b0 | 455 | if (strstr($format, '@') !== false) { // Convert $groupnumber to a character series |
f16fa0a3 | 456 | $letter = 'A'; |
457 | for($i=0; $i<$groupnumber; $i++) { | |
458 | $letter++; | |
acf000b0 | 459 | } |
f16fa0a3 | 460 | $str = str_replace('@', $letter, $format); |
acf000b0 | 461 | } else { |
f16fa0a3 | 462 | $str = str_replace('#', $groupnumber+1, $format); |
acf000b0 | 463 | } |
464 | return($str); | |
ddff2fa8 | 465 | } |
f3f7610c | 466 | |
f16fa0a3 | 467 | /** |
468 | * Assigns group into grouping | |
469 | * @param int groupingid | |
470 | * @param int groupid | |
471 | * @return bool success | |
472 | */ | |
473 | function groups_assign_grouping($groupingid, $groupid) { | |
474 | if (record_exists('groupings_groups', 'groupingid', $groupingid, 'groupid', $groupid)) { | |
475 | return true; | |
476 | } | |
477 | $assign = new object(); | |
478 | $assign->groupingid = $groupingid; | |
479 | $assign->groupid = $groupid; | |
480 | $assign->timeadded = time(); | |
481 | return (bool)insert_record('groupings_groups', $assign); | |
482 | } | |
483 | ||
484 | /** | |
485 | * Unassigns group grom grouping | |
486 | * @param int groupingid | |
487 | * @param int groupid | |
488 | * @return bool success | |
489 | */ | |
490 | function groups_unassign_grouping($groupingid, $groupid) { | |
491 | return delete_records('groupings_groups', 'groupingid', $groupingid, 'groupid', $groupid); | |
492 | } | |
493 | ||
47d1ec41 | 494 | ?> |