Differences Between: [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403]
1 <?php 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 * 20 * @package enrol_meta 21 * @copyright 2010 Petr Skoda {@link http://skodak.org} 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 27 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 */ 34 class enrol_meta_handler { 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) { 44 global $DB; 45 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; 83 require_once($CFG->dirroot . '/group/lib.php'); 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 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.*, e.status AS enrolstatus 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 112 if (!$parentcontext = context_course::instance($instance->customint1, IGNORE_MISSING)) { 113 // Weird, we should not get here. 114 return; 115 } 116 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; 129 } 130 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; 136 } 137 unset($ras); 138 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; 143 } 144 145 // Is parent enrol active? Find minimum timestart and maximum timeend of all active enrolments. 146 $parentstatus = ENROL_USER_SUSPENDED; 147 $parenttimeend = null; 148 $parenttimestart = null; 149 foreach ($parentues as $pue) { 150 if ($pue->status == ENROL_USER_ACTIVE && $pue->enrolstatus == ENROL_INSTANCE_ENABLED) { 151 $parentstatus = ENROL_USER_ACTIVE; 152 if ($parenttimeend === null || $pue->timeend == 0 || ($parenttimeend && $parenttimeend < $pue->timeend)) { 153 $parenttimeend = $pue->timeend; 154 } 155 if ($parenttimestart === null || $parenttimestart > $pue->timestart) { 156 $parenttimestart = $pue->timestart; 157 } 158 } 159 } 160 161 // Enrol user if not enrolled yet or fix status/timestart/timeend. Use the minimum timestart and maximum timeend found above. 162 if ($ue) { 163 if ($parentstatus != $ue->status || 164 ($parentstatus == ENROL_USER_ACTIVE && ($parenttimestart != $ue->timestart || $parenttimeend != $ue->timeend))) { 165 $plugin->update_user_enrol($instance, $userid, $parentstatus, $parenttimestart, $parenttimeend); 166 $ue->status = $parentstatus; 167 $ue->timestart = $parenttimestart; 168 $ue->timeend = $parenttimeend; 169 } 170 } else { 171 $plugin->enrol_user($instance, $userid, NULL, (int)$parenttimestart, (int)$parenttimeend, $parentstatus); 172 $ue = new stdClass(); 173 $ue->userid = $userid; 174 $ue->enrolid = $instance->id; 175 $ue->status = $parentstatus; 176 if ($instance->customint2) { 177 groups_add_member($instance->customint2, $userid, 'enrol_meta', $instance->id); 178 } 179 } 180 181 $unenrolaction = $plugin->get_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES); 182 183 // Only active users in enabled instances are supposed to have roles (we can reassign the roles any time later). 184 if ($ue->status != ENROL_USER_ACTIVE or $instance->status != ENROL_INSTANCE_ENABLED or 185 ($parenttimeend and $parenttimeend < time()) or ($parenttimestart > time())) { 186 if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) { 187 // Always keep the roles. 188 } else if ($roles) { 189 // This will only unassign roles that were assigned in this enrolment method, leaving all manual role assignments intact. 190 role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id, 'component'=>'enrol_meta', 'itemid'=>$instance->id)); 191 } 192 return; 193 } 194 195 // add new roles 196 foreach ($parentroles as $rid) { 197 if (!isset($roles[$rid])) { 198 role_assign($rid, $userid, $context->id, 'enrol_meta', $instance->id); 199 } 200 } 201 202 if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) { 203 // Always keep the roles. 204 return; 205 } 206 207 // remove roles 208 foreach ($roles as $rid) { 209 if (!isset($parentroles[$rid])) { 210 role_unassign($rid, $userid, $context->id, 'enrol_meta', $instance->id); 211 } 212 } 213 } 214 215 /** 216 * Deal with users that are not supposed to be enrolled via this instance 217 * @static 218 * @param stdClass $instance 219 * @param stdClass $ue 220 * @param context_course $context 221 * @param enrol_meta $plugin 222 * @return void 223 */ 224 protected static function user_not_supposed_to_be_here($instance, $ue, context_course $context, $plugin) { 225 if (!$ue) { 226 // Not enrolled yet - simple! 227 return; 228 } 229 230 $userid = $ue->userid; 231 $unenrolaction = $plugin->get_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES); 232 233 if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) { 234 // Purges grades, group membership, preferences, etc. - admins were warned! 235 $plugin->unenrol_user($instance, $userid); 236 237 } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) { 238 if ($ue->status != ENROL_USER_SUSPENDED) { 239 $plugin->update_user_enrol($instance, $userid, ENROL_USER_SUSPENDED); 240 } 241 242 } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) { 243 if ($ue->status != ENROL_USER_SUSPENDED) { 244 $plugin->update_user_enrol($instance, $userid, ENROL_USER_SUSPENDED); 245 } 246 role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id, 'component'=>'enrol_meta', 'itemid'=>$instance->id)); 247 248 } else { 249 debugging('Unknown unenrol action '.$unenrolaction); 250 } 251 } 252 } 253 254 /** 255 * Sync all meta course links. 256 * 257 * @param int $courseid one course, empty mean all 258 * @param bool $verbose verbose CLI output 259 * @return int 0 means ok, 1 means error, 2 means plugin disabled 260 */ 261 function enrol_meta_sync($courseid = NULL, $verbose = false) { 262 global $CFG, $DB; 263 require_once("{$CFG->dirroot}/group/lib.php"); 264 265 // purge all roles if meta sync disabled, those can be recreated later here in cron 266 if (!enrol_is_enabled('meta')) { 267 if ($verbose) { 268 mtrace('Meta sync plugin is disabled, unassigning all plugin roles and stopping.'); 269 } 270 role_unassign_all(array('component'=>'enrol_meta')); 271 return 2; 272 } 273 274 // unfortunately this may take a long time, execution can be interrupted safely 275 core_php_time_limit::raise(); 276 raise_memory_limit(MEMORY_HUGE); 277 278 if ($verbose) { 279 mtrace('Starting user enrolment synchronisation...'); 280 } 281 282 $instances = array(); // cache instances 283 284 $meta = enrol_get_plugin('meta'); 285 286 $unenrolaction = $meta->get_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES); 287 $skiproles = $meta->get_config('nosyncroleids', ''); 288 $skiproles = empty($skiproles) ? array() : explode(',', $skiproles); 289 $syncall = $meta->get_config('syncall', 1); 290 291 $allroles = get_all_roles(); 292 293 294 // Iterate through all not enrolled yet users. For each active enrolment of each user find the minimum 295 // enrolment startdate and maximum enrolment enddate. 296 // This SQL relies on the fact that ENROL_USER_ACTIVE < ENROL_USER_SUSPENDED 297 // and ENROL_INSTANCE_ENABLED < ENROL_INSTANCE_DISABLED. Condition "pue.status + pe.status = 0" means 298 // that enrolment is active. When MIN(pue.status + pe.status)=0 it means there exists an active 299 // enrolment. 300 $onecourse = $courseid ? "AND e.courseid = :courseid" : ""; 301 list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e'); 302 $params['courseid'] = $courseid; 303 $sql = "SELECT pue.userid, e.id AS enrolid, MIN(pue.status + pe.status) AS status, 304 MIN(CASE WHEN (pue.status + pe.status = 0) THEN pue.timestart ELSE 9999999999 END) AS timestart, 305 MAX(CASE WHEN (pue.status + pe.status = 0) THEN 306 (CASE WHEN pue.timeend = 0 THEN 9999999999 ELSE pue.timeend END) 307 ELSE 0 END) AS timeend 308 FROM {user_enrolments} pue 309 JOIN {enrol} pe ON (pe.id = pue.enrolid AND pe.enrol <> 'meta' AND pe.enrol $enabled) 310 JOIN {enrol} e ON (e.customint1 = pe.courseid AND e.enrol = 'meta' AND e.status = :enrolstatus $onecourse) 311 JOIN {user} u ON (u.id = pue.userid AND u.deleted = 0) 312 LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = pue.userid) 313 WHERE ue.id IS NULL 314 GROUP BY pue.userid, e.id"; 315 $params['enrolstatus'] = ENROL_INSTANCE_ENABLED; 316 317 $rs = $DB->get_recordset_sql($sql, $params); 318 foreach($rs as $ue) { 319 if (!isset($instances[$ue->enrolid])) { 320 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid)); 321 } 322 $instance = $instances[$ue->enrolid]; 323 324 if (!$syncall) { 325 // this may be slow if very many users are ignored in sync 326 $parentcontext = context_course::instance($instance->customint1); 327 list($ignoreroles, $params) = $DB->get_in_or_equal($skiproles, SQL_PARAMS_NAMED, 'ri', false, -1); 328 $params['contextid'] = $parentcontext->id; 329 $params['userid'] = $ue->userid; 330 $select = "contextid = :contextid AND userid = :userid AND component <> 'enrol_meta' AND roleid $ignoreroles"; 331 if (!$DB->record_exists_select('role_assignments', $select, $params)) { 332 // bad luck, this user does not have any role we want in parent course 333 if ($verbose) { 334 mtrace(" skipping enrolling: $ue->userid ==> $instance->courseid (user without role)"); 335 } 336 continue; 337 } 338 } 339 340 // So now we have aggregated values that we will use for the meta enrolment status, timeend and timestart. 341 // Again, we use the fact that active=0 and disabled/suspended=1. Only when MIN(pue.status + pe.status)=0 the enrolment is active: 342 $ue->status = ($ue->status == ENROL_USER_ACTIVE + ENROL_INSTANCE_ENABLED) ? ENROL_USER_ACTIVE : ENROL_USER_SUSPENDED; 343 // Timeend 9999999999 was used instead of 0 in the "MAX()" function: 344 $ue->timeend = ($ue->timeend == 9999999999) ? 0 : (int)$ue->timeend; 345 // Timestart 9999999999 is only possible when there are no active enrolments: 346 $ue->timestart = ($ue->timestart == 9999999999) ? 0 : (int)$ue->timestart; 347 348 $meta->enrol_user($instance, $ue->userid, null, $ue->timestart, $ue->timeend, $ue->status); 349 if ($instance->customint2) { 350 groups_add_member($instance->customint2, $ue->userid, 'enrol_meta', $instance->id); 351 } 352 if ($verbose) { 353 mtrace(" enrolling: $ue->userid ==> $instance->courseid"); 354 } 355 } 356 $rs->close(); 357 358 359 // unenrol as necessary - ignore enabled flag, we want to get rid of existing enrols in any case 360 $onecourse = $courseid ? "AND e.courseid = :courseid" : ""; 361 list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e'); 362 $params['courseid'] = $courseid; 363 $sql = "SELECT ue.* 364 FROM {user_enrolments} ue 365 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse) 366 LEFT JOIN ({user_enrolments} xpue 367 JOIN {enrol} xpe ON (xpe.id = xpue.enrolid AND xpe.enrol <> 'meta' AND xpe.enrol $enabled) 368 ) ON (xpe.courseid = e.customint1 AND xpue.userid = ue.userid) 369 WHERE xpue.userid IS NULL"; 370 $rs = $DB->get_recordset_sql($sql, $params); 371 foreach($rs as $ue) { 372 if (!isset($instances[$ue->enrolid])) { 373 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid)); 374 } 375 $instance = $instances[$ue->enrolid]; 376 377 if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) { 378 $meta->unenrol_user($instance, $ue->userid); 379 if ($verbose) { 380 mtrace(" unenrolling: $ue->userid ==> $instance->courseid"); 381 } 382 383 } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) { 384 if ($ue->status != ENROL_USER_SUSPENDED) { 385 $meta->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED); 386 if ($verbose) { 387 mtrace(" suspending: $ue->userid ==> $instance->courseid"); 388 } 389 } 390 391 } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) { 392 if ($ue->status != ENROL_USER_SUSPENDED) { 393 $meta->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED); 394 $context = context_course::instance($instance->courseid); 395 role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$context->id, 'component'=>'enrol_meta', 'itemid'=>$instance->id)); 396 if ($verbose) { 397 mtrace(" suspending and removing all roles: $ue->userid ==> $instance->courseid"); 398 } 399 } 400 } 401 } 402 $rs->close(); 403 404 405 // Update status - meta enrols are ignored to avoid recursion. 406 // Note the trick here is that the active enrolment and instance constants have value 0. 407 $onecourse = $courseid ? "AND e.courseid = :courseid" : ""; 408 list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e'); 409 $params['courseid'] = $courseid; 410 // The query builds a a list of all the non-meta enrolments that are on courses (the children) that are linked to by a meta 411 // enrolment, it then groups them by the course that linked to them (the parents). 412 // 413 // It will only return results where the there is a difference between the status of the parent and the lowest status 414 // of the children (remember that 0 is active, any other status is some form of inactive), or the time the earliest non-zero 415 // start time of a child is different to the parent, or the longest effective end date has changed. 416 // 417 // The last two case statements in the HAVING clause are designed to ignore any inactive child records when calculating 418 // the start and end time. 419 $sql = "SELECT ue.userid, ue.enrolid, 420 MIN(xpue.status + xpe.status) AS pstatus, 421 MIN(CASE WHEN (xpue.status + xpe.status = 0) THEN xpue.timestart ELSE 9999999999 END) AS ptimestart, 422 MAX(CASE WHEN (xpue.status + xpe.status = 0) THEN 423 (CASE WHEN xpue.timeend = 0 THEN 9999999999 ELSE xpue.timeend END) 424 ELSE 0 END) AS ptimeend 425 FROM {user_enrolments} ue 426 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse) 427 JOIN {user_enrolments} xpue ON (xpue.userid = ue.userid) 428 JOIN {enrol} xpe ON (xpe.id = xpue.enrolid AND xpe.enrol <> 'meta' 429 AND xpe.enrol $enabled AND xpe.courseid = e.customint1) 430 GROUP BY ue.userid, ue.enrolid 431 HAVING (MIN(xpue.status + xpe.status) = 0 AND MIN(ue.status) > 0) 432 OR (MIN(xpue.status + xpe.status) > 0 AND MIN(ue.status) = 0) 433 OR ((CASE WHEN 434 MIN(CASE WHEN (xpue.status + xpe.status = 0) THEN xpue.timestart ELSE 9999999999 END) = 9999999999 435 THEN 0 436 ELSE 437 MIN(CASE WHEN (xpue.status + xpe.status = 0) THEN xpue.timestart ELSE 9999999999 END) 438 END) <> MIN(ue.timestart)) 439 OR ((CASE 440 WHEN MAX(CASE WHEN (xpue.status + xpe.status = 0) 441 THEN (CASE WHEN xpue.timeend = 0 THEN 9999999999 ELSE xpue.timeend END) 442 ELSE 0 END) = 9999999999 443 THEN 0 ELSE MAX(CASE WHEN (xpue.status + xpe.status = 0) 444 THEN (CASE WHEN xpue.timeend = 0 THEN 9999999999 ELSE xpue.timeend END) 445 ELSE 0 END) 446 END) <> MAX(ue.timeend))"; 447 $rs = $DB->get_recordset_sql($sql, $params); 448 foreach($rs as $ue) { 449 if (!isset($instances[$ue->enrolid])) { 450 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid)); 451 } 452 $instance = $instances[$ue->enrolid]; 453 $ue->pstatus = ($ue->pstatus == ENROL_USER_ACTIVE + ENROL_INSTANCE_ENABLED) ? ENROL_USER_ACTIVE : ENROL_USER_SUSPENDED; 454 $ue->ptimeend = ($ue->ptimeend == 9999999999) ? 0 : (int)$ue->ptimeend; 455 $ue->ptimestart = ($ue->ptimestart == 9999999999) ? 0 : (int)$ue->ptimestart; 456 457 if ($ue->pstatus == ENROL_USER_ACTIVE and (!$ue->ptimeend || $ue->ptimeend > time()) 458 and !$syncall and $unenrolaction != ENROL_EXT_REMOVED_UNENROL) { 459 // this may be slow if very many users are ignored in sync 460 $parentcontext = context_course::instance($instance->customint1); 461 list($ignoreroles, $params) = $DB->get_in_or_equal($skiproles, SQL_PARAMS_NAMED, 'ri', false, -1); 462 $params['contextid'] = $parentcontext->id; 463 $params['userid'] = $ue->userid; 464 $select = "contextid = :contextid AND userid = :userid AND component <> 'enrol_meta' AND roleid $ignoreroles"; 465 if (!$DB->record_exists_select('role_assignments', $select, $params)) { 466 // bad luck, this user does not have any role we want in parent course 467 if ($verbose) { 468 mtrace(" skipping unsuspending: $ue->userid ==> $instance->courseid (user without role)"); 469 } 470 continue; 471 } 472 } 473 474 $meta->update_user_enrol($instance, $ue->userid, $ue->pstatus, $ue->ptimestart, $ue->ptimeend); 475 if ($verbose) { 476 if ($ue->pstatus == ENROL_USER_ACTIVE) { 477 mtrace(" unsuspending: $ue->userid ==> $instance->courseid"); 478 } else { 479 mtrace(" suspending: $ue->userid ==> $instance->courseid"); 480 } 481 } 482 } 483 $rs->close(); 484 485 486 // now assign all necessary roles 487 $enabled = explode(',', $CFG->enrol_plugins_enabled); 488 foreach($enabled as $k=>$v) { 489 if ($v === 'meta') { 490 continue; // no meta sync of meta roles 491 } 492 $enabled[$k] = 'enrol_'.$v; 493 } 494 $enabled[] = ''; // manual assignments are replicated too 495 496 $onecourse = $courseid ? "AND e.courseid = :courseid" : ""; 497 list($enabled, $params) = $DB->get_in_or_equal($enabled, SQL_PARAMS_NAMED, 'e'); 498 $params['coursecontext'] = CONTEXT_COURSE; 499 $params['courseid'] = $courseid; 500 $params['activeuser'] = ENROL_USER_ACTIVE; 501 $params['enabledinstance'] = ENROL_INSTANCE_ENABLED; 502 $sql = "SELECT DISTINCT pra.roleid, pra.userid, c.id AS contextid, e.id AS enrolid, e.courseid 503 FROM {role_assignments} pra 504 JOIN {user} u ON (u.id = pra.userid AND u.deleted = 0) 505 JOIN {context} pc ON (pc.id = pra.contextid AND pc.contextlevel = :coursecontext AND pra.component $enabled) 506 JOIN {enrol} e ON (e.customint1 = pc.instanceid AND e.enrol = 'meta' $onecourse AND e.status = :enabledinstance) 507 JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = u.id AND ue.status = :activeuser) 508 JOIN {context} c ON (c.contextlevel = pc.contextlevel AND c.instanceid = e.courseid) 509 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') 510 WHERE ra.id IS NULL"; 511 512 if ($ignored = $meta->get_config('nosyncroleids')) { 513 list($notignored, $xparams) = $DB->get_in_or_equal(explode(',', $ignored), SQL_PARAMS_NAMED, 'ig', false); 514 $params = array_merge($params, $xparams); 515 $sql = "$sql AND pra.roleid $notignored"; 516 } 517 518 $rs = $DB->get_recordset_sql($sql, $params); 519 foreach($rs as $ra) { 520 role_assign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_meta', $ra->enrolid); 521 if ($verbose) { 522 mtrace(" assigning role: $ra->userid ==> $ra->courseid as ".$allroles[$ra->roleid]->shortname); 523 } 524 } 525 $rs->close(); 526 527 528 // remove unwanted roles - include ignored roles and disabled plugins too 529 $onecourse = $courseid ? "AND e.courseid = :courseid" : ""; 530 $params = array(); 531 $params['coursecontext'] = CONTEXT_COURSE; 532 $params['courseid'] = $courseid; 533 $params['activeuser'] = ENROL_USER_ACTIVE; 534 $params['enabledinstance'] = ENROL_INSTANCE_ENABLED; 535 if ($ignored = $meta->get_config('nosyncroleids')) { 536 list($notignored, $xparams) = $DB->get_in_or_equal(explode(',', $ignored), SQL_PARAMS_NAMED, 'ig', false); 537 $params = array_merge($params, $xparams); 538 $notignored = "AND pra.roleid $notignored"; 539 } else { 540 $notignored = ""; 541 } 542 543 $sql = "SELECT ra.roleid, ra.userid, ra.contextid, ra.itemid, e.courseid 544 FROM {role_assignments} ra 545 JOIN {enrol} e ON (e.id = ra.itemid AND ra.component = 'enrol_meta' AND e.enrol = 'meta' $onecourse) 546 JOIN {context} pc ON (pc.instanceid = e.customint1 AND pc.contextlevel = :coursecontext) 547 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) 548 LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = ra.userid AND ue.status = :activeuser) 549 WHERE pra.id IS NULL OR ue.id IS NULL OR e.status <> :enabledinstance"; 550 551 if ($unenrolaction != ENROL_EXT_REMOVED_SUSPEND) { 552 $rs = $DB->get_recordset_sql($sql, $params); 553 foreach($rs as $ra) { 554 role_unassign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_meta', $ra->itemid); 555 if ($verbose) { 556 mtrace(" unassigning role: $ra->userid ==> $ra->courseid as ".$allroles[$ra->roleid]->shortname); 557 } 558 } 559 $rs->close(); 560 } 561 562 563 // kick out or suspend users without synced roles if syncall disabled 564 if (!$syncall) { 565 if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) { 566 $onecourse = $courseid ? "AND e.courseid = :courseid" : ""; 567 $params = array(); 568 $params['coursecontext'] = CONTEXT_COURSE; 569 $params['courseid'] = $courseid; 570 $sql = "SELECT ue.userid, ue.enrolid 571 FROM {user_enrolments} ue 572 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse) 573 JOIN {context} c ON (e.courseid = c.instanceid AND c.contextlevel = :coursecontext) 574 LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.itemid = e.id AND ra.userid = ue.userid) 575 WHERE ra.id IS NULL"; 576 $ues = $DB->get_recordset_sql($sql, $params); 577 foreach($ues as $ue) { 578 if (!isset($instances[$ue->enrolid])) { 579 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid)); 580 } 581 $instance = $instances[$ue->enrolid]; 582 $meta->unenrol_user($instance, $ue->userid); 583 if ($verbose) { 584 mtrace(" unenrolling: $ue->userid ==> $instance->courseid (user without role)"); 585 } 586 } 587 $ues->close(); 588 589 } else { 590 // just suspend the users 591 $onecourse = $courseid ? "AND e.courseid = :courseid" : ""; 592 $params = array(); 593 $params['coursecontext'] = CONTEXT_COURSE; 594 $params['courseid'] = $courseid; 595 $params['active'] = ENROL_USER_ACTIVE; 596 $sql = "SELECT ue.userid, ue.enrolid 597 FROM {user_enrolments} ue 598 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse) 599 JOIN {context} c ON (e.courseid = c.instanceid AND c.contextlevel = :coursecontext) 600 LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.itemid = e.id AND ra.userid = ue.userid) 601 WHERE ra.id IS NULL AND ue.status = :active"; 602 $ues = $DB->get_recordset_sql($sql, $params); 603 foreach($ues as $ue) { 604 if (!isset($instances[$ue->enrolid])) { 605 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid)); 606 } 607 $instance = $instances[$ue->enrolid]; 608 $meta->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED); 609 if ($verbose) { 610 mtrace(" suspending: $ue->userid ==> $instance->courseid (user without role)"); 611 } 612 } 613 $ues->close(); 614 } 615 } 616 617 // Finally sync groups. 618 $affectedusers = groups_sync_with_enrolment('meta', $courseid); 619 if ($verbose) { 620 foreach ($affectedusers['removed'] as $gm) { 621 mtrace("removing user from group: $gm->userid ==> $gm->courseid - $gm->groupname", 1); 622 } 623 foreach ($affectedusers['added'] as $ue) { 624 mtrace("adding user to group: $ue->userid ==> $ue->courseid - $ue->groupname", 1); 625 } 626 } 627 628 if ($verbose) { 629 mtrace('...user enrolment synchronisation finished.'); 630 } 631 632 return 0; 633 } 634 635 /** 636 * Create a new group with the course's name. 637 * 638 * @param int $courseid 639 * @param int $linkedcourseid 640 * @return int $groupid Group ID for this cohort. 641 */ 642 function enrol_meta_create_new_group($courseid, $linkedcourseid) { 643 global $DB, $CFG; 644 645 require_once($CFG->dirroot.'/group/lib.php'); 646 647 $coursename = $DB->get_field('course', 'fullname', array('id' => $linkedcourseid), MUST_EXIST); 648 $a = new stdClass(); 649 $a->name = $coursename; 650 $a->increment = ''; 651 $inc = 1; 652 $groupname = trim(get_string('defaultgroupnametext', 'enrol_meta', $a)); 653 // Check to see if the group name already exists in this course. Add an incremented number if it does. 654 while ($DB->record_exists('groups', array('name' => $groupname, 'courseid' => $courseid))) { 655 $a->increment = '(' . (++$inc) . ')'; 656 $groupname = trim(get_string('defaultgroupnametext', 'enrol_meta', $a)); 657 } 658 // Create a new group for the course meta sync. 659 $groupdata = new stdClass(); 660 $groupdata->courseid = $courseid; 661 $groupdata->name = $groupname; 662 $groupid = groups_create_group($groupdata); 663 664 return $groupid; 665 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body