示例#1
0
文件: lib.php 项目: jamesmcq/elis
/**
 * 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;
}
示例#2
0
 /**
  * Create a user-level ELIS field from an existing Moodle user profile field.
  *
  * @param int $mfieldid The ID of a Moodle user profile field.
  * @param field_category $category An ELIS field_category object to add the new field to.
  * @param boolean $syncdir Data Sync Direction.
  *                         Possible values:
  *                             false = no syncing
  *                             pm_moodle_profile::sync_from_moodle = sync from moodle.
  *                             pm_moodle_profile::sync_to_moodle = sync to moodle.
  * @return field The new field object.
  */
 public static function make_from_moodle_field($mfieldid, field_category $category, $syncdir = false)
 {
     require_once elis::file('eliscore/fields/manual/custom_fields.php');
     require_once elis::file('eliscore/fields/moodleprofile/custom_fields.php');
     global $DB;
     // Get moodle field information.
     $mfield = $DB->get_record('user_info_field', array('id' => $mfieldid));
     if (empty($mfield)) {
         return null;
     }
     if (!defined('CONTEXT_ELIS_USER')) {
         return null;
     }
     // Initially elis field data is the same as moodle field data.
     $field = (array) $mfield;
     unset($field['id']);
     $field['datatype'] = 'text';
     $field['categoryid'] = $category->id;
     // Manual field owner data.
     $fieldmanualowner = new field_owner();
     $fieldmanualowner->plugin = 'manual';
     $fieldmanualowner->param_control = $mfield->datatype;
     $fieldmanualowner->param_required = (bool) (int) $mfield->required;
     // Set data based on moodle field's datatype.
     switch ($mfield->datatype) {
         case static::CHECKBOX:
             $field['datatype'] = 'bool';
             break;
         case static::DATETIME:
             $field['datatype'] = 'datetime';
             $fieldmanualowner->param_startyear = $mfield->param1;
             $fieldmanualowner->param_stopyear = $mfield->param2;
             $fieldmanualowner->param_inctime = $mfield->param3;
             break;
         case static::MENU:
             $field['datatype'] = 'char';
             $fieldmanualowner->param_options = $mfield->param1;
             break;
         case static::TEXTAREA:
             $fieldmanualowner->param_columns = !empty($mfield->param1) ? $mfield->param1 : 30;
             $fieldmanualowner->param_rows = !empty($mfield->param2) ? $mfield->param2 : 10;
             break;
         case static::TEXT:
             if ($mfield->param3) {
                 $fieldmanualowner->param_control = 'password';
             }
             $fieldmanualowner->param_columns = $mfield->param1;
             $fieldmanualowner->param_maxlength = $mfield->param2;
             break;
     }
     // Create field.
     $field = new field($field);
     $field->save();
     // Create moodle profile owner.
     if ($syncdir === pm_moodle_profile::sync_from_moodle || $syncdir === pm_moodle_profile::sync_from_moodle) {
         $fieldmoodleprofileowner = new field_owner(array('fieldid' => $field->id, 'plugin' => 'moodle_profile', 'exclude' => $syncdir));
         $fieldmoodleprofileowner->save();
     }
     // Create manual owner.
     $fieldmanualowner->fieldid = $field->id;
     $fieldmanualowner->save();
     // Update field context level.
     static::ensure_field_exists_for_context_level($field, CONTEXT_ELIS_USER, $category);
     // Reload field object.
     $field = new field($field->id);
     $field->load();
     if ($syncdir === pm_moodle_profile::sync_from_moodle) {
         sync_profile_field_settings_from_moodle($field);
     }
     // Set default data.
     if (isset($mfield->defaultdata) && $mfield->defaultdata !== '') {
         field_data::set_for_context_and_field(null, $field, $mfield->defaultdata);
     }
     // Reload field object.
     $field = new field($field->id);
     $field->load();
     return $field;
 }
示例#3
0
/**
 * sync_profile_field_from_moodle function synchronizes ELIS custom user field from corresponding Moodle field if possible.
 * also syncs relevant field settings
 *
 * @param  object $field  the field object to sync
 * @return mixed          void or true (may throw DB exceptions)
 * @uses   $DB
 */
function sync_profile_field_from_moodle($field)
{
    global $DB;
    if (!isset($field->owners['moodle_profile']) || $field->owners['moodle_profile']->exclude == pm_moodle_profile::sync_to_moodle) {
        // not owned by the Moodle plugin, or set to sync to Moodle
        return true;
    }
    // check if sync is possible with current field settings
    if (!moodle_profile_can_sync($field->shortname)) {
        return true;
    }
    // Sync field settings first, since they could prevent field data sync
    sync_profile_field_settings_from_moodle($field);
    $dest = $field->data_table();
    $src = 'user_info_data';
    $mfieldid = $DB->get_field('user_info_field', 'id', array('shortname' => $field->shortname));
    $joins = 'JOIN {' . user::TABLE . '} cu ON usr.idnumber = cu.idnumber
              JOIN {context} ctx ON ctx.instanceid = cu.id AND ctx.contextlevel = ' . CONTEXT_ELIS_USER . '
              JOIN {' . $src . '} src ON src.userid = usr.id AND src.fieldid = ' . $mfieldid;
    // insert field values that don't already exist
    $sql = 'INSERT INTO {' . $dest . '}
            (contextid, fieldid, data)
            SELECT ctx.id AS contextid, ' . $field->id . ' AS fieldid, src.data
              FROM {user} usr
                   ' . $joins . '
         LEFT JOIN {' . $dest . '} dest ON dest.contextid = ctx.id AND dest.fieldid = ?
             WHERE dest.id IS NULL';
    $DB->execute($sql, array($field->id));
    // update already-existing values
    $sql = 'UPDATE {' . $dest . '} dest
              JOIN {user} usr
                   ' . $joins . '
               SET dest.data = src.data
             WHERE dest.fieldid = ?
               AND dest.contextid = ctx.id';
    $DB->execute($sql, array($field->id));
}
示例#4
0
 /**
  * Validate that Moodle & ELIS custom user field settings are synced.
  * @param array $moodlefielddata Array of moodle field params
  * @param array $elisfielddata Array of elis field, context & owner params
  * @param bool  $cansync True if Moodle & ELIS field should be sync-able
  * @param array $moodlefieldexpect Array of expected Moodle field values
  * @param array $elisfieldexpect Array of expected ELIS field/owner values
  * @uses $DB
  * @dataProvider customfieldsync_dataprovider
  */
 public function test_custom_user_field_settings_synced($moodlefielddata, $elisfielddata, $cansync, $moodlefieldexpect, $elisfieldexpect)
 {
     global $DB;
     // Create Moodle profile field with data.
     if (!empty($moodlefielddata)) {
         $DB->insert_record('user_info_field', (object) $moodlefielddata);
     }
     // Create ELIS field, context & owner data.
     $field = $this->build_elis_field_data($elisfielddata);
     $this->assertTrue(moodle_profile_can_sync($field->shortname) == $cansync);
     sync_profile_field_settings_to_moodle($field);
     sync_profile_field_settings_from_moodle($field);
     if (!empty($moodlefieldexpect)) {
         $mdlfield = $DB->get_record('user_info_field', array('shortname' => $field->shortname));
         foreach ($moodlefieldexpect as $key => $val) {
             $this->assertEquals($val, $mdlfield->{$key});
         }
     }
     $this->assert_elis_field_data($field, $elisfieldexpect);
 }