/** * 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 object $user User object before delete * @return boolean always true */ function delete_user($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 . '/tag/lib.php'; // 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 tag_set('user', $user->id, array()); // unconditionally unenrol from all courses enrol_user_delete($user); // unenrol from all roles in all contexts role_unassign_all(array('userid' => $user->id)); // this might be slow but it is really needed - modules might do some extra cleanup! //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)); // last course access not necessary either $DB->delete_records('user_lastaccess', array('userid' => $user->id)); // now do a final accesslib cleanup - removes all role assignments in user context and context itself delete_context(CONTEXT_USER, $user->id); // workaround for bulk deletes of users with the same email address $delname = "{$user->email}." . time(); 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->timemodified = time(); $DB->update_record('user', $updateuser); // notify auth plugin - do not block the delete even when plugin fails $authplugin = get_auth_plugin($user->auth); $authplugin->user_delete($user); // any plugin that needs to cleanup should register this event events_trigger('user_deleted', $user); return true; }
/** * 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; }
/** * 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 . '/tag/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; } // 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 tag_set('user', $user->id, array()); // unconditionally unenrol from all courses enrol_user_delete($user); // unenrol from all roles in all contexts role_unassign_all(array('userid' => $user->id)); // this might be slow but it is really needed - modules might do some extra cleanup! //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)); // 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 session_kill_user($user->id); // now do a final accesslib cleanup - removes all role assignments in user context and context itself delete_context(CONTEXT_USER, $user->id); // workaround for bulk deletes of users with the same email address $delname = "{$user->email}." . time(); 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(); $DB->update_record('user', $updateuser); // Add this action to log add_to_log(SITEID, 'user', 'delete', "view.php?id={$user->id}", $user->firstname . ' ' . $user->lastname); // 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); // any plugin that needs to cleanup should register this event events_trigger('user_deleted', $user); return true; }