mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-24 14:30:56 +01:00
Add an administrative tool for deleting users
Summary: Allow administrators to delete accounts if they jump through enough hoops. Also remove bogus caption about usernames being uneditable since we let admins edit those too now. Test Plan: Tried to delete myself. Deleted a non-myself user. Reviewers: csilvers, vrana Reviewed By: csilvers CC: aran Maniphest Tasks: T1184 Differential Revision: https://secure.phabricator.com/D2767
This commit is contained in:
parent
31fcd78c76
commit
957f9e2ec5
3 changed files with 163 additions and 2 deletions
|
@ -271,6 +271,77 @@ final class PhabricatorUserEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task role
|
||||||
|
*/
|
||||||
|
public function deleteUser(PhabricatorUser $user, $disable) {
|
||||||
|
$actor = $this->requireActor();
|
||||||
|
|
||||||
|
if (!$user->getID()) {
|
||||||
|
throw new Exception("User has not been created yet!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($actor->getPHID() == $user->getPHID()) {
|
||||||
|
throw new Exception("You can not delete yourself!");
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->openTransaction();
|
||||||
|
$ldaps = id(new PhabricatorUserLDAPInfo())->loadAllWhere(
|
||||||
|
'userID = %d',
|
||||||
|
$user->getID());
|
||||||
|
foreach ($ldaps as $ldap) {
|
||||||
|
$ldap->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
$oauths = id(new PhabricatorUserOAuthInfo())->loadAllWhere(
|
||||||
|
'userID = %d',
|
||||||
|
$user->getID());
|
||||||
|
foreach ($oauths as $oauth) {
|
||||||
|
$oauth->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
$prefs = id(new PhabricatorUserPreferences())->loadAllWhere(
|
||||||
|
'userPHID = %s',
|
||||||
|
$user->getPHID());
|
||||||
|
foreach ($prefs as $pref) {
|
||||||
|
$pref->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
$profiles = id(new PhabricatorUserProfile())->loadAllWhere(
|
||||||
|
'userPHID = %s',
|
||||||
|
$user->getPHID());
|
||||||
|
foreach ($profiles as $profile) {
|
||||||
|
$profile->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
$keys = id(new PhabricatorUserSSHKey())->loadAllWhere(
|
||||||
|
'userPHID = %s',
|
||||||
|
$user->getPHID());
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
$key->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
$emails = id(new PhabricatorUserEmail())->loadAllWhere(
|
||||||
|
'userPHID = %s',
|
||||||
|
$user->getPHID());
|
||||||
|
foreach ($emails as $email) {
|
||||||
|
$email->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
$log = PhabricatorUserLog::newLog(
|
||||||
|
$actor,
|
||||||
|
$user,
|
||||||
|
PhabricatorUserLog::ACTION_DELETE);
|
||||||
|
$log->save();
|
||||||
|
|
||||||
|
$user->delete();
|
||||||
|
|
||||||
|
$user->saveTransaction();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( Adding, Removing and Changing Email )-------------------------------- */
|
/* -( Adding, Removing and Changing Email )-------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ final class PhabricatorPeopleEditController
|
||||||
$nav->addFilter('cert', 'Conduit Certificate');
|
$nav->addFilter('cert', 'Conduit Certificate');
|
||||||
$nav->addSpacer();
|
$nav->addSpacer();
|
||||||
$nav->addFilter('rename', 'Change Username');
|
$nav->addFilter('rename', 'Change Username');
|
||||||
|
$nav->addFilter('delete', 'Delete User');
|
||||||
|
|
||||||
if (!$user->getID()) {
|
if (!$user->getID()) {
|
||||||
$this->view = 'basic';
|
$this->view = 'basic';
|
||||||
|
@ -83,6 +84,9 @@ final class PhabricatorPeopleEditController
|
||||||
case 'rename':
|
case 'rename':
|
||||||
$response = $this->processRenameRequest($user);
|
$response = $this->processRenameRequest($user);
|
||||||
break;
|
break;
|
||||||
|
case 'delete':
|
||||||
|
$response = $this->processDeleteRequest($user);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
@ -231,8 +235,7 @@ final class PhabricatorPeopleEditController
|
||||||
->setName('username')
|
->setName('username')
|
||||||
->setValue($user->getUsername())
|
->setValue($user->getUsername())
|
||||||
->setError($e_username)
|
->setError($e_username)
|
||||||
->setDisabled($is_immutable)
|
->setDisabled($is_immutable))
|
||||||
->setCaption('Usernames are permanent and can not be changed later!'))
|
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormTextControl())
|
id(new AphrontFormTextControl())
|
||||||
->setLabel('Real Name')
|
->setLabel('Real Name')
|
||||||
|
@ -565,7 +568,93 @@ final class PhabricatorPeopleEditController
|
||||||
return array($errors, $panel);
|
return array($errors, $panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function processDeleteRequest(PhabricatorUser $user) {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$admin = $request->getUser();
|
||||||
|
|
||||||
|
if ($user->getPHID() == $admin->getPHID()) {
|
||||||
|
$error = new AphrontErrorView();
|
||||||
|
$error->setTitle('You Shall Journey No Farther');
|
||||||
|
$error->appendChild(
|
||||||
|
'<p>As you stare into the gaping maw of the abyss, something holds '.
|
||||||
|
'you back.</p>'.
|
||||||
|
'<p>You can not delete your own account.</p>');
|
||||||
|
return $error;
|
||||||
|
}
|
||||||
|
|
||||||
|
$e_username = true;
|
||||||
|
$username = null;
|
||||||
|
|
||||||
|
$errors = array();
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
|
||||||
|
$username = $request->getStr('username');
|
||||||
|
if (!strlen($username)) {
|
||||||
|
$e_username = 'Required';
|
||||||
|
$errors[] = 'You must type the username to confirm deletion.';
|
||||||
|
} else if ($username != $user->getUsername()) {
|
||||||
|
$e_username = 'Invalid';
|
||||||
|
$errors[] = 'You must type the username correctly.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$errors) {
|
||||||
|
id(new PhabricatorUserEditor())
|
||||||
|
->setActor($admin)
|
||||||
|
->deleteUser($user);
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())->setURI('/people/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($errors) {
|
||||||
|
$errors = id(new AphrontErrorView())
|
||||||
|
->setTitle('Form Errors')
|
||||||
|
->setErrors($errors);
|
||||||
|
} else {
|
||||||
|
$errors = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$form = new AphrontFormView();
|
||||||
|
$form
|
||||||
|
->setUser($admin)
|
||||||
|
->setAction($request->getRequestURI())
|
||||||
|
->appendChild(
|
||||||
|
'<p class="aphront-form-instructions">'.
|
||||||
|
'<strong>Be careful when deleting users!</strong> '.
|
||||||
|
'If this user interacted with anything, it is generally better '.
|
||||||
|
'to disable them, not delete them. If you delete them, it will '.
|
||||||
|
'no longer be possible to search for their objects, for example, '.
|
||||||
|
'and you will lose other information about their history. Disabling '.
|
||||||
|
'them instead will prevent them from logging in but not destroy '.
|
||||||
|
'any of their data.'.
|
||||||
|
'</p>'.
|
||||||
|
'<p class="aphront-form-instructions">'.
|
||||||
|
'It is generally safe to delete newly created users (and test users '.
|
||||||
|
'and so on), but less safe to delete established users. If '.
|
||||||
|
'possible, disable them instead.'.
|
||||||
|
'</p>')
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormStaticControl())
|
||||||
|
->setLabel('Username')
|
||||||
|
->setValue($user->getUsername()))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setLabel('Confirm')
|
||||||
|
->setValue($username)
|
||||||
|
->setName('username')
|
||||||
|
->setCaption("Type the username again to confirm deletion.")
|
||||||
|
->setError($e_username))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormSubmitControl())
|
||||||
|
->setValue('Delete User'));
|
||||||
|
|
||||||
|
$panel = new AphrontPanelView();
|
||||||
|
$panel->setHeader('Delete User');
|
||||||
|
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
|
||||||
|
$panel->appendChild($form);
|
||||||
|
|
||||||
|
return array($errors, $panel);
|
||||||
|
}
|
||||||
|
|
||||||
private function getRoleInstructions() {
|
private function getRoleInstructions() {
|
||||||
$roles_link = phutil_render_tag(
|
$roles_link = phutil_render_tag(
|
||||||
|
|
|
@ -28,6 +28,7 @@ final class PhabricatorUserLog extends PhabricatorUserDAO {
|
||||||
|
|
||||||
const ACTION_ADMIN = 'admin';
|
const ACTION_ADMIN = 'admin';
|
||||||
const ACTION_DISABLE = 'disable';
|
const ACTION_DISABLE = 'disable';
|
||||||
|
const ACTION_DELETE = 'delete';
|
||||||
|
|
||||||
const ACTION_CONDUIT_CERTIFICATE = 'conduit-cert';
|
const ACTION_CONDUIT_CERTIFICATE = 'conduit-cert';
|
||||||
const ACTION_CONDUIT_CERTIFICATE_FAILURE = 'conduit-cert-fail';
|
const ACTION_CONDUIT_CERTIFICATE_FAILURE = 'conduit-cert-fail';
|
||||||
|
|
Loading…
Reference in a new issue