/** * Function to synchronize the curriculum data with the Moodle data. * * @param boolean $tomoodle Optional direction to synchronize the data. * @param boolean $strict_match Whether we should use the association table rather * than just check idnumbers when comparing to Moodle users * */ function synchronize_moodle_user($tomoodle = true, $createnew = false, $strict_match = true) { global $CFG; require_once $CFG->dirroot . '/admin/tool/uploaduser/locallib.php'; require_once elispm::lib('data/usermoodle.class.php'); require_once elis::lib('lib.php'); static $mu_loop_detect = array(); // Create a new Moodle user record to update with. if (!($muser = $this->get_moodleuser($strict_match)) && !$createnew) { return false; } $muserid = $muser ? $muser->id : false; if ($tomoodle) { // map PM user fields to Moodle user fields $mdlfieldmap = array('idnumber' => 'idnumber', 'username' => 'username', 'firstname' => 'firstname', 'lastname' => 'lastname', 'email' => 'email', 'address' => 'address', 'city' => 'city', 'country' => 'country', 'language' => 'lang'); // determine if the user is already noted as having been associated to a PM user if ($um = usermoodle::find(new field_filter('cuserid', $this->id))) { if ($um->valid()) { $um = $um->current(); // determine if the PM user idnumber was updated if ($um->idnumber != $this->idnumber) { // update the Moodle user with the new idnumber $muser = new stdClass(); $muser->id = $um->muserid; $muser->idnumber = $this->idnumber; $this->_db->update_record('user', $muser); // update the association table with the new idnumber $um->idnumber = $this->idnumber; $um->save(); } } } //try to update the idnumber of a matching Moodle user that //doesn't have an idnumber set yet $exists_params = array('username' => $this->username, 'mnethostid' => $CFG->mnet_localhost_id); if ($moodle_user = $this->_db->get_record('user', $exists_params)) { if (empty($moodle_user->idnumber)) { //potentially old data, so set the idnumber $moodle_user->idnumber = $this->idnumber; $this->_db->update_record('user', $moodle_user); $muserid = $moodle_user->id; } else { if ($this->idnumber != $moodle_user->idnumber) { //the username points to a pre-existing Moodle user //with a non-matching idnumber, so something horrible //happened return; } } } if ($createnew && !$muserid) { /// Add a new user $record = new stdClass(); foreach ($mdlfieldmap as $pmfield => $mdlfield) { if (isset($this->{$pmfield})) { $record->{$mdlfield} = $this->{$pmfield}; } } $record->password = $this->password === null ? '' : $this->password; $record->confirmed = 1; $record->mnethostid = $CFG->mnet_localhost_id; $record->timemodified = time(); $record->id = $this->_db->insert_record('user', $record); } else { if ($muserid) { /// Update an existing user $record = new stdClass(); $record->id = $muserid; foreach ($mdlfieldmap as $pmfield => $mdlfield) { if (isset($this->{$pmfield})) { $record->{$mdlfield} = $this->{$pmfield}; } } if (!empty($this->password)) { $record->password = $this->password; } $record->timemodified = time(); $this->_db->update_record('user', $record); } else { return true; } } // avoid update loops if (isset($mu_loop_detect[$this->id])) { return $record->id; } $mu_loop_detect[$this->id] = true; // synchronize profile fields $origrec = clone $record; profile_load_data($origrec); fix_moodle_profile_fields($origrec); $fields = field::get_for_context_level(CONTEXT_ELIS_USER); $mfields = $this->_db->get_records('user_info_field', array(), '', 'shortname'); $fields = $fields ? $fields : array(); $changed = false; require_once elis::plugin_file('elisfields_moodleprofile', 'custom_fields.php'); foreach ($fields as $field) { $field = new field($field); if (!moodle_profile_can_sync($field->shortname)) { continue; } if (isset($field->owners['moodle_profile']) && $field->owners['moodle_profile']->exclude == pm_moodle_profile::sync_to_moodle && isset($mfields[$field->shortname])) { $shortname = $field->shortname; $fieldname = "field_{$shortname}"; $mfieldname = "profile_{$fieldname}"; $mfieldvalue = isset($origrec->{$mfieldname}) ? $origrec->{$mfieldname} : null; if ($mfieldvalue != $this->{$fieldname}) { $record->{$mfieldname} = $this->{$fieldname}; $changed = true; sync_profile_field_settings_to_moodle($field); } } } $record = uu_pre_process_custom_profile_data($record); profile_save_data($record); if ($muserid) { if ($changed) { events_trigger('user_updated', $record); } } else { // if no user association record exists, create one $um = new usermoodle(); $um->cuserid = $this->id; $um->muserid = $record->id; $um->idnumber = $this->idnumber; $um->save(); events_trigger('user_created', $record); } unset($mu_loop_detect[$this->id]); return $record->id; } }
/** * Migrate a single Moodle user to the Program Management system. Will * only do this for users who have an idnumber set. * * @param object $mu Moodle user object * @return boolean Whether user was synchronized or not */ function pm_moodle_user_to_pm($mu) { global $CFG, $DB; require_once $CFG->dirroot . '/lib/moodlelib.php'; require_once elis::lib('data/customfield.class.php'); require_once elispm::lib('data/user.class.php'); require_once elispm::lib('data/usermoodle.class.php'); require_once elis::lib('data/data_filter.class.php'); require_once $CFG->dirroot . '/user/profile/lib.php'; require_once elis::lib('lib.php'); if (!isset($mu->id)) { return true; } // re-fetch, in case this is from a stale event $mu = $DB->get_record('user', array('id' => $mu->id)); if (user_not_fully_set_up($mu) || !$mu->confirmed) { // Prevent the sync if a bare-bones user record is being created by create_user_record // or Moodle user has not yet been confirmed. return true; } //not going to be concerned with city or password for now if (empty($mu->idnumber) && elis::$config->local_elisprogram->auto_assign_user_idnumber) { //make sure the current user's username does not match up with some other user's //idnumber (necessary since usernames and idnumbers aren't bound to one another) if (!$DB->record_exists('user', array('idnumber' => $mu->username))) { $mu->idnumber = $mu->username; $DB->update_record('user', $mu); } } // skip user if no ID number set if (empty($mu->idnumber)) { return true; } // track whether we're syncing an idnumber change over to the PM system $idnumber_updated = false; // track whether an associated Moodle user is linked to the current PM user $moodle_user_exists = false; // determine if the user is already noted as having been associated to a PM user // this will join to Moodle user and PM user table to ensure data correctness $filters = array(); $filters[] = new join_filter('muserid', 'user', 'id'); $filters[] = new join_filter('cuserid', user::TABLE, 'id'); $filters[] = new field_filter('muserid', $mu->id); if ($um = usermoodle::find($filters)) { if ($um->valid()) { $um = $um->current(); //signal that an associated user already exists $moodle_user_exists = true; // determine if the Moodle user idnumber was updated if ($um->idnumber != $mu->idnumber) { //signal that the idnumber was synced over $idnumber_updated = true; // update the PM user with the new idnumber $cmuser = new user(); $cmuser->id = $um->cuserid; $cmuser->idnumber = $mu->idnumber; $cmuser->save(); // update the association table with the new idnumber $um->idnumber = $mu->idnumber; $um->save(); } } } // find the linked PM user //filter for the basic condition on the Moodle user id $condition_filter = new field_filter('id', $mu->id); //filter for joining the association table $association_filter = new join_filter('muserid', 'user', 'id', $condition_filter); //outermost filter $filter = new join_filter('id', usermoodle::TABLE, 'cuserid', $association_filter); $cu = user::find($filter); if ($cu->valid()) { $cu = $cu->current(); } else { // if a user with the same username but different idnumber exists, // we can't sync over because it will violate PM user uniqueness // constraints $cu = user::find(new field_filter('username', $mu->username)); if ($cu->valid()) { return true; } // if no such PM user exists, create a new one $cu = new user(); $cu->transfercredits = 0; $cu->timecreated = time(); } // synchronize standard fields $cu->username = $mu->username; $cu->password = $mu->password; // only need to update the idnumber if it wasn't handled above if (!$idnumber_updated) { $cu->idnumber = $mu->idnumber; } $cu->firstname = $mu->firstname; $cu->lastname = $mu->lastname; $cu->email = $mu->email; $cu->address = $mu->address; $cu->city = $mu->city; $cu->country = $mu->country; if (!empty($mu->phone1)) { $cu->phone = $mu->phone1; } if (!empty($mu->phone2)) { $cu->phone2 = $mu->phone2; } if (!empty($mu->lang)) { $cu->language = $mu->lang; } $cu->timemodified = time(); // synchronize custom profile fields profile_load_data($mu); fix_moodle_profile_fields($mu); $fields = field::get_for_context_level(CONTEXT_ELIS_USER); $fields = $fields ? $fields : array(); require_once elis::plugin_file('elisfields_moodleprofile', 'custom_fields.php'); foreach ($fields as $field) { $field = new field($field); if (!moodle_profile_can_sync($field->shortname)) { continue; } if (isset($field->owners['moodle_profile']) && isset($mu->{"profile_field_{$field->shortname}"})) { // check if should sync user profile field settings if ($field->owners['moodle_profile']->exclude == pm_moodle_profile::sync_from_moodle) { sync_profile_field_settings_from_moodle($field); } $fieldname = "field_{$field->shortname}"; $cu->{$fieldname} = $mu->{"profile_field_{$field->shortname}"}; } } //specifically tell the user save not to use the local_elisprogram_usr_mdl for syncing //because the record hasn't been inserted yet (see below) try { $cu->save(false); } catch (Exception $ex) { if (in_cron()) { mtrace(get_string('record_not_created_reason', 'local_elisprogram', array('message' => $ex->getMessage() . " [{$mu->id}]"))); return false; } else { throw new Exception($ex->getMessage()); } } // if no user association record exists, create one if (!$moodle_user_exists) { $um = new usermoodle(); $um->cuserid = $cu->id; $um->muserid = $mu->id; $um->idnumber = $mu->idnumber; $um->save(); } return true; }
/** * Test validation of duplicates * @expectedException data_object_validation_exception */ public function test_usermoodlepreventsduplicateidnumber() { $this->load_csv_data(); $usermoodle = new usermoodle(array('cuserid' => 2, 'muserid' => 2, 'idnumber' => '__idnumber__phpunit_test2__')); $usermoodle->save(); }