From e384d2dc7b98d332667baa74beb8368a217d869b Mon Sep 17 00:00:00 2001 From: Petr Skoda Date: Sat, 10 Jul 2010 18:53:52 +0000 Subject: [PATCH] MDL-22780 sync ext db enrol when user logs in - except admins in case something goes really wrong in plugins --- enrol/database/lib.php | 193 ++++++++++++++++++++++++++++++++++++++--- lib/enrollib.php | 7 ++ 2 files changed, 187 insertions(+), 13 deletions(-) diff --git a/enrol/database/lib.php b/enrol/database/lib.php index 7f30eafc566..a41bbb99e92 100644 --- a/enrol/database/lib.php +++ b/enrol/database/lib.php @@ -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')"; diff --git a/lib/enrollib.php b/lib/enrollib.php index 6e4727fb920..d05d97bbf5c 100644 --- a/lib/enrollib.php +++ b/lib/enrollib.php @@ -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; }