MDL-22780 sync ext db enrol when user logs in - except admins in case something goes really wrong in plugins

This commit is contained in:
Petr Skoda 2010-07-10 18:53:52 +00:00
parent 5f8354eb06
commit e384d2dc7b
2 changed files with 187 additions and 13 deletions

View File

@ -50,15 +50,180 @@ class enrol_database_plugin extends enrol_plugin {
}
/**
* Forces synchronisation of user enrolments with external database.
* Forces synchronisation of user enrolments with external database,
* does not create new courses.
*
* @param object $user user record
* @return void
*/
public function sync_user_enrolments($user = NULL) {
public function sync_user_enrolments($user) {
global $CFG, $DB;
//TODO: full sync with external system is very expensive, it could cause big perf problems if we did that during each log-in,
// so do the sync only once in a while or rely on cron
// we do not create courses here intentionally because it requires full sync and is slow
if (!$this->get_config('dbtype') or !$this->get_config('dbhost') or !$this->get_config('remoteenroltable') or !$this->get_config('remotecoursefield') or !$this->get_config('remoteuserfield')) {
return;
}
$table = $this->get_config('remoteenroltable');
$coursefield = strtolower($this->get_config('remotecoursefield'));
$userfield = strtolower($this->get_config('remoteuserfield'));
$rolefield = strtolower($this->get_config('remoterolefield'));
$localrolefield = $this->get_config('localrolefield');
$localuserfield = $this->get_config('localuserfield');
$localcoursefiled = $this->get_config('localcoursefield');
$unenrolaction = $this->get_config('unenrolaction');
$defaultrole = $this->get_config('defaultrole');
$ignorehidden = $this->get_config('ignorehiddencourses');
// create roles mapping
$allroles = get_all_roles();
if (!isset($allroles[$defaultrole])) {
$defaultrole = 0;
}
$roles = array();
foreach ($allroles as $role) {
$roles[$role->$localrolefield] = $role->id;
}
$enrols = array();
$instances = array();
$extdb = $this->db_init();
// read remote enrols and create instances
$sql = $this->db_get_sql($table, array($userfield=>$user->$localuserfield), array(), false);
if ($rs = $extdb->Execute($sql)) {
if (!$rs->EOF) {
while ($fields = $rs->FetchRow()) {
$fields = $this->db_decode($fields);
if (empty($fields[$coursefield])) {
// missing course info
continue;
}
if (!$course = $DB->get_record('course', array($localcoursefiled=>$fields[$coursefield]), 'id,visible')) {
continue;
}
if (!$course->visible and $ignorehidden) {
continue;
}
if (empty($fields[$rolefield]) or !isset($roles[$fields[$rolefield]])) {
if (!$defaultrole) {
// role is mandatory
continue;
}
$roleid = $defaultrole;
} else {
$roleid = $roles[$fields[$rolefield]];
}
if (empty($enrols[$course->id])) {
$enrols[$course->id] = array();
}
$enrols[$course->id][] = $roleid;
if ($instance = $DB->get_record('enrol', array('courseid'=>$course->id, 'enrol'=>'database'), '*', IGNORE_MULTIPLE)) {
$instances[$course->id] = $instance;
continue;
}
$enrolid = $this->add_instance($course);
$instances[$course->id] = $DB->get_record('enrol', array('id'=>$enrolid));
}
}
$rs->Close();
$extdb->Close();
} else {
// bad luck, something is wrong with the db connection
$extdb->Close();
return;
}
// enrol user into courses and sync roles
foreach ($enrols as $courseid => $roles) {
if (!isset($instances[$courseid])) {
// ignored
continue;
}
$instance = $instances[$courseid];
if ($e = $DB->get_record('user_enrolments', array('userid'=>$user->id, 'enrolid'=>$instance->id))) {
// reenable enrolment when previously disable enrolment refreshed
if ($e->status == ENROL_USER_SUSPENDED) {
$DB->set_field('user_enrolments', 'status', ENROL_USER_ACTIVE, array('enrolid'=>$instance->id, 'userid'=>$user->id));
}
} else {
$roleid = reset($roles);
$this->enrol_user($instance, $user->id, $roleid);
}
if (!$context = get_context_instance(CONTEXT_COURSE, $instance->courseid)) {
//weird
continue;
}
$current = $DB->get_records('role_assignments', array('contextid'=>$context->id, 'userid'=>$user->id, 'component'=>'enrol_database', 'itemid'=>$instance->id), '', 'id, roleid');
$existing = array();
foreach ($current as $r) {
if (in_array($r->id, $roles)) {
$existing[$r->roleid] = $r->roleid;
} else {
role_unassign($r->roleid, $user->id, $context->id, 'enrol_database', $instance->id);
}
}
foreach ($roles as $rid) {
if (!isset($existing[$rid])) {
role_assign($rid, $user->id, $context->id, 'enrol_database', $instance->id);
}
}
}
// unenrol as necessary
$sql = "SELECT e.*, c.visible AS cvisible, ue.status AS ustatus
FROM {enrol} e
JOIN {user_enrolments} ue ON ue.enrolid = e.id
JOIN {course} c ON c.id = e.courseid
WHERE ue.userid = :userid AND e.enrol = 'database'";
$rs = $DB->get_recordset_sql($sql, array('userid'=>$user->id));
foreach ($rs as $instance) {
if (!$instance->cvisible and $ignorehidden) {
continue;
}
if (!$context = get_context_instance(CONTEXT_COURSE, $instance->courseid)) {
//weird
continue;
}
if (!empty($enrols[$instance->courseid])) {
// we want this user enrolled
continue;
}
// deal with enrolments removed from external table
if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
// unenrol
$this->unenrol_user($instance, $user->id);
} else if ($unenrolaction == ENROL_EXT_REMOVED_KEEP) {
// keep - only adding enrolments
} else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND or $unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
// disable
if ($instance->ustatus != ENROL_USER_SUSPENDED) {
$DB->set_field('user_enrolments', 'status', ENROL_USER_SUSPENDED, array('enrolid'=>$instance->id, 'userid'=>$user->id));
}
if ($unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
role_unassign_all(array('contextid'=>$context->id, 'userid'=>$user->id, 'component'=>'enrol_database', 'itemid'=>$instance->id));
}
}
}
$rs->close();
}
/**
@ -81,17 +246,20 @@ class enrol_database_plugin extends enrol_plugin {
$extdb = $this->db_init();
// second step is to sync instances and users
$table = $this->get_config('remoteenroltable');
$coursefield = strtolower($this->get_config('remotecoursefield'));
$userfield = strtolower($this->get_config('remoteuserfield'));
$rolefield = strtolower($this->get_config('remoterolefield'));
$localrolefield = $this->get_config('localrolefield');
$localuserfield = $this->get_config('localuserfield');
$unenrolaction = $this->get_config('unenrolaction');
$table = $this->get_config('remoteenroltable');
$coursefield = strtolower($this->get_config('remotecoursefield'));
$userfield = strtolower($this->get_config('remoteuserfield'));
$rolefield = strtolower($this->get_config('remoterolefield'));
$localrolefield = $this->get_config('localrolefield');
$localuserfield = $this->get_config('localuserfield');
$localcoursefiled = $this->get_config('localcoursefield');
$unenrolaction = $this->get_config('unenrolaction');
$defaultrole = $this->get_config('defaultrole');
// create roles mapping
$allroles = get_all_roles();
$defaultrole = $this->get_config('defaultrole');
if (!isset($allroles[$defaultrole])) {
$defaultrole = 0;
}
@ -101,7 +269,6 @@ class enrol_database_plugin extends enrol_plugin {
}
// first find all existing courses with enrol instance
$localcoursefiled = $this->get_config('localcoursefield');
$sql = "SELECT c.id, c.visible, c.$localcoursefiled AS mapping, e.id AS enrolid
FROM {course} c
JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'database')";

View File

@ -186,6 +186,12 @@ function enrol_check_plugins($user) {
return;
}
if (is_siteadmin()) {
// no sync for admin user, please use admin accounts only for admin tasks like the unix root user!
// if plugin fails on sync admins need to be able to log in
return;
}
static $inprogress = array(); // To prevent this function being called more than once in an invocation
if (!empty($inprogress[$user->id])) {
@ -943,6 +949,7 @@ abstract class enrol_plugin {
if (!$ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid))) {
// weird, user not enrolled
echo "grrrr";
return;
}