Beispiel #1
0
 /**
  * Test that a record can be modified, and that the corresponding Moodle
  * user is modified.
  */
 public function test_canupdaterecordandsynctomoodle()
 {
     global $DB;
     require_once elispm::lib('lib.php');
     $this->load_csv_data();
     // Read a record.
     $src = new user(103, null, array(), false, array());
     $src->reset_custom_field_list();
     // Modify the data.
     $src->firstname = 'Testuser';
     $src->lastname = 'One';
     $src->field_sometext = 'boo';
     $src->field_sometextfrompm = 'bla';
     $src->save();
     // Read it back.
     $retr = new user($src->id, null, array(), false, array());
     $this->assertEquals($src->firstname, $retr->firstname);
     $this->assertEquals($src->lastname, $retr->lastname);
     // Check the Moodle user.
     $retr = $DB->get_record('user', array('id' => 100));
     profile_load_data($retr);
     fix_moodle_profile_fields($retr);
     $this->assertEquals($src->firstname, $retr->firstname);
     $this->assertEquals($src->lastname, $retr->lastname);
     // Check custom fields.
     $result = new moodle_recordset_phpunit_datatable('user_info_data', $DB->get_records('user_info_data', null, '', 'id, userid, fieldid, data'));
     $dataset = new PHPUnit_Extensions_Database_DataSet_CsvDataSet();
     $dataset->addTable('user_info_data', elispm::file('tests/fixtures/user_info_data.csv'));
     $dataset = new PHPUnit_Extensions_Database_DataSet_ReplacementDataSet($dataset);
     // Only the second text field should be changed; everything else should be the same.
     $dataset->addFullReplacement('Second text entry field', 'bla');
     $this->assertTablesEqual($dataset->getTable('user_info_data'), $result);
 }
Beispiel #2
0
/**
 * 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;
}
    /**
     * Validate new library method fix_moodle_profile_fields()
     */
    public function test_fix_moodle_profile_fields()
    {
        global $CFG;
        require_once $CFG->dirroot . '/user/profile/lib.php';
        require_once $CFG->dirroot . '/user/profile/definelib.php';
        require_once $CFG->dirroot . '/user/profile/field/menu/define.class.php';
        require_once $CFG->dirroot . '/user/profile/field/menu/field.class.php';
        require_once $CFG->dirroot . '/user/profile/field/checkbox/define.class.php';
        require_once $CFG->dirroot . '/user/profile/field/checkbox/field.class.php';
        require_once elis::lib('lib.php');
        require_once elis::lib('testlib.php');
        // Create a couple Moodle profile fields, one menu-of-choices
        $profiledefinemenu = new profile_define_menu();
        $data = new stdClass();
        $data->datatype = 'menu';
        $data->categoryid = 99999;
        $data->shortname = 'testfieldmenu';
        $data->name = 'testfieldmenu';
        $data->param1 = 'Option1
Option2';
        $data->defaultdata = 'Option2';
        $profiledefinemenu->define_save($data);
        $profiledefinecheckbox = new profile_define_checkbox();
        $data = new stdClass();
        $data->datatype = 'checkbox';
        $data->categoryid = 99999;
        $data->shortname = 'testfieldcheckbox';
        $data->name = 'testfieldcheckbox';
        $profiledefinecheckbox->define_save($data);
        $testuser = get_test_user();
        $testuser->profile_field_testfieldmenu = 'Option3';
        // illegal value
        $testuser->profile_field_testfieldcheckbox = 0;
        fix_moodle_profile_fields($testuser);
        $this->assertTrue(!$testuser->profile_field_testfieldcheckbox);
        $this->assertTrue(!isset($testuser->profile_field_testfieldmenu));
        $testuser->profile_field_testfieldmenu = 'Option1';
        // legal value
        $testuser->profile_field_testfieldcheckbox = 1;
        fix_moodle_profile_fields($testuser);
        $this->assertTrue($testuser->profile_field_testfieldcheckbox == 1);
        $this->assertTrue($testuser->profile_field_testfieldmenu == 'Option1');
    }
Beispiel #4
0
 /**
  * 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;
     }
 }
 /**
  * Validate that the import does not create bogus profile field data on user update
  */
 public function test_version1importvalidatesprofilefieldsonupdate()
 {
     global $CFG, $DB;
     // Run the "create user" import.
     $this->run_core_user_import(array());
     $userid = $DB->get_field('user', 'id', array('username' => 'rlipusername', 'mnethostid' => $CFG->mnet_localhost_id));
     // Create the category.
     $category = new stdClass();
     $category->sortorder = $DB->count_records('user_info_category') + 1;
     $category->id = $DB->insert_record('user_info_category', $category);
     // Try to insert bogus checkbox data.
     $this->create_profile_field('rlipcheckbox', 'checkbox', $category->id);
     $params = array('action' => 'update', 'username' => 'rlipusername', 'profile_field_rlipcheckbox' => '2');
     $this->run_core_user_import($params);
     $user = new stdClass();
     $user->id = $userid;
     profile_load_data($user);
     fix_moodle_profile_fields($user);
     $this->assertEquals(isset($user->profile_field_rlipcheckbox), false);
     // Try to insert bogus datetime data.
     $this->create_profile_field('rlipdatetime', 'datetime', $category->id);
     $params = array('action' => 'update', 'username' => 'rlipusername', 'profile_field_rlipdatetime' => '1000000000');
     $this->run_core_user_import($params);
     $user = new stdClass();
     $user->id = $userid;
     profile_load_data($user);
     fix_moodle_profile_fields($user);
     $this->assertEquals(isset($user->profile_field_rlipcheckbox), false);
     // Try to insert bogus menu data.
     $this->create_profile_field('rlipmenu', 'menu', $category->id, "rlipoption1\nrlipoption1B");
     $params = array('action' => 'update', 'username' => 'rlipusername', 'profile_field_rlipmenu' => 'rlipoption2');
     $this->run_core_user_import($params);
     $user = new stdClass();
     $user->id = $userid;
     profile_load_data($user);
     fix_moodle_profile_fields($user);
     $this->assertEquals(isset($user->profile_field_rlipcheckbox), false);
 }