@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Move "Delete User" action to user profiles

Summary:
Ref T4065. The existence of two separate edit workflows for users is broadly confusing to administrators.

I want to unify user administration and improve administration of system agent accounts. Particularly, I plan to:

- Give administrators limited access to profile editing of system agents (e.g., change profile picture).
- Give administrators limited access to Settings for system agents.
- Broadly, move all the weird old special editing into standard editing.

Test Plan:
- Hit all the errors (delete self, no username, wrong username).
- Deleted a user.
- Visited page as a non-admin, got 403'd.
- Viewed old edit UI.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T4065

Differential Revision: https://secure.phabricator.com/D8662

+136 -89
+2
src/__phutil_library_map__.php
··· 1805 1805 'PhabricatorPeopleApproveController' => 'applications/people/controller/PhabricatorPeopleApproveController.php', 1806 1806 'PhabricatorPeopleCalendarController' => 'applications/people/controller/PhabricatorPeopleCalendarController.php', 1807 1807 'PhabricatorPeopleController' => 'applications/people/controller/PhabricatorPeopleController.php', 1808 + 'PhabricatorPeopleDeleteController' => 'applications/people/controller/PhabricatorPeopleDeleteController.php', 1808 1809 'PhabricatorPeopleDisableController' => 'applications/people/controller/PhabricatorPeopleDisableController.php', 1809 1810 'PhabricatorPeopleEditController' => 'applications/people/controller/PhabricatorPeopleEditController.php', 1810 1811 'PhabricatorPeopleHovercardEventListener' => 'applications/people/event/PhabricatorPeopleHovercardEventListener.php', ··· 4608 4609 'PhabricatorPeopleApproveController' => 'PhabricatorPeopleController', 4609 4610 'PhabricatorPeopleCalendarController' => 'PhabricatorPeopleController', 4610 4611 'PhabricatorPeopleController' => 'PhabricatorController', 4612 + 'PhabricatorPeopleDeleteController' => 'PhabricatorPeopleController', 4611 4613 'PhabricatorPeopleDisableController' => 'PhabricatorPeopleController', 4612 4614 'PhabricatorPeopleEditController' => 'PhabricatorPeopleController', 4613 4615 'PhabricatorPeopleHovercardEventListener' => 'PhabricatorEventListener',
+1
src/applications/people/application/PhabricatorApplicationPeople.php
··· 43 43 'logs/' => 'PhabricatorPeopleLogsController', 44 44 'approve/(?P<id>[1-9]\d*)/' => 'PhabricatorPeopleApproveController', 45 45 'disable/(?P<id>[1-9]\d*)/' => 'PhabricatorPeopleDisableController', 46 + 'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorPeopleDeleteController', 46 47 'edit/(?:(?P<id>[1-9]\d*)/(?:(?P<view>\w+)/)?)?' 47 48 => 'PhabricatorPeopleEditController', 48 49 'ldap/' => 'PhabricatorPeopleLdapController',
+125
src/applications/people/controller/PhabricatorPeopleDeleteController.php
··· 1 + <?php 2 + 3 + final class PhabricatorPeopleDeleteController 4 + extends PhabricatorPeopleController { 5 + 6 + private $id; 7 + 8 + public function willProcessRequest(array $data) { 9 + $this->id = $data['id']; 10 + } 11 + 12 + public function processRequest() { 13 + $request = $this->getRequest(); 14 + $admin = $request->getUser(); 15 + 16 + $user = id(new PhabricatorPeopleQuery()) 17 + ->setViewer($admin) 18 + ->withIDs(array($this->id)) 19 + ->executeOne(); 20 + if (!$user) { 21 + return new Aphront404Response(); 22 + } 23 + 24 + $profile_uri = '/p/'.$user->getUsername(); 25 + 26 + if ($user->getPHID() == $admin->getPHID()) { 27 + return $this->buildDeleteSelfResponse($profile_uri); 28 + } 29 + 30 + $errors = array(); 31 + 32 + $v_username = ''; 33 + $e_username = true; 34 + if ($request->isFormPost()) { 35 + $v_username = $request->getStr('username'); 36 + 37 + if (!$v_username) { 38 + $errors[] = pht( 39 + 'You must type the username to confirm that you want to delete '. 40 + 'this user account.'); 41 + $e_username = pht('Required'); 42 + } else if ($v_username != $user->getUsername()) { 43 + $errors[] = pht( 44 + 'You must type the username correctly to confirm that you want '. 45 + 'to delete this user account.'); 46 + $e_username = pht('Incorrect'); 47 + } 48 + 49 + if (!$errors) { 50 + id(new PhabricatorUserEditor()) 51 + ->setActor($admin) 52 + ->deleteUser($user); 53 + 54 + $done_uri = $this->getApplicationURI(); 55 + 56 + return id(new AphrontRedirectResponse())->setURI($done_uri); 57 + } 58 + } 59 + 60 + $str1 = pht( 61 + 'Be careful when deleting users! This will permanently and '. 62 + 'irreversibly destroy this user account.'); 63 + 64 + $str2 = pht( 65 + 'If this user interacted with anything, it is generally better to '. 66 + 'disable them, not delete them. If you delete them, it will no longer '. 67 + 'be possible to (for example) search for objects they created, and you '. 68 + 'will lose other information about their history. Disabling them '. 69 + 'instead will prevent them from logging in but not destroy any of '. 70 + 'their data.'); 71 + 72 + $str3 = pht( 73 + 'It is generally safe to delete newly created users (and test users and '. 74 + 'so on), but less safe to delete established users. If possible, '. 75 + 'disable them instead.'); 76 + 77 + $form = id(new AphrontFormView()) 78 + ->setUser($admin) 79 + ->appendRemarkupInstructions( 80 + pht( 81 + 'To confirm that you want to permanently and irrevocably destroy '. 82 + 'this user account, type their username:')) 83 + ->appendChild( 84 + id(new AphrontFormStaticControl()) 85 + ->setLabel(pht('Username')) 86 + ->setValue($user->getUsername())) 87 + ->appendChild( 88 + id(new AphrontFormTextControl()) 89 + ->setLabel(pht('Confirm')) 90 + ->setValue($v_username) 91 + ->setName('username') 92 + ->setError($e_username)); 93 + 94 + if ($errors) { 95 + $errors = id(new AphrontErrorView())->setErrors($errors); 96 + } 97 + 98 + return $this->newDialog() 99 + ->setWidth(AphrontDialogView::WIDTH_FORM) 100 + ->setTitle(pht('Really Delete User?')) 101 + ->setShortTitle(pht('Delete User')) 102 + ->appendChild($errors) 103 + ->appendParagraph($str1) 104 + ->appendParagraph($str2) 105 + ->appendParagraph($str3) 106 + ->appendChild($form->buildLayoutView()) 107 + ->addSubmitButton(pht('Delete User')) 108 + ->addCancelButton($profile_uri); 109 + } 110 + 111 + private function buildDeleteSelfResponse($profile_uri) { 112 + return $this->newDialog() 113 + ->setTitle(pht('You Shall Journey No Farther')) 114 + ->appendParagraph( 115 + pht( 116 + 'As you stare into the gaping maw of the abyss, something '. 117 + 'holds you back.')) 118 + ->appendParagraph( 119 + pht( 120 + 'You can not delete your own account.')) 121 + ->addCancelButton($profile_uri, pht('Turn Back')); 122 + } 123 + 124 + 125 + }
-89
src/applications/people/controller/PhabricatorPeopleEditController.php
··· 44 44 if ($user->getIsSystemAgent()) { 45 45 $nav->addFilter('picture', pht('Set Account Picture')); 46 46 } 47 - $nav->addFilter('delete', pht('Delete User')); 48 47 49 48 if (!$user->getID()) { 50 49 $this->view = 'basic'; ··· 78 77 break; 79 78 case 'picture': 80 79 $response = $this->processSetAccountPicture($user); 81 - break; 82 - case 'delete': 83 - $response = $this->processDeleteRequest($user); 84 80 break; 85 81 default: 86 82 return new Aphront404Response(); ··· 567 563 568 564 $form_box = id(new PHUIObjectBoxView()) 569 565 ->setHeaderText(pht('Change Username')) 570 - ->setFormErrors($errors) 571 - ->setForm($form); 572 - 573 - return array($form_box); 574 - } 575 - 576 - private function processDeleteRequest(PhabricatorUser $user) { 577 - $request = $this->getRequest(); 578 - $admin = $request->getUser(); 579 - 580 - $far1 = pht('As you stare into the gaping maw of the abyss, something '. 581 - 'hold you back.'); 582 - $far2 = pht('You can not delete your own account.'); 583 - 584 - if ($user->getPHID() == $admin->getPHID()) { 585 - $error = new AphrontErrorView(); 586 - $error->setTitle(pht('You Shall Journey No Farther')); 587 - $error->appendChild(hsprintf( 588 - '<p>%s</p><p>%s</p>', $far1, $far2)); 589 - return $error; 590 - } 591 - 592 - $e_username = true; 593 - $username = null; 594 - 595 - $errors = array(); 596 - if ($request->isFormPost()) { 597 - 598 - $username = $request->getStr('username'); 599 - if (!strlen($username)) { 600 - $e_username = pht('Required'); 601 - $errors[] = pht('You must type the username to confirm deletion.'); 602 - } else if ($username != $user->getUsername()) { 603 - $e_username = pht('Invalid'); 604 - $errors[] = pht('You must type the username correctly.'); 605 - } 606 - 607 - if (!$errors) { 608 - id(new PhabricatorUserEditor()) 609 - ->setActor($admin) 610 - ->deleteUser($user); 611 - 612 - return id(new AphrontRedirectResponse())->setURI('/people/'); 613 - } 614 - } 615 - 616 - $str1 = pht('Be careful when deleting users!'); 617 - $str2 = pht('If this user interacted with anything, it is generally '. 618 - 'better to disable them, not delete them. If you delete them, it will '. 619 - 'no longer be possible to search for their objects, for example, '. 620 - 'and you will lose other information about their history. Disabling '. 621 - 'them instead will prevent them from logging in but not destroy '. 622 - 'any of their data.'); 623 - $str3 = pht('It is generally safe to delete newly created users (and '. 624 - 'test users and so on), but less safe to delete established users. '. 625 - 'If possible, disable them instead.'); 626 - 627 - $form = new AphrontFormView(); 628 - $form 629 - ->setUser($admin) 630 - ->setAction($request->getRequestURI()) 631 - ->appendChild(hsprintf( 632 - '<p class="aphront-form-instructions">'. 633 - '<strong>%s</strong> %s'. 634 - '</p>'. 635 - '<p class="aphront-form-instructions">'. 636 - '%s'. 637 - '</p>', $str1, $str2, $str3)) 638 - ->appendChild( 639 - id(new AphrontFormStaticControl()) 640 - ->setLabel(pht('Username')) 641 - ->setValue($user->getUsername())) 642 - ->appendChild( 643 - id(new AphrontFormTextControl()) 644 - ->setLabel(pht('Confirm')) 645 - ->setValue($username) 646 - ->setName('username') 647 - ->setCaption(pht("Type the username again to confirm deletion.")) 648 - ->setError($e_username)) 649 - ->appendChild( 650 - id(new AphrontFormSubmitControl()) 651 - ->setValue(pht('Delete User'))); 652 - 653 - $form_box = id(new PHUIObjectBoxView()) 654 - ->setHeaderText(pht('Delete User')) 655 566 ->setFormErrors($errors) 656 567 ->setForm($form); 657 568
+8
src/applications/people/controller/PhabricatorPeopleProfileController.php
··· 63 63 if ($viewer->getIsAdmin()) { 64 64 $actions->addAction( 65 65 id(new PhabricatorActionView()) 66 + ->setIcon('delete') 67 + ->setName(pht('Delete User')) 68 + ->setDisabled(($user->getPHID() == $viewer->getPHID())) 69 + ->setWorkflow(true) 70 + ->setHref($this->getApplicationURI('delete/'.$user->getID().'/'))); 71 + 72 + $actions->addAction( 73 + id(new PhabricatorActionView()) 66 74 ->setIcon('blame') 67 75 ->setName(pht('Administrate User')) 68 76 ->setHref($this->getApplicationURI('edit/'.$user->getID().'/')));