/** * Test user_update_user. */ public function test_user_update_user() { global $DB; $this->resetAfterTest(); // Create user and modify user profile. $user = $this->getDataGenerator()->create_user(); $user->firstname = 'Test'; $user->password = '******'; // Update user and capture event. $sink = $this->redirectEvents(); user_update_user($user); $events = $sink->get_events(); $sink->close(); $event = array_pop($events); // Test updated value. $dbuser = $DB->get_record('user', array('id' => $user->id)); $this->assertSame($user->firstname, $dbuser->firstname); $this->assertNotSame('M00dLe@T', $dbuser->password); // Test event. $this->assertInstanceOf('\\core\\event\\user_updated', $event); $this->assertSame($user->id, $event->objectid); $this->assertSame('user_updated', $event->get_legacy_eventname()); $this->assertEventLegacyData($dbuser, $event); $this->assertEquals(context_user::instance($user->id), $event->get_context()); $expectedlogdata = array(SITEID, 'user', 'update', 'view.php?id=' . $user->id, ''); $this->assertEventLegacyLogData($expectedlogdata, $event); // Update user with no password update. $password = $user->password = hash_internal_user_password('M00dLe@T'); user_update_user($user, false); $dbuser = $DB->get_record('user', array('id' => $user->id)); $this->assertSame($password, $dbuser->password); }
/** * Installs a site using $CFG->dataroot and $CFG->prefix * @throws coding_exception * @return void */ public static function install_site() { global $DB, $CFG; require_once $CFG->dirroot . '/user/lib.php'; if (!defined('BEHAT_UTIL')) { throw new coding_exception('This method can be only used by Behat CLI tool'); } // New dataroot. self::reset_dataroot(); $options = array(); $options['adminuser'] = '******'; $options['adminpass'] = '******'; $options['fullname'] = self::BEHATSITENAME; $options['shortname'] = self::BEHATSITENAME; install_cli_database($options, false); $frontpagesummary = new admin_setting_special_frontpagedesc(); $frontpagesummary->write_setting(self::BEHATSITENAME); // Update admin user info. $user = $DB->get_record('user', array('username' => 'admin')); $user->email = '*****@*****.**'; $user->firstname = 'Admin'; $user->lastname = 'User'; $user->city = 'Perth'; $user->country = 'AU'; user_update_user($user, false); // Disable email message processor. $DB->set_field('message_processors', 'enabled', '0', array('name' => 'email')); // Sets maximum debug level. set_config('debug', DEBUG_DEVELOPER); set_config('debugdisplay', true); // Keeps the current version of database and dataroot. self::store_versions_hash(); // Stores the database contents for fast reset. self::store_database_state(); }
/** * Install a site using $CFG->dataroot and $CFG->prefix * * @return string|bool true on success, else exception code. */ public static function install_site($sitefullname = "Performance test site", $siteshortname = "Performance test site", $adminpass = "******", $adminemail = "*****@*****.**") { global $DB, $CFG; require_once $CFG->dirroot . '/user/lib.php'; if (!defined('PERFORMANCE_SITE_GENERATOR')) { util::performance_exception('This method can be only used by performance site generator.'); } // If already installed, then return with error. $tables = $DB->get_tables(false); if (!empty($tables)) { return self::SITE_ERROR_INSTALLED; } $options = array(); $options['adminuser'] = '******'; $options['adminpass'] = $adminpass; $options['fullname'] = $sitefullname; $options['shortname'] = $siteshortname; install_cli_database($options, false); $frontpagesummary = new \admin_setting_special_frontpagedesc(); $frontpagesummary->write_setting($sitefullname); // Update admin user info. $user = $DB->get_record('user', array('username' => 'admin')); $user->email = $adminemail; $user->firstname = 'Admin'; $user->lastname = 'User'; $user->city = 'Perth'; $user->country = 'AU'; user_update_user($user, false); // Disable email message processor. $DB->set_field('message_processors', 'enabled', '0', array('name' => 'email')); // Disable some settings that are not wanted on test sites. set_config('noemailever', 1); // Enable web cron. set_config('cronclionly', 0); $CFG->dboptions = array('dbpersist' => 1); // Keeps the current version of components hash. self::store_versions_hash(); }
if ($user = $DB->get_record('user', array('id' => $suspend, 'mnethostid' => $CFG->mnet_localhost_id, 'deleted' => 0))) { if (!is_siteadmin($user) and $USER->id != $user->id and $user->suspended != 1) { $user->suspended = 1; // Force logout. \core\session\manager::kill_user_sessions($user->id); user_update_user($user, false); } } redirect($returnurl); } else { if ($unsuspend and confirm_sesskey()) { require_capability('moodle/user:update', $sitecontext); if ($user = $DB->get_record('user', array('id' => $unsuspend, 'mnethostid' => $CFG->mnet_localhost_id, 'deleted' => 0))) { if ($user->suspended != 0) { $user->suspended = 0; user_update_user($user, false); } } redirect($returnurl); } else { if ($unlock and confirm_sesskey()) { require_capability('moodle/user:update', $sitecontext); if ($user = $DB->get_record('user', array('id' => $unlock, 'mnethostid' => $CFG->mnet_localhost_id, 'deleted' => 0))) { login_unlock_account($user); } redirect($returnurl); } } } } }
/** * Performs the synchronisation of members. * * @return bool|void */ public function execute() { global $CFG, $DB; require_once $CFG->dirroot . '/enrol/lti/ims-blti/OAuth.php'; require_once $CFG->dirroot . '/enrol/lti/ims-blti/OAuthBody.php'; // Check if the authentication plugin is disabled. if (!is_enabled_auth('lti')) { mtrace('Skipping task - ' . get_string('pluginnotenabled', 'auth', get_string('pluginname', 'auth_lti'))); return true; } // Check if the enrolment plugin is disabled - isn't really necessary as the task should not run if // the plugin is disabled, but there is no harm in making sure core hasn't done something wrong. if (!enrol_is_enabled('lti')) { mtrace('Skipping task - ' . get_string('enrolisdisabled', 'enrol_lti')); return true; } // Get all the enabled tools. if ($tools = \enrol_lti\helper::get_lti_tools(array('status' => ENROL_INSTANCE_ENABLED, 'membersync' => 1))) { $ltiplugin = enrol_get_plugin('lti'); $consumers = array(); $currentusers = array(); $userphotos = array(); foreach ($tools as $tool) { mtrace("Starting - Member sync for shared tool '{$tool->id}' for the course '{$tool->courseid}'."); // Variables to keep track of information to display later. $usercount = 0; $enrolcount = 0; $unenrolcount = 0; // We check for all the users - users can access the same tool from different consumers. if ($ltiusers = $DB->get_records('enrol_lti_users', array('toolid' => $tool->id), 'lastaccess DESC')) { foreach ($ltiusers as $ltiuser) { $mtracecontent = "for the user '{$ltiuser->userid}' in the tool '{$tool->id}' for the course " . "'{$tool->courseid}'"; $usercount++; // Check if we do not have a membershipsurl - this can happen if the sync process has an unexpected error. if (!$ltiuser->membershipsurl) { mtrace("Skipping - Empty membershipsurl {$mtracecontent}."); continue; } // Check if we do not have a membershipsid - this can happen if the sync process has an unexpected error. if (!$ltiuser->membershipsid) { mtrace("Skipping - Empty membershipsid {$mtracecontent}."); continue; } $consumer = sha1($ltiuser->membershipsurl . ':' . $ltiuser->membershipsid . ':' . $ltiuser->consumerkey . ':' . $ltiuser->consumersecret); if (in_array($consumer, $consumers)) { // We have already synchronised with this consumer. continue; } $consumers[] = $consumer; $params = array('lti_message_type' => self::LTI_MESSAGE_TYPE, 'id' => $ltiuser->membershipsid, 'lti_version' => self::LTI_VERSION); mtrace("Calling memberships url '{$ltiuser->membershipsurl}' with body '" . json_encode($params) . "'"); try { $response = sendOAuthParamsPOST('POST', $ltiuser->membershipsurl, $ltiuser->consumerkey, $ltiuser->consumersecret, 'application/x-www-form-urlencoded', $params); } catch (\Exception $e) { mtrace("Skipping - No response received {$mtracecontent} from '{$ltiuser->membershipsurl}'"); mtrace($e->getMessage()); continue; } // Check the response from the consumer. $data = new \SimpleXMLElement($response); // Check if we did not receive a valid response. if (empty($data->statusinfo)) { mtrace("Skipping - Bad response received {$mtracecontent} from '{$ltiuser->membershipsurl}'"); mtrace('Skipping - Error parsing the XML received \'' . substr($response, 0, 125) . '\' ... (Displaying only 125 chars)'); continue; } // Check if we did not receive a valid response. if (strpos(strtolower($data->statusinfo->codemajor), 'success') === false) { mtrace('Skipping - Error received from the remote system: ' . $data->statusinfo->codemajor . ' ' . $data->statusinfo->severity . ' ' . $data->statusinfo->codeminor); continue; } $members = $data->memberships->member; mtrace(count($members) . ' members received.'); foreach ($members as $member) { // Set the user data. $user = new \stdClass(); $user->username = \enrol_lti\helper::create_username($ltiuser->consumerkey, $member->user_id); $user->firstname = \core_user::clean_field($member->person_name_given, 'firstname'); $user->lastname = \core_user::clean_field($member->person_name_family, 'lastname'); $user->email = \core_user::clean_field($member->person_contact_email_primary, 'email'); // Get the user data from the LTI consumer. $user = \enrol_lti\helper::assign_user_tool_data($tool, $user); if (!($dbuser = $DB->get_record('user', array('username' => $user->username, 'deleted' => 0)))) { if ($tool->membersyncmode == \enrol_lti\helper::MEMBER_SYNC_ENROL_AND_UNENROL || $tool->membersyncmode == \enrol_lti\helper::MEMBER_SYNC_ENROL_NEW) { // If the email was stripped/not set then fill it with a default one. This // stops the user from being redirected to edit their profile page. if (empty($user->email)) { $user->email = $user->username . "@example.com"; } $user->auth = 'lti'; $user->id = user_create_user($user); // Add the information to the necessary arrays. $currentusers[] = $user->id; $userphotos[$user->id] = $member->user_image; } } else { // If email is empty remove it, so we don't update the user with an empty email. if (empty($user->email)) { unset($user->email); } $user->id = $dbuser->id; user_update_user($user); // Add the information to the necessary arrays. $currentusers[] = $user->id; $userphotos[$user->id] = $member->user_image; } if ($tool->membersyncmode == \enrol_lti\helper::MEMBER_SYNC_ENROL_AND_UNENROL || $tool->membersyncmode == \enrol_lti\helper::MEMBER_SYNC_ENROL_NEW) { // Enrol the user in the course. \enrol_lti\helper::enrol_user($tool, $user->id); } } } // Now we check if we have to unenrol users who were not listed. if ($tool->membersyncmode == \enrol_lti\helper::MEMBER_SYNC_ENROL_AND_UNENROL || $tool->membersyncmode == \enrol_lti\helper::MEMBER_SYNC_UNENROL_MISSING) { // Go through the users and check if any were never listed, if so, remove them. foreach ($ltiusers as $ltiuser) { if (!in_array($ltiuser->userid, $currentusers)) { $instance = new \stdClass(); $instance->id = $tool->enrolid; $instance->courseid = $tool->courseid; $instance->enrol = 'lti'; $ltiplugin->unenrol_user($instance, $ltiuser->id); } } } } mtrace("Completed - Synced members for tool '{$tool->id}' in the course '{$tool->courseid}'. " . "Processed {$usercount} users; enrolled {$enrolcount} members; unenrolled {$unenrolcount} members."); mtrace(""); } // Sync the user profile photos. mtrace("Started - Syncing user profile images."); $counter = 0; if (!empty($userphotos)) { foreach ($userphotos as $userid => $url) { if ($url) { $result = \enrol_lti\helper::update_user_profile_image($userid, $url); if ($result === \enrol_lti\helper::PROFILE_IMAGE_UPDATE_SUCCESSFUL) { $counter++; mtrace("Profile image succesfully downloaded and created for user '{$userid}' from {$url}."); } else { mtrace($result); } } } } mtrace("Completed - Synced {$counter} profile images."); } }
/** * Installs a site using $CFG->dataroot and $CFG->prefix * @throws coding_exception * @return void */ public static function install_site() { global $DB, $CFG; require_once $CFG->dirroot . '/user/lib.php'; if (!defined('BEHAT_UTIL')) { throw new coding_exception('This method can be only used by Behat CLI tool'); } $tables = $DB->get_tables(false); if (!empty($tables)) { behat_error(BEHAT_EXITCODE_INSTALLED); } // New dataroot. self::reset_dataroot(); $options = array(); $options['adminuser'] = '******'; $options['adminpass'] = '******'; $options['fullname'] = self::BEHATSITENAME; $options['shortname'] = self::BEHATSITENAME; install_cli_database($options, false); // We need to keep the installed dataroot filedir files. // So each time we reset the dataroot before running a test, the default files are still installed. self::save_original_data_files(); $frontpagesummary = new admin_setting_special_frontpagedesc(); $frontpagesummary->write_setting(self::BEHATSITENAME); // Update admin user info. $user = $DB->get_record('user', array('username' => 'admin')); $user->email = '*****@*****.**'; $user->firstname = 'Admin'; $user->lastname = 'User'; $user->city = 'Perth'; $user->country = 'AU'; user_update_user($user, false); // Disable email message processor. $DB->set_field('message_processors', 'enabled', '0', array('name' => 'email')); // Sets maximum debug level. set_config('debug', DEBUG_DEVELOPER); set_config('debugdisplay', 1); // Disable some settings that are not wanted on test sites. set_config('noemailever', 1); // Enable web cron. set_config('cronclionly', 0); // Keeps the current version of database and dataroot. self::store_versions_hash(); // Stores the database contents for fast reset. self::store_database_state(); }
// Use a low cost factor when generating bcrypt hash otherwise // hashing would be slow when uploading lots of users. Hashes // will be automatically updated to a higher cost factor the first // time the user logs in. $existinguser->password = hash_internal_user_password($user->password, true); $upt->track('password', $user->password, 'normal', false); } else { // do not print password when not changed $upt->track('password', '', 'normal', false); } } } } if ($doupdate or $existinguser->password !== $oldpw) { // We want only users that were really updated. user_update_user($existinguser, false, false); $upt->track('status', $struserupdated); $usersupdated++; if (!$remoteuser) { // pre-process custom profile menu fields data from csv file $existinguser = uu_pre_process_custom_profile_data($existinguser); // save custom profile fields data from csv file profile_save_data($existinguser); } if ($bulk == UU_BULK_UPDATED or $bulk == UU_BULK_ALL) { if (!in_array($user->id, $SESSION->bulk_users)) { $SESSION->bulk_users[] = $user->id; } } // Trigger event. \core\event\user_updated::create_from_userid($existinguser->id)->trigger();
/** * Update users * * @param array $users * @return null * @since Moodle 2.2 */ public static function update_users($users) { global $CFG, $DB; require_once $CFG->dirroot . "/user/lib.php"; require_once $CFG->dirroot . "/user/profile/lib.php"; //required for customfields related function // Ensure the current user is allowed to run this function $context = context_system::instance(); require_capability('moodle/user:update', $context); self::validate_context($context); $params = self::validate_parameters(self::update_users_parameters(), array('users' => $users)); $transaction = $DB->start_delegated_transaction(); foreach ($params['users'] as $user) { if (empty($user['country'])) { //Allowing empty country leads to login issues. Let's not allow such updates continue; } user_update_user($user); //update user custom fields if (!empty($user['customfields'])) { foreach ($user['customfields'] as $customfield) { $user["profile_field_" . $customfield['type']] = $customfield['value']; //profile_save_data() saves profile file //it's expecting a user with the correct id, //and custom field to be named profile_field_"shortname" } profile_save_data((object) $user); events_trigger('user_updated', (object) $user); } //preferences if (!empty($user['preferences'])) { foreach ($user['preferences'] as $preference) { set_user_preference($preference['type'], $preference['value'], $user['id']); } } } $transaction->allow_commit(); return null; }
$user->email = $user->username . "@example.com"; } $user->auth = 'lti'; $user->id = user_create_user($user); // Get the updated user record. $user = $DB->get_record('user', array('id' => $user->id)); } else { if (\enrol_lti\helper::user_match($user, $dbuser)) { $user = $dbuser; } else { // If email is empty remove it, so we don't update the user with an empty email. if (empty($user->email)) { unset($user->email); } $user->id = $dbuser->id; user_update_user($user); // Get the updated user record. $user = $DB->get_record('user', array('id' => $user->id)); } } // Update user image. $image = false; if (!empty($ltirequest->info['user_image'])) { $image = $ltirequest->info['user_image']; } else { if (!empty($ltirequest->info['custom_user_image'])) { $image = $ltirequest->info['custom_user_image']; } } // Check if there is an image to process. if ($image) {
* 1. Update user profile. * 2. Save request data into request table. * 3. Take the user to the list of request and pass the message if the request was made * successfully. */ $profile = new stdClass(); $profile->id = $USER->id; $profile->firstname = $fromform->firstname; $profile->lastname = $fromform->lastname; $profile->email = $fromform->email; $profile->country = $fromform->country; $profile->city = $fromform->city; $profile->address = $fromform->address; $profile->phone1 = $fromform->phone1; // Update user. user_update_user($profile, false, true); // Reload from db. $user = $DB->get_record('user', array('id' => $profile->id), '*', MUST_EXIST); // Override old $USER session variable if needed. if ($USER->id == $user->id) { // Override old $USER session variable if needed. foreach ((array) $user as $variable => $value) { if ($variable === 'description' or $variable === 'password') { // These are not set for security nad perf reasons. continue; } $USER->{$variable} = $value; } } $today = time(); $request = new stdClass();
/** * Update users * * @param array $users * @return null * @since Moodle 2.2 */ public static function update_users($users) { global $CFG, $DB; require_once $CFG->dirroot . "/user/lib.php"; require_once $CFG->dirroot . "/user/profile/lib.php"; // Required for customfields related function. // Ensure the current user is allowed to run this function. $context = context_system::instance(); require_capability('moodle/user:update', $context); self::validate_context($context); $params = self::validate_parameters(self::update_users_parameters(), array('users' => $users)); $filemanageroptions = array('maxbytes' => $CFG->maxbytes, 'subdirs' => 0, 'maxfiles' => 1, 'accepted_types' => 'web_image'); $transaction = $DB->start_delegated_transaction(); foreach ($params['users'] as $user) { user_update_user($user, true, false); // Update user picture if it was specified for this user. if (empty($CFG->disableuserimages) && isset($user['userpicture'])) { $userobject = (object) $user; $userobject->deletepicture = null; if ($user['userpicture'] == 0) { $userobject->deletepicture = true; } else { $userobject->imagefile = $user['userpicture']; } core_user::update_picture($userobject, $filemanageroptions); } // Update user custom fields. if (!empty($user['customfields'])) { foreach ($user['customfields'] as $customfield) { // Profile_save_data() saves profile file it's expecting a user with the correct id, // and custom field to be named profile_field_"shortname". $user["profile_field_" . $customfield['type']] = $customfield['value']; } profile_save_data((object) $user); } // Trigger event. \core\event\user_updated::create_from_userid($user['id'])->trigger(); // Preferences. if (!empty($user['preferences'])) { foreach ($user['preferences'] as $preference) { set_user_preference($preference['type'], $preference['value'], $user['id']); } } } $transaction->allow_commit(); return null; }
/** * Create one or more users * * @param array $users An array of users to create. * @return array An array of arrays */ function create_users($users) { global $CFG, $DB; require_once $CFG->dirroot . "/user/lib.php"; require_once $CFG->dirroot . "/user/profile/lib.php"; //required for customfields related function //TODO: move the functions somewhere else as //they are "user" related $availableauths = get_plugin_list('auth'); $availablethemes = get_plugin_list('theme'); $availablelangs = get_string_manager()->get_list_of_translations(); $transaction = $DB->start_delegated_transaction(); $userids = array(); foreach ($users as $user) { // Make sure that the username doesn't already exist if ($DB->record_exists('user', array('username' => $user['username'], 'mnethostid' => $CFG->mnet_localhost_id))) { // $userids[] = array('id' => $user['id'], 'username' => $user['username'], 'error'=>'Username already exists: ' . $user['username']); $user_rec = $DB->get_record('user', array('username' => $user['username'])); $user['id'] = $user_rec->id; unset($user['password']); unset($user['auth']); user_update_user($user); $userids[] = array('id' => $user['id'], 'username' => $user['username'], 'error' => 'Updated'); continue; } // Make sure auth is valid if (empty($availableauths[$user['auth']])) { $userids[] = array('id' => $user['id'], 'username' => $user['username'], 'error' => 'Invalid authentication type: ' . $user['auth']); continue; } // Make sure lang is valid if (empty($availablelangs[$user['lang']])) { $userids[] = array('id' => $user['id'], 'username' => $user['username'], 'error' => 'Invalid language code: ' . $user['lang']); continue; } // Make sure lang is valid if (!empty($user['theme']) && empty($availablethemes[$user['theme']])) { //theme is VALUE_OPTIONAL, // so no default value. // We need to test if the client sent it // => !empty($user['theme']) $userids[] = array('id' => $user['id'], 'username' => $user['username'], 'error' => 'Invalid theme: ' . $user['theme']); continue; } // make sure there is no data loss during truncation $truncated = truncate_userinfo($user); foreach ($truncated as $key => $value) { if ($truncated[$key] !== $user[$key]) { $userids[] = array('id' => $user['id'], 'username' => $user['username'], 'error' => 'Property: ' . $key . ' is too long: ' . $user[$key]); continue; } } $user['confirmed'] = true; $user['mnethostid'] = $CFG->mnet_localhost_id; $user['id'] = user_create_user($user); // // custom fields // if (!empty($user['customfields'])) { // foreach ($user['customfields'] as $customfield) { // $user["profile_field_" . $customfield['type']] = $customfield['value']; //profile_save_data() saves profile file // //it's expecting a user with the correct id, // //and custom field to be named profile_field_"shortname" // } // profile_save_data((object)$user); // } // // //preferences // if (!empty($user['preferences'])) { // foreach ($user['preferences'] as $preference) { // set_user_preference($preference['type'], $preference['value'], $user['id']); // } // } $userids[] = array('id' => $user['id'], 'username' => $user['username'], 'error' => ""); } $transaction->allow_commit(); return $userids; }
/** * Handle OIDC disconnection from Moodle account. * * @param bool $justremovetokens If true, just remove the stored OIDC tokens for the user, otherwise revert login methods. */ public function disconnect($justremovetokens = false, \moodle_url $redirect = null) { if ($redirect === null) { $redirect = new \moodle_url('/auth/oidc/ucp.php'); } if ($justremovetokens === true) { global $USER, $DB, $CFG; // Delete token data. $DB->delete_records('auth_oidc_token', ['username' => $USER->username]); $eventdata = ['objectid' => $USER->id, 'userid' => $USER->id]; $event = \auth_oidc\event\user_disconnected::create($eventdata); $event->trigger(); redirect($redirect); } else { global $OUTPUT, $PAGE, $USER, $DB, $CFG; require_once $CFG->dirroot . '/user/lib.php'; $PAGE->set_url('/auth/oidc/ucp.php'); $PAGE->set_context(\context_system::instance()); $PAGE->set_pagelayout('standard'); $USER->editing = false; $ucptitle = get_string('ucp_disconnect_title', 'auth_oidc', $this->config->opname); $PAGE->navbar->add($ucptitle, $PAGE->url); $PAGE->set_title($ucptitle); // Check if we have recorded the user's previous login method. $prevmethodrec = $DB->get_record('auth_oidc_prevlogin', ['userid' => $USER->id]); $prevauthmethod = !empty($prevmethodrec) && is_enabled_auth($prevmethodrec->method) === true ? $prevmethodrec->method : null; // Manual is always available, we don't need it twice. if ($prevauthmethod === 'manual') { $prevauthmethod = null; } // We need either the user's previous method or the manual login plugin to be enabled for disconnection. if (empty($prevauthmethod) && is_enabled_auth('manual') !== true) { throw new \moodle_exception('errornodisconnectionauthmethod', 'auth_oidc'); } // Check to see if the user has a username created by OIDC, or a self-created username. // OIDC-created usernames are usually very verbose, so we'll allow them to choose a sensible one. // Otherwise, keep their existing username. $oidctoken = $DB->get_record('auth_oidc_token', ['username' => $USER->username]); $ccun = isset($oidctoken->oidcuniqid) && strtolower($oidctoken->oidcuniqid) === $USER->username ? true : false; $customdata = ['canchooseusername' => $ccun, 'prevmethod' => $prevauthmethod]; $mform = new \auth_oidc\form\disconnect('?action=disconnectlogin', $customdata); if ($mform->is_cancelled()) { redirect($redirect); } else { if ($fromform = $mform->get_data()) { $origusername = $USER->username; if (empty($fromform->newmethod) || $fromform->newmethod !== $prevauthmethod && $fromform->newmethod !== 'manual') { throw new \moodle_exception('errorauthdisconnectinvalidmethod', 'auth_oidc'); } $updateduser = new \stdClass(); if ($fromform->newmethod === 'manual') { if (empty($fromform->password)) { throw new \moodle_exception('errorauthdisconnectemptypassword', 'auth_oidc'); } if ($customdata['canchooseusername'] === true) { if (empty($fromform->username)) { throw new \moodle_exception('errorauthdisconnectemptyusername', 'auth_oidc'); } if (strtolower($fromform->username) !== $USER->username) { $newusername = strtolower($fromform->username); $usercheck = ['username' => $newusername, 'mnethostid' => $CFG->mnet_localhost_id]; if ($DB->record_exists('user', $usercheck) === false) { $updateduser->username = $newusername; } else { throw new \moodle_exception('errorauthdisconnectusernameexists', 'auth_oidc'); } } } $updateduser->auth = 'manual'; $updateduser->password = $fromform->password; } else { if ($fromform->newmethod === $prevauthmethod) { $updateduser->auth = $prevauthmethod; // We can't use user_update_user as it will rehash the value. if (!empty($prevmethodrec->password)) { $manualuserupdate = new \stdClass(); $manualuserupdate->id = $USER->id; $manualuserupdate->password = $prevmethodrec->password; $DB->update_record('user', $manualuserupdate); } } } // Update user. $updateduser->id = $USER->id; user_update_user($updateduser); // Delete token data. $DB->delete_records('auth_oidc_token', ['username' => $origusername]); $eventdata = ['objectid' => $USER->id, 'userid' => $USER->id]; $event = \auth_oidc\event\user_disconnected::create($eventdata); $event->trigger(); $USER = $DB->get_record('user', ['id' => $USER->id]); redirect($redirect); } } echo $OUTPUT->header(); $mform->display(); echo $OUTPUT->footer(); } }
/** * Update details for the current user * Password is passed in plaintext. * * @param object $user current user object * @param boolean $notify print notice with link and terminate */ public function user_update_details($user) { global $CFG, $DB, $USER; require_once $CFG->dirroot . '/user/profile/lib.php'; require_once $CFG->dirroot . '/user/lib.php'; if ($user->password == $user->confirmpassword and !empty($user->password)) { $plainpassword = $user->password; echo $plainpassword; $user->password = hash_internal_user_password($user->password); $this->user_update_password($user, $user->password); user_add_password_history($user->id, $plainpassword); } if (empty($user->calendartype)) { $user->calendartype = $CFG->calendartype; } try { $transaction = $DB->start_delegated_transaction(); user_update_user($user, false, false); $user->profile_field_yearlevel = empty($user->profile_field_yearlevel) ? 'N/A' : $user->profile_field_yearlevel; $user->profile_field_yearofbirth = empty($user->profile_field_yearofbirth) ? 'N/A' : $user->profile_field_yearofbirth; $user->profile_field_whereareyoufrom = empty($user->profile_field_whereareyoufrom) ? 'Perth' : $user->profile_field_whereareyoufrom; $USER->profile['yearlevel'] = $user->profile_field_yearlevel; $USER->profile['yearofbirth'] = $user->profile_field_yearofbirth; $USER->profile['whereareyoufrom'] = $user->profile_field_whereareyoufrom; profile_save_data($user); // Trigger event. \core\event\user_updated::create_from_userid($user->id)->trigger(); // Assuming the both inserts work, we get to the following line. $transaction->allow_commit(); } catch (Exception $e) { $transaction->rollback($e); return false; } return $this->update_user_session($user); }
/** * Override onLaunch with tool logic. * @return void */ protected function onLaunch() { global $DB, $SESSION, $CFG; // Check for valid consumer. if (empty($this->consumer) || $this->dataConnector->loadToolConsumer($this->consumer) === false) { $this->ok = false; $this->message = get_string('invalidtoolconsumer', 'enrol_lti'); return; } $url = helper::get_launch_url($this->tool->id); // If a tool proxy has been stored for the current consumer trying to access a tool, // check that the tool is being launched from the correct url. $correctlaunchurl = false; if (!empty($this->consumer->toolProxy)) { $proxy = json_decode($this->consumer->toolProxy); $handlers = $proxy->tool_profile->resource_handler; foreach ($handlers as $handler) { foreach ($handler->message as $message) { $handlerurl = new moodle_url($message->path); $fullpath = $handlerurl->out(false); if ($message->message_type == "basic-lti-launch-request" && $fullpath == $url) { $correctlaunchurl = true; break 2; } } } } else { if ($this->tool->secret == $this->consumer->secret) { // Test if the LTI1 secret for this tool is being used. Then we know the correct tool is being launched. $correctlaunchurl = true; } } if (!$correctlaunchurl) { $this->ok = false; $this->message = get_string('invalidrequest', 'enrol_lti'); return; } // Before we do anything check that the context is valid. $tool = $this->tool; $context = context::instance_by_id($tool->contextid); // Set the user data. $user = new stdClass(); $user->username = helper::create_username($this->consumer->getKey(), $this->user->ltiUserId); if (!empty($this->user->firstname)) { $user->firstname = $this->user->firstname; } else { $user->firstname = $this->user->getRecordId(); } if (!empty($this->user->lastname)) { $user->lastname = $this->user->lastname; } else { $user->lastname = $this->tool->contextid; } $user->email = core_user::clean_field($this->user->email, 'email'); // Get the user data from the LTI consumer. $user = helper::assign_user_tool_data($tool, $user); // Check if the user exists. if (!($dbuser = $DB->get_record('user', ['username' => $user->username, 'deleted' => 0]))) { // If the email was stripped/not set then fill it with a default one. This // stops the user from being redirected to edit their profile page. if (empty($user->email)) { $user->email = $user->username . "@example.com"; } $user->auth = 'lti'; $user->id = \user_create_user($user); // Get the updated user record. $user = $DB->get_record('user', ['id' => $user->id]); } else { if (helper::user_match($user, $dbuser)) { $user = $dbuser; } else { // If email is empty remove it, so we don't update the user with an empty email. if (empty($user->email)) { unset($user->email); } $user->id = $dbuser->id; \user_update_user($user); // Get the updated user record. $user = $DB->get_record('user', ['id' => $user->id]); } } // Update user image. if (isset($this->user) && isset($this->user->image) && !empty($this->user->image)) { $image = $this->user->image; } else { // Use custom_user_image parameter as a fallback. $image = $this->resourceLink->getSetting('custom_user_image'); } // Check if there is an image to process. if ($image) { helper::update_user_profile_image($user->id, $image); } // Check if we need to force the page layout to embedded. $isforceembed = $this->resourceLink->getSetting('custom_force_embed') == 1; // Check if we are an instructor. $isinstructor = $this->user->isStaff() || $this->user->isAdmin(); if ($context->contextlevel == CONTEXT_COURSE) { $courseid = $context->instanceid; $urltogo = new moodle_url('/course/view.php', ['id' => $courseid]); } else { if ($context->contextlevel == CONTEXT_MODULE) { $cm = get_coursemodule_from_id(false, $context->instanceid, 0, false, MUST_EXIST); $urltogo = new moodle_url('/mod/' . $cm->modname . '/view.php', ['id' => $cm->id]); // If we are a student in the course module context we do not want to display blocks. if (!$isforceembed && !$isinstructor) { $isforceembed = true; } } else { print_error('invalidcontext'); exit; } } // Force page layout to embedded if necessary. if ($isforceembed) { $SESSION->forcepagelayout = 'embedded'; } else { // May still be set from previous session, so unset it. unset($SESSION->forcepagelayout); } // Enrol the user in the course with no role. $result = helper::enrol_user($tool, $user->id); // Display an error, if there is one. if ($result !== helper::ENROLMENT_SUCCESSFUL) { print_error($result, 'enrol_lti'); exit; } // Give the user the role in the given context. $roleid = $isinstructor ? $tool->roleinstructor : $tool->rolelearner; role_assign($roleid, $user->id, $tool->contextid); // Login user. $sourceid = $this->user->ltiResultSourcedId; $serviceurl = $this->resourceLink->getSetting('lis_outcome_service_url'); // Check if we have recorded this user before. if ($userlog = $DB->get_record('enrol_lti_users', ['toolid' => $tool->id, 'userid' => $user->id])) { if ($userlog->sourceid != $sourceid) { $userlog->sourceid = $sourceid; } if ($userlog->serviceurl != $serviceurl) { $userlog->serviceurl = $serviceurl; } $userlog->lastaccess = time(); $DB->update_record('enrol_lti_users', $userlog); } else { // Add the user details so we can use it later when syncing grades and members. $userlog = new stdClass(); $userlog->userid = $user->id; $userlog->toolid = $tool->id; $userlog->serviceurl = $serviceurl; $userlog->sourceid = $sourceid; $userlog->consumerkey = $this->consumer->getKey(); $userlog->consumersecret = $tool->secret; $userlog->lastgrade = 0; $userlog->lastaccess = time(); $userlog->timecreated = time(); $userlog->membershipsurl = $this->resourceLink->getSetting('ext_ims_lis_memberships_url'); $userlog->membershipsid = $this->resourceLink->getSetting('ext_ims_lis_memberships_id'); $DB->insert_record('enrol_lti_users', $userlog); } // Finalise the user log in. complete_user_login($user); // Everything's good. Set appropriate OK flag and message values. $this->ok = true; $this->message = get_string('success'); if (empty($CFG->allowframembedding)) { // Provide an alternative link. $stropentool = get_string('opentool', 'enrol_lti'); echo html_writer::tag('p', get_string('frameembeddingnotenabled', 'enrol_lti')); echo html_writer::link($urltogo, $stropentool, ['target' => '_blank']); } else { // All done, redirect the user to where they want to go. redirect($urltogo); } }
public static function update_users($users) { global $CFG, $DB; require_once($CFG->dirroot."/user/lib.php"); require_once($CFG->dirroot."/user/profile/lib.php"); //required for customfields related function //TODO: move the functions somewhere else as //they are "user" related // Ensure the current user is allowed to run this function $context = get_context_instance(CONTEXT_SYSTEM); require_capability('moodle/user:update', $context); self::validate_context($context); $params = self::validate_parameters(self::update_users_parameters(), array('users'=>$users)); $transaction = $DB->start_delegated_transaction(); foreach ($params['users'] as $user) { user_update_user($user); //update user custom fields if(!empty($user['customfields'])) { foreach($user['customfields'] as $customfield) { $user["profile_field_".$customfield['type']] = $customfield['value']; //profile_save_data() saves profile file //it's expecting a user with the correct id, //and custom field to be named profile_field_"shortname" } profile_save_data((object) $user); } //preferences if (!empty($user['preferences'])) { foreach($user['preferences'] as $preference) { set_user_preference($preference['type'], $preference['value'],$user['id']); } } } $transaction->allow_commit(); return null; }
/** * Update users * * @param array $users * @return null * @since Moodle 2.2 */ public static function update_users($users) { global $CFG, $DB; require_once $CFG->dirroot . "/user/lib.php"; require_once $CFG->dirroot . "/user/profile/lib.php"; // Required for customfields related function. // Ensure the current user is allowed to run this function. $context = context_system::instance(); require_capability('moodle/user:update', $context); self::validate_context($context); $params = self::validate_parameters(self::update_users_parameters(), array('users' => $users)); $transaction = $DB->start_delegated_transaction(); foreach ($params['users'] as $user) { user_update_user($user, true, false); // Update user custom fields. if (!empty($user['customfields'])) { foreach ($user['customfields'] as $customfield) { // Profile_save_data() saves profile file it's expecting a user with the correct id, // and custom field to be named profile_field_"shortname". $user["profile_field_" . $customfield['type']] = $customfield['value']; } profile_save_data((object) $user); } // Trigger event. \core\event\user_updated::create_from_userid($user['id'])->trigger(); // Preferences. if (!empty($user['preferences'])) { foreach ($user['preferences'] as $preference) { set_user_preference($preference['type'], $preference['value'], $user['id']); } } } $transaction->allow_commit(); return null; }
/** * Proceed with the import of the user. * * @return void */ public function proceed() { if (!$this->prepared) { throw new coding_exception('The course has not been prepared.'); } else { if ($this->has_errors()) { throw new moodle_exception('Cannot proceed, errors were detected.'); } else { if ($this->processstarted) { throw new coding_exception('The process has already been started.'); } } } $this->processstarted = true; if ($this->do === self::DO_DELETE) { $this->finaldata = $this->existing; try { $success = delete_user($this->existing); } catch (moodle_exception $e) { $success = false; } if (!$success) { $this->error('usernotdeletederror', new lang_string('usernotdeletederror', 'tool_uploadusercli')); return false; } $this->set_status('userdeleted', new lang_string('userdeleted', 'tool_uploaduser')); return true; } else { if ($this->do === self::DO_CREATE) { try { $this->finaldata->id = user_create_user($this->finaldata, false, false); } catch (Exception $e) { $this->error('errorcreatinguser', new lang_string('errorcreatinguser', 'tool_uploadusercli')); return false; } if ($this->needpasswordchange) { set_user_preference('auth_forcepasswordchange', 1, $this->finaldata); $this->set_status('forcepasswordchange', new lang_string('forcepasswordchange', 'tool_uploadusercli')); } if ($this->finaldata->password === 'to be generated') { set_user_preference('create_password', 1, $this->finaldata); } $this->set_status('useradded', new lang_string('newuser')); } else { if ($this->do === self::DO_UPDATE) { try { user_update_user($this->finaldata, false, false); } catch (Exception $e) { $this->error('usernotupdatederror', new lang_string('usernotupdatederror', 'error')); return false; } if ($this->dologout) { \core\session\manager::kill_user_sessions($this->finaldata->id); } $this->set_status('useraccountupdated', new lang_string('useraccountupdated', 'tool_uploaduser')); } } } if ($this->do === self::DO_UPDATE || $this->do === self::DO_CREATE) { if (!$this->isremote) { $this->finaldata = uu_pre_process_custom_profile_data($this->finaldata); profile_save_data($this->finaldata); } $success = $this->add_to_cohort(); $success = $success && $this->add_to_egr(); if (!$success) { return false; } } return true; }
/** * will update a local user record from an external source. * is a lighter version of the one in moodlelib -- won't do * expensive ops such as enrolment. * * If you don't pass $updatekeys, there is a performance hit and * values removed from DB won't be removed from moodle. * * @param string $username username * @param bool $updatekeys * @return stdClass */ function update_user_record($username, $updatekeys = false) { global $CFG, $DB; //just in case check text case $username = trim(core_text::strtolower($username)); // get the current user record $user = $DB->get_record('user', array('username' => $username, 'mnethostid' => $CFG->mnet_localhost_id)); if (empty($user)) { // trouble error_log("Cannot update non-existent user: {$username}"); print_error('auth_dbusernotexist', 'auth_db', $username); die; } // Ensure userid is not overwritten. $userid = $user->id; $needsupdate = false; $updateuser = new stdClass(); $updateuser->id = $userid; if ($newinfo = $this->get_userinfo($username)) { $newinfo = truncate_userinfo($newinfo); if (empty($updatekeys)) { // All keys? This does not support removing values. $updatekeys = array_keys($newinfo); } foreach ($updatekeys as $key) { if (isset($newinfo[$key])) { $value = $newinfo[$key]; } else { $value = ''; } if (!empty($this->config->{'field_updatelocal_' . $key})) { if (isset($user->{$key}) and $user->{$key} != $value) { // Only update if it's changed. $needsupdate = true; $updateuser->{$key} = $value; } } } } if ($needsupdate) { require_once $CFG->dirroot . '/user/lib.php'; user_update_user($updateuser); } return $DB->get_record('user', array('id' => $userid, 'deleted' => 0)); }
/** * This function confirms the remote (ID provider) host's mnet session * by communicating the token and UA over the XMLRPC transport layer, and * returns the local user record on success. * * @param string $token The random session token. * @param mnet_peer $remotepeer The ID provider mnet_peer object. * @return array The local user record. */ function confirm_mnet_session($token, $remotepeer) { global $CFG, $DB; require_once $CFG->dirroot . '/mnet/xmlrpc/client.php'; require_once $CFG->libdir . '/gdlib.php'; require_once $CFG->dirroot . '/user/lib.php'; // verify the remote host is configured locally before attempting RPC call if (!($remotehost = $DB->get_record('mnet_host', array('wwwroot' => $remotepeer->wwwroot, 'deleted' => 0)))) { print_error('notpermittedtoland', 'mnet'); } // set up the RPC request $mnetrequest = new mnet_xmlrpc_client(); $mnetrequest->set_method('auth/mnet/auth.php/user_authorise'); // set $token and $useragent parameters $mnetrequest->add_param($token); $mnetrequest->add_param(sha1($_SERVER['HTTP_USER_AGENT'])); // Thunderbirds are go! Do RPC call and store response if ($mnetrequest->send($remotepeer) === true) { $remoteuser = (object) $mnetrequest->response; } else { foreach ($mnetrequest->error as $errormessage) { list($code, $message) = array_map('trim', explode(':', $errormessage, 2)); if ($code == 702) { $site = get_site(); print_error('mnet_session_prohibited', 'mnet', $remotepeer->wwwroot, format_string($site->fullname)); exit; } $message .= "ERROR {$code}:<br/>{$errormessage}<br/>"; } print_error("rpcerror", '', '', $message); } unset($mnetrequest); if (empty($remoteuser) or empty($remoteuser->username)) { print_error('unknownerror', 'mnet'); exit; } if (user_not_fully_set_up($remoteuser)) { print_error('notenoughidpinfo', 'mnet'); exit; } $remoteuser = mnet_strip_user($remoteuser, mnet_fields_to_import($remotepeer)); $remoteuser->auth = 'mnet'; $remoteuser->wwwroot = $remotepeer->wwwroot; // the user may roam from Moodle 1.x where lang has _utf8 suffix // also, make sure that the lang is actually installed, otherwise set site default if (isset($remoteuser->lang)) { $remoteuser->lang = clean_param(str_replace('_utf8', '', $remoteuser->lang), PARAM_LANG); } if (empty($remoteuser->lang)) { if (!empty($CFG->lang)) { $remoteuser->lang = $CFG->lang; } else { $remoteuser->lang = 'en'; } } $firsttime = false; // get the local record for the remote user $localuser = $DB->get_record('user', array('username' => $remoteuser->username, 'mnethostid' => $remotehost->id)); // add the remote user to the database if necessary, and if allowed // TODO: refactor into a separate function if (empty($localuser) || !$localuser->id) { /* if (empty($this->config->auto_add_remote_users)) { print_error('nolocaluser', 'mnet'); } See MDL-21327 for why this is commented out */ $remoteuser->mnethostid = $remotehost->id; $remoteuser->firstaccess = time(); // First time user in this server, grab it here $remoteuser->confirmed = 1; $remoteuser->id = $DB->insert_record('user', $remoteuser); $firsttime = true; $localuser = $remoteuser; } // check sso access control list for permission first if (!$this->can_login_remotely($localuser->username, $remotehost->id)) { print_error('sso_mnet_login_refused', 'mnet', '', array('user' => $localuser->username, 'host' => $remotehost->name)); } $fs = get_file_storage(); // update the local user record with remote user data foreach ((array) $remoteuser as $key => $val) { if ($key == '_mnet_userpicture_timemodified' and empty($CFG->disableuserimages) and isset($remoteuser->picture)) { // update the user picture if there is a newer verion at the identity provider $usercontext = context_user::instance($localuser->id, MUST_EXIST); if ($usericonfile = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f1.png')) { $localtimemodified = $usericonfile->get_timemodified(); } else { if ($usericonfile = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f1.jpg')) { $localtimemodified = $usericonfile->get_timemodified(); } else { $localtimemodified = 0; } } if (!empty($val) and $localtimemodified < $val) { mnet_debug('refetching the user picture from the identity provider host'); $fetchrequest = new mnet_xmlrpc_client(); $fetchrequest->set_method('auth/mnet/auth.php/fetch_user_image'); $fetchrequest->add_param($localuser->username); if ($fetchrequest->send($remotepeer) === true) { if (strlen($fetchrequest->response['f1']) > 0) { $imagefilename = $CFG->tempdir . '/mnet-usericon-' . $localuser->id; $imagecontents = base64_decode($fetchrequest->response['f1']); file_put_contents($imagefilename, $imagecontents); if ($newrev = process_new_icon($usercontext, 'user', 'icon', 0, $imagefilename)) { $localuser->picture = $newrev; } unlink($imagefilename); } // note that since Moodle 2.0 we ignore $fetchrequest->response['f2'] // the mimetype information provided is ignored and the type of the file is detected // by process_new_icon() } } } if ($key == 'myhosts') { $localuser->mnet_foreign_host_array = array(); foreach ($val as $rhost) { $name = clean_param($rhost['name'], PARAM_ALPHANUM); $url = clean_param($rhost['url'], PARAM_URL); $count = clean_param($rhost['count'], PARAM_INT); $url_is_local = stristr($url, $CFG->wwwroot); if (!empty($name) && !empty($count) && empty($url_is_local)) { $localuser->mnet_foreign_host_array[] = array('name' => $name, 'url' => $url, 'count' => $count); } } } $localuser->{$key} = $val; } $localuser->mnethostid = $remotepeer->id; if (empty($localuser->firstaccess)) { // Now firstaccess, grab it here $localuser->firstaccess = time(); } user_update_user($localuser, false); if (!$firsttime) { // repeat customer! let the IDP know about enrolments // we have for this user. // set up the RPC request $mnetrequest = new mnet_xmlrpc_client(); $mnetrequest->set_method('auth/mnet/auth.php/update_enrolments'); // pass username and an assoc array of "my courses" // with info so that the IDP can maintain mnetservice_enrol_enrolments $mnetrequest->add_param($remoteuser->username); $fields = 'id, category, sortorder, fullname, shortname, idnumber, summary, startdate, visible'; $courses = enrol_get_users_courses($localuser->id, false, $fields, 'visible DESC,sortorder ASC'); if (is_array($courses) && !empty($courses)) { // Second request to do the JOINs that we'd have done // inside enrol_get_users_courses() if we had been allowed $sql = "SELECT c.id,\n cc.name AS cat_name, cc.description AS cat_description\n FROM {course} c\n JOIN {course_categories} cc ON c.category = cc.id\n WHERE c.id IN (" . join(',', array_keys($courses)) . ')'; $extra = $DB->get_records_sql($sql); $keys = array_keys($courses); $studentroles = get_archetype_roles('student'); if (!empty($studentroles)) { $defaultrole = reset($studentroles); //$defaultrole = get_default_course_role($ccache[$shortname]); //TODO: rewrite this completely, there is no default course role any more!!! foreach ($keys as $id) { if ($courses[$id]->visible == 0) { unset($courses[$id]); continue; } $courses[$id]->cat_id = $courses[$id]->category; $courses[$id]->defaultroleid = $defaultrole->id; unset($courses[$id]->category); unset($courses[$id]->visible); $courses[$id]->cat_name = $extra[$id]->cat_name; $courses[$id]->cat_description = $extra[$id]->cat_description; $courses[$id]->defaultrolename = $defaultrole->name; // coerce to array $courses[$id] = (array) $courses[$id]; } } else { throw new moodle_exception('unknownrole', 'error', '', 'student'); } } else { // if the array is empty, send it anyway // we may be clearing out stale entries $courses = array(); } $mnetrequest->add_param($courses); // Call 0800-RPC Now! -- we don't care too much if it fails // as it's just informational. if ($mnetrequest->send($remotepeer) === false) { // error_log(print_r($mnetrequest->error,1)); } } return $localuser; }
/** * Update a local user record from an external source. * This is a lighter version of the one in moodlelib -- won't do * expensive ops such as enrolment. * * If you don't pass $updatekeys, there is a performance hit and * values removed from LDAP won't be removed from moodle. * * @param string $username username * @param boolean $updatekeys true to update the local record with the external LDAP values. * @param bool $triggerevent set false if user_updated event should not be triggered. * This will not affect user_password_updated event triggering. * @return stdClass|bool updated user record or false if there is no new info to update. */ function update_user_record($username, $updatekeys = false, $triggerevent = false) { global $CFG, $DB; // Just in case check text case $username = trim(core_text::strtolower($username)); // Get the current user record $user = $DB->get_record('user', array('username' => $username, 'mnethostid' => $CFG->mnet_localhost_id)); if (empty($user)) { // trouble error_log($this->errorlogtag . get_string('auth_dbusernotexist', 'auth_db', '', $username)); print_error('auth_dbusernotexist', 'auth_db', '', $username); die; } // Protect the userid from being overwritten $userid = $user->id; if ($newinfo = $this->get_userinfo($username)) { $newinfo = truncate_userinfo($newinfo); if (empty($updatekeys)) { // all keys? this does not support removing values $updatekeys = array_keys($newinfo); } if (!empty($updatekeys)) { $newuser = new stdClass(); $newuser->id = $userid; foreach ($updatekeys as $key) { if (isset($newinfo[$key])) { $value = $newinfo[$key]; } else { $value = ''; } if (!empty($this->config->{'field_updatelocal_' . $key})) { // Only update if it's changed. if ($user->{$key} != $value) { $newuser->{$key} = $value; } } } user_update_user($newuser, false, $triggerevent); } } else { return false; } return $DB->get_record('user', array('id' => $userid, 'deleted' => 0)); }
$forumform = new user_edit_forumng_form(null, array('id' => $userid, 'course' => $courseid, 'fid' => $cmid)); if ($user->maildigest == 2) { $user->maildigest = 1; } $forumform->set_data($user); $redirect = new moodle_url('/user/preferences.php', array('userid' => $user->id)); if ($cmid) { $redirect = new moodle_url('/mod/forumng/view.php', array('id' => $cmid)); } if ($forumform->is_cancelled()) { redirect($redirect); } else { if ($data = $forumform->get_data()) { $user->maildigest = $data->maildigest; $user->mailformat = $data->mailformat; user_update_user($user, false, true); if ($USER->id == $user->id) { $USER->maildigest = $data->maildigest; $USER->mailformat = $data->mailformat; } redirect($redirect); } } // Display page header. $streditmyforum = get_string('forumpreferences'); $userfullname = fullname($user, true); // Add forum info to breadcrumbs. if ($cmid) { $modinfo = get_fast_modinfo($courseid); $forum = $modinfo->get_cm($cmid); $PAGE->navbar->add(format_text($CFG->navshowfullcoursenames ? $course->fullname : $course->shortname), "/course/view.php?id={$courseid}");
/** * Parses the submitted form data and saves it into preferences array. * * @param stdClass $form preferences form class * @param array $preferences preferences array */ function process_form($form, &$preferences) { global $CFG; if (isset($form->email_email)) { $preferences['message_processor_email_email'] = $form->email_email; } if (isset($form->preference_mailcharset)) { $preferences['mailcharset'] = $form->preference_mailcharset; } if (isset($form->mailformat) && isset($form->userid)) { require_once $CFG->dirroot . '/user/lib.php'; $user = core_user::get_user($form->userid, '*', MUST_EXIST); $user->mailformat = clean_param($form->mailformat, PARAM_INT); user_update_user($user, false, false); } }
/** * Synchronizes user from external db to moodle user table. * * Sync should be done by using idnumber attribute, not username. * You need to pass firstsync parameter to function to fill in * idnumbers if they don't exists in moodle user table. * * Syncing users removes (disables) users that don't exists anymore in external db. * Creates new users and updates coursecreator status of users. * * This implementation is simpler but less scalable than the one found in the LDAP module. * * @param progress_trace $trace * @param bool $do_updates Optional: set to true to force an update of existing accounts * @return int 0 means success, 1 means failure */ function sync_users(progress_trace $trace, $do_updates = false) { global $CFG, $DB; // List external users. $userlist = $this->get_userlist(); // Delete obsolete internal users. if (!empty($this->config->removeuser)) { $suspendselect = ""; if ($this->config->removeuser == AUTH_REMOVEUSER_SUSPEND) { $suspendselect = "AND u.suspended = 0"; } // Find obsolete users. if (count($userlist)) { list($notin_sql, $params) = $DB->get_in_or_equal($userlist, SQL_PARAMS_NAMED, 'u', false); $params['authtype'] = $this->authtype; $sql = "SELECT u.*\n FROM {user} u\n WHERE u.auth=:authtype AND u.deleted=0 AND u.mnethostid=:mnethostid {$suspendselect} AND u.username {$notin_sql}"; } else { $sql = "SELECT u.*\n FROM {user} u\n WHERE u.auth=:authtype AND u.deleted=0 AND u.mnethostid=:mnethostid {$suspendselect}"; $params = array(); $params['authtype'] = $this->authtype; } $params['mnethostid'] = $CFG->mnet_localhost_id; $remove_users = $DB->get_records_sql($sql, $params); if (!empty($remove_users)) { require_once $CFG->dirroot . '/user/lib.php'; $trace->output(get_string('auth_dbuserstoremove', 'auth_db', count($remove_users))); foreach ($remove_users as $user) { if ($this->config->removeuser == AUTH_REMOVEUSER_FULLDELETE) { delete_user($user); $trace->output(get_string('auth_dbdeleteuser', 'auth_db', array('name' => $user->username, 'id' => $user->id)), 1); } else { if ($this->config->removeuser == AUTH_REMOVEUSER_SUSPEND) { $updateuser = new stdClass(); $updateuser->id = $user->id; $updateuser->suspended = 1; user_update_user($updateuser, false); $trace->output(get_string('auth_dbsuspenduser', 'auth_db', array('name' => $user->username, 'id' => $user->id)), 1); } } } } unset($remove_users); } if (!count($userlist)) { // Exit right here, nothing else to do. $trace->finished(); return 0; } // Update existing accounts. if ($do_updates) { // Narrow down what fields we need to update. $all_keys = array_keys(get_object_vars($this->config)); $updatekeys = array(); foreach ($all_keys as $key) { if (preg_match('/^field_updatelocal_(.+)$/', $key, $match)) { if ($this->config->{$key} === 'onlogin') { array_push($updatekeys, $match[1]); // The actual key name. } } } unset($all_keys); unset($key); // Only go ahead if we actually have fields to update locally. if (!empty($updatekeys)) { list($in_sql, $params) = $DB->get_in_or_equal($userlist, SQL_PARAMS_NAMED, 'u', true); $params['authtype'] = $this->authtype; $sql = "SELECT u.id, u.username\n FROM {user} u\n WHERE u.auth=:authtype AND u.deleted=0 AND u.username {$in_sql}"; if ($update_users = $DB->get_records_sql($sql, $params)) { $trace->output("User entries to update: " . count($update_users)); foreach ($update_users as $user) { if ($this->update_user_record($user->username, $updatekeys)) { $trace->output(get_string('auth_dbupdatinguser', 'auth_db', array('name' => $user->username, 'id' => $user->id)), 1); } else { $trace->output(get_string('auth_dbupdatinguser', 'auth_db', array('name' => $user->username, 'id' => $user->id)) . " - " . get_string('skipped'), 1); } } unset($update_users); } } } // Create missing accounts. // NOTE: this is very memory intensive and generally inefficient. $suspendselect = ""; if ($this->config->removeuser == AUTH_REMOVEUSER_SUSPEND) { $suspendselect = "AND u.suspended = 0"; } $sql = "SELECT u.id, u.username\n FROM {user} u\n WHERE u.auth=:authtype AND u.deleted='0' AND mnethostid=:mnethostid {$suspendselect}"; $users = $DB->get_records_sql($sql, array('authtype' => $this->authtype, 'mnethostid' => $CFG->mnet_localhost_id)); // Simplify down to usernames. $usernames = array(); if (!empty($users)) { foreach ($users as $user) { array_push($usernames, $user->username); } unset($users); } $add_users = array_diff($userlist, $usernames); unset($usernames); if (!empty($add_users)) { $trace->output(get_string('auth_dbuserstoadd', 'auth_db', count($add_users))); // Do not use transactions around this foreach, we want to skip problematic users, not revert everything. foreach ($add_users as $user) { $username = $user; if ($this->config->removeuser == AUTH_REMOVEUSER_SUSPEND) { if ($old_user = $DB->get_record('user', array('username' => $username, 'deleted' => 0, 'suspended' => 1, 'mnethostid' => $CFG->mnet_localhost_id, 'auth' => $this->authtype))) { $DB->set_field('user', 'suspended', 0, array('id' => $old_user->id)); $trace->output(get_string('auth_dbreviveduser', 'auth_db', array('name' => $username, 'id' => $old_user->id)), 1); continue; } } // Do not try to undelete users here, instead select suspending if you ever expect users will reappear. // Prep a few params. $user = $this->get_userinfo_asobj($user); $user->username = $username; $user->confirmed = 1; $user->auth = $this->authtype; $user->mnethostid = $CFG->mnet_localhost_id; if (empty($user->lang)) { $user->lang = $CFG->lang; } if (empty($user->calendartype)) { $user->calendartype = $CFG->calendartype; } $user->timecreated = time(); $user->timemodified = $user->timecreated; if ($collision = $DB->get_record_select('user', "username = :username AND mnethostid = :mnethostid AND auth <> :auth", array('username' => $user->username, 'mnethostid' => $CFG->mnet_localhost_id, 'auth' => $this->authtype), 'id,username,auth')) { $trace->output(get_string('auth_dbinsertuserduplicate', 'auth_db', array('username' => $user->username, 'auth' => $collision->auth)), 1); continue; } try { $id = $DB->insert_record('user', $user); // it is truly a new user $trace->output(get_string('auth_dbinsertuser', 'auth_db', array('name' => $user->username, 'id' => $id)), 1); } catch (moodle_exception $e) { $trace->output(get_string('auth_dbinsertusererror', 'auth_db', $user->username), 1); continue; } // If relevant, tag for password generation. if ($this->is_internal()) { set_user_preference('auth_forcepasswordchange', 1, $id); set_user_preference('create_password', 1, $id); } // Make sure user context is present. context_user::instance($id); } unset($add_users); } $trace->finished(); return 0; }
// This error should get caught before here anyhow, // so no need to translate this. This is just in case. :-) $error = 'Invalid characters in login.'; } else { if (empty($user)) { // Username cannot be blank. This is currently the only place // that calls addUser that is located in $user_inc. $error = $blankUserStr; } else { user_add_user($user, $upassword1, $ufirstname, $ulastname, $uemail, $uis_admin, $u_enabled); activity_log(0, $login, $user, LOG_USER_ADD, "{$ufirstname} {$ulastname}" . (empty($uemail) ? '' : " <{$uemail}>")); } } } } else { if (!empty($add) && !access_can_access_function(ACCESS_USER_MANAGEMENT)) { $error = print_not_auth(15); } else { // Don't allow a user to change themself to an admin by setting // uis_admin in the URL by hand. They must be admin beforehand. if (!$is_admin) { $uis_admin = 'N'; } user_update_user($user, $ufirstname, $ulastname, $uemail, $uis_admin, $uenabled); activity_log(0, $login, $user, LOG_USER_UPDATE, "{$ufirstname} {$ulastname}" . (empty($uemail) ? '' : " <{$uemail}>")); } } } } } echo error_check('users.php', false);
/** * Test badges assertion generated when a badge is issued. */ public function test_badges_assertion() { $this->preventResetByRollback(); // Messaging is not compatible with transactions. $badge = new badge($this->coursebadge); $this->assertFalse($badge->is_issued($this->user->id)); $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY)); $criteria_overall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE, 'badgeid' => $badge->id)); $criteria_overall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL, 'field_address' => 'address')); $this->user->address = 'Test address'; $sink = $this->redirectEmails(); user_update_user($this->user, false); $this->assertCount(1, $sink->get_messages()); $sink->close(); // Check if badge is awarded. $this->assertDebuggingCalled('Error baking badge image!'); $awards = $badge->get_awards(); $this->assertCount(1, $awards); // Get assertion. $award = reset($awards); $assertion = new core_badges_assertion($award->uniquehash); $testassertion = $this->assertion; // Make sure JSON strings have the same structure. $this->assertStringMatchesFormat($testassertion->badge, json_encode($assertion->get_badge_assertion())); $this->assertStringMatchesFormat($testassertion->class, json_encode($assertion->get_badge_class())); $this->assertStringMatchesFormat($testassertion->issuer, json_encode($assertion->get_issuer())); }
/** * Marks user deleted in internal user database and notifies the auth plugin. * Also unenrols user from all roles and does other cleanup. * * Any plugin that needs to purge user data should register the 'user_deleted' event. * * @param stdClass $user full user object before delete * @return boolean success * @throws coding_exception if invalid $user parameter detected */ function delete_user(stdClass $user) { global $CFG, $DB; require_once $CFG->libdir . '/grouplib.php'; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->dirroot . '/message/lib.php'; require_once $CFG->dirroot . '/user/lib.php'; // Make sure nobody sends bogus record type as parameter. if (!property_exists($user, 'id') or !property_exists($user, 'username')) { throw new coding_exception('Invalid $user parameter in delete_user() detected'); } // Better not trust the parameter and fetch the latest info this will be very expensive anyway. if (!($user = $DB->get_record('user', array('id' => $user->id)))) { debugging('Attempt to delete unknown user account.'); return false; } // There must be always exactly one guest record, originally the guest account was identified by username only, // now we use $CFG->siteguest for performance reasons. if ($user->username === 'guest' or isguestuser($user)) { debugging('Guest user account can not be deleted.'); return false; } // Admin can be theoretically from different auth plugin, but we want to prevent deletion of internal accoutns only, // if anything goes wrong ppl may force somebody to be admin via config.php setting $CFG->siteadmins. if ($user->auth === 'manual' and is_siteadmin($user)) { debugging('Local administrator accounts can not be deleted.'); return false; } // Allow plugins to use this user object before we completely delete it. if ($pluginsfunction = get_plugins_with_function('pre_user_delete')) { foreach ($pluginsfunction as $plugintype => $plugins) { foreach ($plugins as $pluginfunction) { $pluginfunction($user); } } } // Keep user record before updating it, as we have to pass this to user_deleted event. $olduser = clone $user; // Keep a copy of user context, we need it for event. $usercontext = context_user::instance($user->id); // Delete all grades - backup is kept in grade_grades_history table. grade_user_delete($user->id); // Move unread messages from this user to read. message_move_userfrom_unread2read($user->id); // TODO: remove from cohorts using standard API here. // Remove user tags. core_tag_tag::remove_all_item_tags('core', 'user', $user->id); // Unconditionally unenrol from all courses. enrol_user_delete($user); // Unenrol from all roles in all contexts. // This might be slow but it is really needed - modules might do some extra cleanup! role_unassign_all(array('userid' => $user->id)); // Now do a brute force cleanup. // Remove from all cohorts. $DB->delete_records('cohort_members', array('userid' => $user->id)); // Remove from all groups. $DB->delete_records('groups_members', array('userid' => $user->id)); // Brute force unenrol from all courses. $DB->delete_records('user_enrolments', array('userid' => $user->id)); // Purge user preferences. $DB->delete_records('user_preferences', array('userid' => $user->id)); // Purge user extra profile info. $DB->delete_records('user_info_data', array('userid' => $user->id)); // Purge log of previous password hashes. $DB->delete_records('user_password_history', array('userid' => $user->id)); // Last course access not necessary either. $DB->delete_records('user_lastaccess', array('userid' => $user->id)); // Remove all user tokens. $DB->delete_records('external_tokens', array('userid' => $user->id)); // Unauthorise the user for all services. $DB->delete_records('external_services_users', array('userid' => $user->id)); // Remove users private keys. $DB->delete_records('user_private_key', array('userid' => $user->id)); // Remove users customised pages. $DB->delete_records('my_pages', array('userid' => $user->id, 'private' => 1)); // Force logout - may fail if file based sessions used, sorry. \core\session\manager::kill_user_sessions($user->id); // Generate username from email address, or a fake email. $delemail = !empty($user->email) ? $user->email : $user->username . '.' . $user->id . '@unknownemail.invalid'; $delname = clean_param($delemail . "." . time(), PARAM_USERNAME); // Workaround for bulk deletes of users with the same email address. while ($DB->record_exists('user', array('username' => $delname))) { // No need to use mnethostid here. $delname++; } // Mark internal user record as "deleted". $updateuser = new stdClass(); $updateuser->id = $user->id; $updateuser->deleted = 1; $updateuser->username = $delname; // Remember it just in case. $updateuser->email = md5($user->username); // Store hash of username, useful importing/restoring users. $updateuser->idnumber = ''; // Clear this field to free it up. $updateuser->picture = 0; $updateuser->timemodified = time(); // Don't trigger update event, as user is being deleted. user_update_user($updateuser, false, false); // Now do a final accesslib cleanup - removes all role assignments in user context and context itself. context_helper::delete_instance(CONTEXT_USER, $user->id); // Any plugin that needs to cleanup should register this event. // Trigger event. $event = \core\event\user_deleted::create(array('objectid' => $user->id, 'relateduserid' => $user->id, 'context' => $usercontext, 'other' => array('username' => $user->username, 'email' => $user->email, 'idnumber' => $user->idnumber, 'picture' => $user->picture, 'mnethostid' => $user->mnethostid))); $event->add_record_snapshot('user', $olduser); $event->trigger(); // We will update the user's timemodified, as it will be passed to the user_deleted event, which // should know about this updated property persisted to the user's table. $user->timemodified = $updateuser->timemodified; // Notify auth plugin - do not block the delete even when plugin fails. $authplugin = get_auth_plugin($user->auth); $authplugin->user_delete($user); return true; }
/** * Test user_update_user. */ public function test_user_update_user() { global $DB; $this->resetAfterTest(); // Create user and modify user profile. $user = $this->getDataGenerator()->create_user(); $user->firstname = 'Test'; $user->password = '******'; // Update user and capture event. $sink = $this->redirectEvents(); user_update_user($user); $events = $sink->get_events(); $sink->close(); $event = array_pop($events); // Test updated value. $dbuser = $DB->get_record('user', array('id' => $user->id)); $this->assertSame($user->firstname, $dbuser->firstname); $this->assertNotSame('M00dLe@T', $dbuser->password); // Test event. $this->assertInstanceOf('\\core\\event\\user_updated', $event); $this->assertSame($user->id, $event->objectid); $this->assertSame('user_updated', $event->get_legacy_eventname()); $this->assertEventLegacyData($dbuser, $event); $this->assertEquals(context_user::instance($user->id), $event->get_context()); $expectedlogdata = array(SITEID, 'user', 'update', 'view.php?id=' . $user->id, ''); $this->assertEventLegacyLogData($expectedlogdata, $event); // Update user with no password update. $password = $user->password = hash_internal_user_password('M00dLe@T'); user_update_user($user, false); $dbuser = $DB->get_record('user', array('id' => $user->id)); $this->assertSame($password, $dbuser->password); // Verify event is not triggred by user_update_user when needed. $sink = $this->redirectEvents(); user_update_user($user, false, false); $events = $sink->get_events(); $sink->close(); $this->assertCount(0, $events); // With password, there should be 1 event. $sink = $this->redirectEvents(); user_update_user($user, true, false); $events = $sink->get_events(); $sink->close(); $this->assertCount(1, $events); $event = array_pop($events); $this->assertInstanceOf('\\core\\event\\user_password_updated', $event); // Test user data validation. $user->username = '******'; $user->auth = 'shibolth'; $user->country = 'WW'; $user->lang = 'xy'; $user->theme = 'somewrongthemename'; $user->timezone = 'Paris'; $user->url = 'wwww.somewrong@#$url.com.aus'; $debugmessages = $this->getDebuggingMessages(); user_update_user($user, true, false); $this->assertDebuggingCalledCount(6, $debugmessages); // Now, with valid user data. $user->username = '******'; $user->auth = 'shibboleth'; $user->country = 'AU'; $user->lang = 'en'; $user->theme = 'clean'; $user->timezone = 'Australia/Perth'; $user->url = 'www.moodle.org'; user_update_user($user, true, false); $this->assertDebuggingNotCalled(); }
$emailchanged = true; } } $authplugin = get_auth_plugin($user->auth); $usernew->timemodified = time(); // Description editor element may not exist! if (isset($usernew->description_editor) && isset($usernew->description_editor['format'])) { $usernew = file_postupdate_standard_editor($usernew, 'description', $editoroptions, $personalcontext, 'user', 'profile', 0); } // Pass a true old $user here. if (!$authplugin->user_update($user, $usernew)) { // Auth update failed. print_error('cannotupdateprofile'); } // Update user with new profile data. user_update_user($usernew, false, false); // Update preferences. useredit_update_user_preference($usernew); // Update interests. if (isset($usernew->interests)) { useredit_update_interests($usernew, $usernew->interests); } // Update user picture. if (empty($CFG->disableuserimages)) { useredit_update_picture($usernew, $userform, $filemanageroptions); } // Update mail bounces. useredit_update_bounces($user, $usernew); // Update forum track preference. useredit_update_trackforums($user, $usernew); // Save custom profile fields data.
/** * Performs synchronisation of member information and enrolments. * * @param stdClass $tool * @param ToolConsumer $consumer * @param User[] $members * @return array An array containing the number of members that were processed and the number of members that were enrolled. */ protected function sync_member_information(stdClass $tool, ToolConsumer $consumer, $members) { global $DB; $usercount = 0; $enrolcount = 0; // Process member information. foreach ($members as $member) { $usercount++; // Set the user data. $user = new stdClass(); $user->username = helper::create_username($consumer->getKey(), $member->ltiUserId); $user->firstname = core_user::clean_field($member->firstname, 'firstname'); $user->lastname = core_user::clean_field($member->lastname, 'lastname'); $user->email = core_user::clean_field($member->email, 'email'); // Get the user data from the LTI consumer. $user = helper::assign_user_tool_data($tool, $user); $dbuser = core_user::get_user_by_username($user->username, 'id'); if ($dbuser) { // If email is empty remove it, so we don't update the user with an empty email. if (empty($user->email)) { unset($user->email); } $user->id = $dbuser->id; user_update_user($user); // Add the information to the necessary arrays. if (!in_array($user->id, $this->currentusers)) { $this->currentusers[] = $user->id; } $this->userphotos[$user->id] = $member->image; } else { if ($this->should_sync_enrol($tool->membersyncmode)) { // If the email was stripped/not set then fill it with a default one. This // stops the user from being redirected to edit their profile page. if (empty($user->email)) { $user->email = $user->username . "@example.com"; } $user->auth = 'lti'; $user->id = user_create_user($user); // Add the information to the necessary arrays. $this->currentusers[] = $user->id; $this->userphotos[$user->id] = $member->image; } } // Sync enrolments. if ($this->should_sync_enrol($tool->membersyncmode)) { // Enrol the user in the course. if (helper::enrol_user($tool, $user->id) === helper::ENROLMENT_SUCCESSFUL) { // Increment enrol count. $enrolcount++; } // Check if this user has already been registered in the enrol_lti_users table. if (!$DB->record_exists('enrol_lti_users', ['toolid' => $tool->id, 'userid' => $user->id])) { // Create an initial enrol_lti_user record that we can use later when syncing grades and members. $userlog = new stdClass(); $userlog->userid = $user->id; $userlog->toolid = $tool->id; $userlog->consumerkey = $consumer->getKey(); $DB->insert_record('enrol_lti_users', $userlog); } } } return [$usercount, $enrolcount]; }