MDL-50744 enrol_meta: fix incorrect role assign
[moodle.git] / enrol / meta / locallib.php
CommitLineData
df997f84 1<?php
df997f84
PS
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/**
18 * Local stuff for meta course enrolment plugin.
19 *
31ac2aef 20 * @package enrol_meta
e2382027
PS
21 * @copyright 2010 Petr Skoda {@link http://skodak.org}
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
df997f84
PS
23 */
24
e2382027 25defined('MOODLE_INTERNAL') || die();
df997f84 26
ad68ed74 27
df997f84
PS
28/**
29 * Event handler for meta enrolment plugin.
30 *
31 * We try to keep everything in sync via listening to events,
32 * it may fail sometimes, so we always do a full sync in cron too.
33 */
34class enrol_meta_handler {
ad68ed74
PS
35
36 /**
37 * Synchronise meta enrolments of this user in this course
38 * @static
39 * @param int $courseid
40 * @param int $userid
41 * @return void
42 */
43 protected static function sync_course_instances($courseid, $userid) {
df997f84
PS
44 global $DB;
45
ad68ed74
PS
46 static $preventrecursion = false;
47
48 // does anything want to sync with this parent?
49 if (!$enrols = $DB->get_records('enrol', array('customint1'=>$courseid, 'enrol'=>'meta'), 'id ASC')) {
50 return;
51 }
52
53 if ($preventrecursion) {
54 return;
55 }
56
57 $preventrecursion = true;
58
59 try {
60 foreach ($enrols as $enrol) {
61 self::sync_with_parent_course($enrol, $userid);
62 }
63 } catch (Exception $e) {
64 $preventrecursion = false;
65 throw $e;
66 }
67
68 $preventrecursion = false;
69 }
70
71 /**
72 * Synchronise user enrolments in given instance as fast as possible.
73 *
74 * All roles are removed if the meta plugin disabled.
75 *
76 * @static
77 * @param stdClass $instance
78 * @param int $userid
79 * @return void
80 */
81 protected static function sync_with_parent_course(stdClass $instance, $userid) {
82 global $DB, $CFG;
1165cab2 83 require_once($CFG->dirroot . '/group/lib.php');
ad68ed74
PS
84
85 $plugin = enrol_get_plugin('meta');
86
87 if ($instance->customint1 == $instance->courseid) {
88 // can not sync with self!!!
89 return;
90 }
91
92 $context = context_course::instance($instance->courseid);
93
ad68ed74
PS
94 // list of enrolments in parent course (we ignore meta enrols in parents completely)
95 list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e');
96 $params['userid'] = $userid;
97 $params['parentcourse'] = $instance->customint1;
98 $sql = "SELECT ue.*
99 FROM {user_enrolments} ue
100 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol <> 'meta' AND e.courseid = :parentcourse AND e.enrol $enabled)
101 WHERE ue.userid = :userid";
102 $parentues = $DB->get_records_sql($sql, $params);
103 // current enrolments for this instance
104 $ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid));
105
106 // first deal with users that are not enrolled in parent
107 if (empty($parentues)) {
108 self::user_not_supposed_to_be_here($instance, $ue, $context, $plugin);
109 return;
110 }
111
1344bc78
PS
112 if (!$parentcontext = context_course::instance($instance->customint1, IGNORE_MISSING)) {
113 // Weird, we should not get here.
ad68ed74 114 return;
df997f84
PS
115 }
116
ad68ed74
PS
117 $skiproles = $plugin->get_config('nosyncroleids', '');
118 $skiproles = empty($skiproles) ? array() : explode(',', $skiproles);
119 $syncall = $plugin->get_config('syncall', 1);
120
121 // roles in parent course (meta enrols must be ignored!)
122 $parentroles = array();
123 list($ignoreroles, $params) = $DB->get_in_or_equal($skiproles, SQL_PARAMS_NAMED, 'ri', false, -1);
124 $params['contextid'] = $parentcontext->id;
125 $params['userid'] = $userid;
126 $select = "contextid = :contextid AND userid = :userid AND component <> 'enrol_meta' AND roleid $ignoreroles";
127 foreach($DB->get_records_select('role_assignments', $select, $params) as $ra) {
128 $parentroles[$ra->roleid] = $ra->roleid;
df997f84
PS
129 }
130
ad68ed74
PS
131 // roles from this instance
132 $roles = array();
133 $ras = $DB->get_records('role_assignments', array('contextid'=>$context->id, 'userid'=>$userid, 'component'=>'enrol_meta', 'itemid'=>$instance->id));
134 foreach($ras as $ra) {
135 $roles[$ra->roleid] = $ra->roleid;
df997f84 136 }
ad68ed74 137 unset($ras);
df997f84 138
ad68ed74
PS
139 // do we want users without roles?
140 if (!$syncall and empty($parentroles)) {
141 self::user_not_supposed_to_be_here($instance, $ue, $context, $plugin);
142 return;
df997f84
PS
143 }
144
ad68ed74
PS
145 // is parent enrol active? (we ignore enrol starts and ends, sorry it would be too complex)
146 $parentstatus = ENROL_USER_SUSPENDED;
147 foreach ($parentues as $pue) {
148 if ($pue->status == ENROL_USER_ACTIVE) {
149 $parentstatus = ENROL_USER_ACTIVE;
150 break;
df997f84
PS
151 }
152 }
153
ad68ed74
PS
154 // enrol user if not enrolled yet or fix status
155 if ($ue) {
156 if ($parentstatus != $ue->status) {
157 $plugin->update_user_enrol($instance, $userid, $parentstatus);
158 $ue->status = $parentstatus;
159 }
160 } else {
161 $plugin->enrol_user($instance, $userid, NULL, 0, 0, $parentstatus);
162 $ue = new stdClass();
163 $ue->userid = $userid;
164 $ue->enrolid = $instance->id;
165 $ue->status = $parentstatus;
9e37d365
MG
166 if ($instance->customint2) {
167 groups_add_member($instance->customint2, $userid, 'enrol_meta', $instance->id);
168 }
ad68ed74
PS
169 }
170
1344bc78
PS
171 $unenrolaction = $plugin->get_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES);
172
ad68ed74
PS
173 // only active users in enabled instances are supposed to have roles (we can reassign the roles any time later)
174 if ($ue->status != ENROL_USER_ACTIVE or $instance->status != ENROL_INSTANCE_ENABLED) {
1344bc78
PS
175 if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) {
176 // Always keep the roles.
177 } else if ($roles) {
ad68ed74 178 role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id, 'component'=>'enrol_meta', 'itemid'=>$instance->id));
df997f84 179 }
ad68ed74
PS
180 return;
181 }
df997f84 182
ad68ed74
PS
183 // add new roles
184 foreach ($parentroles as $rid) {
185 if (!isset($roles[$rid])) {
186 role_assign($rid, $userid, $context->id, 'enrol_meta', $instance->id);
187 }
df997f84
PS
188 }
189
1344bc78
PS
190 if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) {
191 // Always keep the roles.
192 return;
193 }
194
ad68ed74
PS
195 // remove roles
196 foreach ($roles as $rid) {
197 if (!isset($parentroles[$rid])) {
198 role_unassign($rid, $userid, $context->id, 'enrol_meta', $instance->id);
199 }
200 }
df997f84
PS
201 }
202
ad68ed74
PS
203 /**
204 * Deal with users that are not supposed to be enrolled via this instance
205 * @static
206 * @param stdClass $instance
207 * @param stdClass $ue
208 * @param context_course $context
209 * @param enrol_meta $plugin
210 * @return void
211 */
212 protected static function user_not_supposed_to_be_here($instance, $ue, context_course $context, $plugin) {
213 if (!$ue) {
1344bc78 214 // Not enrolled yet - simple!
ad68ed74
PS
215 return;
216 }
217
218 $userid = $ue->userid;
1344bc78 219 $unenrolaction = $plugin->get_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES);
ad68ed74
PS
220
221 if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
1344bc78 222 // Purges grades, group membership, preferences, etc. - admins were warned!
ad68ed74 223 $plugin->unenrol_user($instance, $userid);
ad68ed74 224
1344bc78 225 } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) {
ad68ed74
PS
226 if ($ue->status != ENROL_USER_SUSPENDED) {
227 $plugin->update_user_enrol($instance, $userid, ENROL_USER_SUSPENDED);
ad68ed74 228 }
1344bc78
PS
229
230 } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
231 if ($ue->status != ENROL_USER_SUSPENDED) {
232 $plugin->update_user_enrol($instance, $userid, ENROL_USER_SUSPENDED);
233 }
234 role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id, 'component'=>'enrol_meta', 'itemid'=>$instance->id));
235
236 } else {
237 debugging('Unknown unenrol action '.$unenrolaction);
ad68ed74
PS
238 }
239 }
df997f84
PS
240}
241
242/**
243 * Sync all meta course links.
ad68ed74 244 *
df997f84 245 * @param int $courseid one course, empty mean all
ad68ed74
PS
246 * @param bool $verbose verbose CLI output
247 * @return int 0 means ok, 1 means error, 2 means plugin disabled
df997f84 248 */
ad68ed74 249function enrol_meta_sync($courseid = NULL, $verbose = false) {
df997f84 250 global $CFG, $DB;
98177a45 251 require_once("{$CFG->dirroot}/group/lib.php");
df997f84 252
ad68ed74
PS
253 // purge all roles if meta sync disabled, those can be recreated later here in cron
254 if (!enrol_is_enabled('meta')) {
255 if ($verbose) {
256 mtrace('Meta sync plugin is disabled, unassigning all plugin roles and stopping.');
257 }
258 role_unassign_all(array('component'=>'enrol_meta'));
259 return 2;
260 }
261
262 // unfortunately this may take a long time, execution can be interrupted safely
3ef7279f 263 core_php_time_limit::raise();
ad68ed74 264 raise_memory_limit(MEMORY_HUGE);
df997f84 265
ad68ed74
PS
266 if ($verbose) {
267 mtrace('Starting user enrolment synchronisation...');
268 }
269
270 $instances = array(); // cache instances
379434e4 271
df997f84
PS
272 $meta = enrol_get_plugin('meta');
273
1344bc78 274 $unenrolaction = $meta->get_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES);
ad68ed74
PS
275 $skiproles = $meta->get_config('nosyncroleids', '');
276 $skiproles = empty($skiproles) ? array() : explode(',', $skiproles);
277 $syncall = $meta->get_config('syncall', 1);
278
279 $allroles = get_all_roles();
280
df997f84
PS
281
282 // iterate through all not enrolled yet users
ad68ed74
PS
283 $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
284 list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e');
285 $params['courseid'] = $courseid;
286 $sql = "SELECT pue.userid, e.id AS enrolid, pue.status
287 FROM {user_enrolments} pue
288 JOIN {enrol} pe ON (pe.id = pue.enrolid AND pe.enrol <> 'meta' AND pe.enrol $enabled)
289 JOIN {enrol} e ON (e.customint1 = pe.courseid AND e.enrol = 'meta' $onecourse)
f3bd4ea6 290 JOIN {user} u ON (u.id = pue.userid AND u.deleted = 0)
ad68ed74
PS
291 LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = pue.userid)
292 WHERE ue.id IS NULL";
293
294 $rs = $DB->get_recordset_sql($sql, $params);
295 foreach($rs as $ue) {
296 if (!isset($instances[$ue->enrolid])) {
297 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
df997f84 298 }
ad68ed74
PS
299 $instance = $instances[$ue->enrolid];
300
301 if (!$syncall) {
302 // this may be slow if very many users are ignored in sync
303 $parentcontext = context_course::instance($instance->customint1);
304 list($ignoreroles, $params) = $DB->get_in_or_equal($skiproles, SQL_PARAMS_NAMED, 'ri', false, -1);
305 $params['contextid'] = $parentcontext->id;
306 $params['userid'] = $ue->userid;
307 $select = "contextid = :contextid AND userid = :userid AND component <> 'enrol_meta' AND roleid $ignoreroles";
308 if (!$DB->record_exists_select('role_assignments', $select, $params)) {
309 // bad luck, this user does not have any role we want in parent course
310 if ($verbose) {
311 mtrace(" skipping enrolling: $ue->userid ==> $instance->courseid (user without role)");
312 }
313 continue;
df997f84 314 }
df997f84 315 }
ad68ed74 316
f06d8d94 317 $meta->enrol_user($instance, $ue->userid, null, 0, 0, $ue->status);
9e37d365
MG
318 if ($instance->customint2) {
319 groups_add_member($instance->customint2, $ue->userid, 'enrol_meta', $instance->id);
320 }
ad68ed74
PS
321 if ($verbose) {
322 mtrace(" enrolling: $ue->userid ==> $instance->courseid");
323 }
df997f84 324 }
ad68ed74
PS
325 $rs->close();
326
df997f84 327
ad68ed74
PS
328 // unenrol as necessary - ignore enabled flag, we want to get rid of existing enrols in any case
329 $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
330 list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e');
331 $params['courseid'] = $courseid;
332 $sql = "SELECT ue.*
df997f84
PS
333 FROM {user_enrolments} ue
334 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
26a06fa7 335 LEFT JOIN ({user_enrolments} xpue
ad68ed74 336 JOIN {enrol} xpe ON (xpe.id = xpue.enrolid AND xpe.enrol <> 'meta' AND xpe.enrol $enabled)
26a06fa7
MA
337 ) ON (xpe.courseid = e.customint1 AND xpue.userid = ue.userid)
338 WHERE xpue.userid IS NULL";
ad68ed74 339 $rs = $DB->get_recordset_sql($sql, $params);
df997f84
PS
340 foreach($rs as $ue) {
341 if (!isset($instances[$ue->enrolid])) {
342 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
343 }
ad68ed74
PS
344 $instance = $instances[$ue->enrolid];
345
346 if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
347 $meta->unenrol_user($instance, $ue->userid);
348 if ($verbose) {
349 mtrace(" unenrolling: $ue->userid ==> $instance->courseid");
350 }
ad68ed74 351
1344bc78
PS
352 } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) {
353 if ($ue->status != ENROL_USER_SUSPENDED) {
354 $meta->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
355 if ($verbose) {
356 mtrace(" suspending: $ue->userid ==> $instance->courseid");
357 }
358 }
359
360 } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
ad68ed74
PS
361 if ($ue->status != ENROL_USER_SUSPENDED) {
362 $meta->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
363 $context = context_course::instance($instance->courseid);
1344bc78 364 role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$context->id, 'component'=>'enrol_meta', 'itemid'=>$instance->id));
ad68ed74
PS
365 if ($verbose) {
366 mtrace(" suspending and removing all roles: $ue->userid ==> $instance->courseid");
367 }
368 }
ad68ed74 369 }
df997f84
PS
370 }
371 $rs->close();
df997f84 372
ad68ed74
PS
373
374 // update status - meta enrols + start and end dates are ignored, sorry
375 // note the trick here is that the active enrolment and instance constants have value 0
376 $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
377 list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e');
378 $params['courseid'] = $courseid;
379 $sql = "SELECT ue.userid, ue.enrolid, pue.pstatus
380 FROM {user_enrolments} ue
381 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
382 JOIN (SELECT xpue.userid, xpe.courseid, MIN(xpue.status + xpe.status) AS pstatus
383 FROM {user_enrolments} xpue
384 JOIN {enrol} xpe ON (xpe.id = xpue.enrolid AND xpe.enrol <> 'meta' AND xpe.enrol $enabled)
385 GROUP BY xpue.userid, xpe.courseid
386 ) pue ON (pue.courseid = e.customint1 AND pue.userid = ue.userid)
387 WHERE (pue.pstatus = 0 AND ue.status > 0) OR (pue.pstatus > 0 and ue.status = 0)";
388 $rs = $DB->get_recordset_sql($sql, $params);
389 foreach($rs as $ue) {
390 if (!isset($instances[$ue->enrolid])) {
391 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
392 }
393 $instance = $instances[$ue->enrolid];
394 $ue->pstatus = ($ue->pstatus == ENROL_USER_ACTIVE) ? ENROL_USER_ACTIVE : ENROL_USER_SUSPENDED;
395
396 if ($ue->pstatus == ENROL_USER_ACTIVE and !$syncall and $unenrolaction != ENROL_EXT_REMOVED_UNENROL) {
397 // this may be slow if very many users are ignored in sync
398 $parentcontext = context_course::instance($instance->customint1);
399 list($ignoreroles, $params) = $DB->get_in_or_equal($skiproles, SQL_PARAMS_NAMED, 'ri', false, -1);
400 $params['contextid'] = $parentcontext->id;
401 $params['userid'] = $ue->userid;
402 $select = "contextid = :contextid AND userid = :userid AND component <> 'enrol_meta' AND roleid $ignoreroles";
403 if (!$DB->record_exists_select('role_assignments', $select, $params)) {
404 // bad luck, this user does not have any role we want in parent course
405 if ($verbose) {
406 mtrace(" skipping unsuspending: $ue->userid ==> $instance->courseid (user without role)");
407 }
408 continue;
df997f84 409 }
ad68ed74
PS
410 }
411
412 $meta->update_user_enrol($instance, $ue->userid, $ue->pstatus);
413 if ($verbose) {
414 if ($ue->pstatus == ENROL_USER_ACTIVE) {
415 mtrace(" unsuspending: $ue->userid ==> $instance->courseid");
416 } else {
417 mtrace(" suspending: $ue->userid ==> $instance->courseid");
418 }
419 }
420 }
421 $rs->close();
422
423
424 // now assign all necessary roles
425 $enabled = explode(',', $CFG->enrol_plugins_enabled);
426 foreach($enabled as $k=>$v) {
427 if ($v === 'meta') {
428 continue; // no meta sync of meta roles
429 }
430 $enabled[$k] = 'enrol_'.$v;
431 }
77a5c093 432 $enabled[] = ''; // manual assignments are replicated too
ad68ed74
PS
433
434 $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
435 list($enabled, $params) = $DB->get_in_or_equal($enabled, SQL_PARAMS_NAMED, 'e');
436 $params['coursecontext'] = CONTEXT_COURSE;
437 $params['courseid'] = $courseid;
438 $params['activeuser'] = ENROL_USER_ACTIVE;
439 $params['enabledinstance'] = ENROL_INSTANCE_ENABLED;
440 $sql = "SELECT DISTINCT pra.roleid, pra.userid, c.id AS contextid, e.id AS enrolid, e.courseid
441 FROM {role_assignments} pra
442 JOIN {user} u ON (u.id = pra.userid AND u.deleted = 0)
443 JOIN {context} pc ON (pc.id = pra.contextid AND pc.contextlevel = :coursecontext AND pra.component $enabled)
444 JOIN {enrol} e ON (e.customint1 = pc.instanceid AND e.enrol = 'meta' $onecourse AND e.status = :enabledinstance)
445 JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = u.id AND ue.status = :activeuser)
446 JOIN {context} c ON (c.contextlevel = pc.contextlevel AND c.instanceid = e.courseid)
447 LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.userid = pra.userid AND ra.roleid = pra.roleid AND ra.itemid = e.id AND ra.component = 'enrol_meta')
448 WHERE ra.id IS NULL";
449
450 if ($ignored = $meta->get_config('nosyncroleids')) {
451 list($notignored, $xparams) = $DB->get_in_or_equal(explode(',', $ignored), SQL_PARAMS_NAMED, 'ig', false);
452 $params = array_merge($params, $xparams);
453 $sql = "$sql AND pra.roleid $notignored";
df997f84
PS
454 }
455
ad68ed74
PS
456 $rs = $DB->get_recordset_sql($sql, $params);
457 foreach($rs as $ra) {
458 role_assign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_meta', $ra->enrolid);
459 if ($verbose) {
460 mtrace(" assigning role: $ra->userid ==> $ra->courseid as ".$allroles[$ra->roleid]->shortname);
461 }
462 }
463 $rs->close();
464
465
df997f84 466 // remove unwanted roles - include ignored roles and disabled plugins too
ad68ed74
PS
467 $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
468 $params = array();
469 $params['coursecontext'] = CONTEXT_COURSE;
470 $params['courseid'] = $courseid;
471 $params['activeuser'] = ENROL_USER_ACTIVE;
472 $params['enabledinstance'] = ENROL_INSTANCE_ENABLED;
df997f84 473 if ($ignored = $meta->get_config('nosyncroleids')) {
cf717dc2 474 list($notignored, $xparams) = $DB->get_in_or_equal(explode(',', $ignored), SQL_PARAMS_NAMED, 'ig', false);
df997f84
PS
475 $params = array_merge($params, $xparams);
476 $notignored = "AND pra.roleid $notignored";
477 } else {
478 $notignored = "";
479 }
1344bc78 480
ad68ed74 481 $sql = "SELECT ra.roleid, ra.userid, ra.contextid, ra.itemid, e.courseid
df997f84
PS
482 FROM {role_assignments} ra
483 JOIN {enrol} e ON (e.id = ra.itemid AND ra.component = 'enrol_meta' AND e.enrol = 'meta' $onecourse)
484 JOIN {context} pc ON (pc.instanceid = e.customint1 AND pc.contextlevel = :coursecontext)
485 LEFT JOIN {role_assignments} pra ON (pra.contextid = pc.id AND pra.userid = ra.userid AND pra.roleid = ra.roleid AND pra.component <> 'enrol_meta' $notignored)
ad68ed74
PS
486 LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = ra.userid AND ue.status = :activeuser)
487 WHERE pra.id IS NULL OR ue.id IS NULL OR e.status <> :enabledinstance";
df997f84 488
1344bc78
PS
489 if ($unenrolaction != ENROL_EXT_REMOVED_SUSPEND) {
490 $rs = $DB->get_recordset_sql($sql, $params);
491 foreach($rs as $ra) {
492 role_unassign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_meta', $ra->itemid);
493 if ($verbose) {
494 mtrace(" unassigning role: $ra->userid ==> $ra->courseid as ".$allroles[$ra->roleid]->shortname);
495 }
ad68ed74 496 }
1344bc78 497 $rs->close();
df997f84 498 }
df997f84 499
ad68ed74
PS
500
501 // kick out or suspend users without synced roles if syncall disabled
502 if (!$syncall) {
503 if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
504 $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
505 $params = array();
506 $params['coursecontext'] = CONTEXT_COURSE;
379434e4 507 $params['courseid'] = $courseid;
ad68ed74
PS
508 $sql = "SELECT ue.userid, ue.enrolid
509 FROM {user_enrolments} ue
510 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
511 JOIN {context} c ON (e.courseid = c.instanceid AND c.contextlevel = :coursecontext)
512 LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.itemid = e.id AND ra.userid = ue.userid)
513 WHERE ra.id IS NULL";
514 $ues = $DB->get_recordset_sql($sql, $params);
515 foreach($ues as $ue) {
516 if (!isset($instances[$ue->enrolid])) {
517 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
518 }
519 $instance = $instances[$ue->enrolid];
520 $meta->unenrol_user($instance, $ue->userid);
521 if ($verbose) {
522 mtrace(" unenrolling: $ue->userid ==> $instance->courseid (user without role)");
523 }
379434e4 524 }
ad68ed74 525 $ues->close();
379434e4 526
ad68ed74
PS
527 } else {
528 // just suspend the users
529 $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
530 $params = array();
531 $params['coursecontext'] = CONTEXT_COURSE;
379434e4 532 $params['courseid'] = $courseid;
ad68ed74
PS
533 $params['active'] = ENROL_USER_ACTIVE;
534 $sql = "SELECT ue.userid, ue.enrolid
535 FROM {user_enrolments} ue
536 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
537 JOIN {context} c ON (e.courseid = c.instanceid AND c.contextlevel = :coursecontext)
538 LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.itemid = e.id AND ra.userid = ue.userid)
539 WHERE ra.id IS NULL AND ue.status = :active";
540 $ues = $DB->get_recordset_sql($sql, $params);
541 foreach($ues as $ue) {
542 if (!isset($instances[$ue->enrolid])) {
543 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
544 }
545 $instance = $instances[$ue->enrolid];
546 $meta->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
547 if ($verbose) {
548 mtrace(" suspending: $ue->userid ==> $instance->courseid (user without role)");
549 }
379434e4 550 }
ad68ed74 551 $ues->close();
379434e4 552 }
ad68ed74 553 }
379434e4 554
98177a45 555 // Finally sync groups.
9c1561ef
MG
556 $affectedusers = groups_sync_with_enrolment('meta', $courseid);
557 if ($verbose) {
558 foreach ($affectedusers['removed'] as $gm) {
9e37d365
MG
559 mtrace("removing user from group: $gm->userid ==> $gm->courseid - $gm->groupname", 1);
560 }
9c1561ef 561 foreach ($affectedusers['added'] as $ue) {
9e37d365
MG
562 mtrace("adding user to group: $ue->userid ==> $ue->courseid - $ue->groupname", 1);
563 }
98177a45 564 }
98177a45 565
ad68ed74
PS
566 if ($verbose) {
567 mtrace('...user enrolment synchronisation finished.');
379434e4
PS
568 }
569
ad68ed74 570 return 0;
df997f84 571}
e284e179
MG
572
573/**
574 * Create a new group with the course's name.
575 *
576 * @param int $courseid
577 * @param int $linkedcourseid
578 * @return int $groupid Group ID for this cohort.
579 */
580function enrol_meta_create_new_group($courseid, $linkedcourseid) {
581 global $DB, $CFG;
582
583 require_once($CFG->dirroot.'/group/lib.php');
584
585 $coursename = $DB->get_field('course', 'fullname', array('id' => $linkedcourseid), MUST_EXIST);
586 $a = new stdClass();
587 $a->name = $coursename;
588 $a->increment = '';
589 $inc = 1;
590 $groupname = trim(get_string('defaultgroupnametext', 'enrol_meta', $a));
591 // Check to see if the group name already exists in this course. Add an incremented number if it does.
592 while ($DB->record_exists('groups', array('name' => $groupname, 'courseid' => $courseid))) {
593 $a->increment = '(' . (++$inc) . ')';
594 $groupname = trim(get_string('defaultgroupnametext', 'enrol_meta', $a));
595 }
596 // Create a new group for the course meta sync.
597 $groupdata = new stdClass();
598 $groupdata->courseid = $courseid;
599 $groupdata->name = $groupname;
600 $groupid = groups_create_group($groupdata);
601
602 return $groupid;
603}