@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 admin promotions to modular transactions

Summary: Continue clean up of super-old code. I am pretty proud of "defrocked", but would also consider "dethroned", "ousted", "unseated", "unmade", or "disenfranchised". I feel like there's a word for being kicked out of Hogwarts and having your wizarding powers revoked, but it is not leaping to mind.

Test Plan: Promoted/demoted users to/from admin, attempted to demote myself and observed preserved witty text, checked user timelines, checked feed, checked DB for sanity, including `user_logs`. I didn't test exposing this via Conduit to attempt promoting a user without having admin access.

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: Korvin

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

+114 -51
+2
src/__phutil_library_map__.php
··· 4622 4622 'PhabricatorUserEditorTestCase' => 'applications/people/editor/__tests__/PhabricatorUserEditorTestCase.php', 4623 4623 'PhabricatorUserEmail' => 'applications/people/storage/PhabricatorUserEmail.php', 4624 4624 'PhabricatorUserEmailTestCase' => 'applications/people/storage/__tests__/PhabricatorUserEmailTestCase.php', 4625 + 'PhabricatorUserEmpowerTransaction' => 'applications/people/xaction/PhabricatorUserEmpowerTransaction.php', 4625 4626 'PhabricatorUserFerretEngine' => 'applications/people/search/PhabricatorUserFerretEngine.php', 4626 4627 'PhabricatorUserFulltextEngine' => 'applications/people/search/PhabricatorUserFulltextEngine.php', 4627 4628 'PhabricatorUserIconField' => 'applications/people/customfield/PhabricatorUserIconField.php', ··· 10683 10684 'PhabricatorUserEditorTestCase' => 'PhabricatorTestCase', 10684 10685 'PhabricatorUserEmail' => 'PhabricatorUserDAO', 10685 10686 'PhabricatorUserEmailTestCase' => 'PhabricatorTestCase', 10687 + 'PhabricatorUserEmpowerTransaction' => 'PhabricatorUserTransactionType', 10686 10688 'PhabricatorUserFerretEngine' => 'PhabricatorFerretEngine', 10687 10689 'PhabricatorUserFulltextEngine' => 'PhabricatorFulltextEngine', 10688 10690 'PhabricatorUserIconField' => 'PhabricatorUserCustomField',
+17 -12
src/applications/people/controller/PhabricatorPeopleEmpowerController.php
··· 22 22 $request, 23 23 $done_uri); 24 24 25 - if ($user->getPHID() == $viewer->getPHID()) { 26 - return $this->newDialog() 27 - ->setTitle(pht('Your Way is Blocked')) 28 - ->appendParagraph( 29 - pht( 30 - 'After a time, your efforts fail. You can not adjust your own '. 31 - 'status as an administrator.')) 32 - ->addCancelButton($done_uri, pht('Accept Fate')); 33 - } 25 + $validation_exception = null; 34 26 35 27 if ($request->isFormPost()) { 36 - id(new PhabricatorUserEditor()) 28 + $xactions = array(); 29 + $xactions[] = id(new PhabricatorUserTransaction()) 30 + ->setTransactionType( 31 + PhabricatorUserEmpowerTransaction::TRANSACTIONTYPE) 32 + ->setNewValue(!$user->getIsAdmin()); 33 + 34 + $editor = id(new PhabricatorUserTransactionEditor()) 37 35 ->setActor($viewer) 38 - ->makeAdminUser($user, !$user->getIsAdmin()); 36 + ->setContentSourceFromRequest($request) 37 + ->setContinueOnMissingFields(true); 39 38 40 - return id(new AphrontRedirectResponse())->setURI($done_uri); 39 + try { 40 + $editor->applyTransactions($user, $xactions); 41 + return id(new AphrontRedirectResponse())->setURI($done_uri); 42 + } catch (PhabricatorApplicationTransactionValidationException $ex) { 43 + $validation_exception = $ex; 44 + } 41 45 } 42 46 43 47 if ($user->getIsAdmin()) { ··· 60 64 } 61 65 62 66 return $this->newDialog() 67 + ->setValidationException($validation_exception) 63 68 ->setTitle($title) 64 69 ->setShortTitle($short) 65 70 ->appendParagraph($body)
-39
src/applications/people/editor/PhabricatorUserEditor.php
··· 131 131 132 132 /* -( Editing Roles )------------------------------------------------------ */ 133 133 134 - 135 - /** 136 - * @task role 137 - */ 138 - public function makeAdminUser(PhabricatorUser $user, $admin) { 139 - $actor = $this->requireActor(); 140 - 141 - if (!$user->getID()) { 142 - throw new Exception(pht('User has not been created yet!')); 143 - } 144 - 145 - $user->openTransaction(); 146 - $user->beginWriteLocking(); 147 - 148 - $user->reload(); 149 - if ($user->getIsAdmin() == $admin) { 150 - $user->endWriteLocking(); 151 - $user->killTransaction(); 152 - return $this; 153 - } 154 - 155 - $log = PhabricatorUserLog::initializeNewLog( 156 - $actor, 157 - $user->getPHID(), 158 - PhabricatorUserLog::ACTION_ADMIN); 159 - $log->setOldValue($user->getIsAdmin()); 160 - $log->setNewValue($admin); 161 - 162 - $user->setIsAdmin((int)$admin); 163 - $user->save(); 164 - 165 - $log->save(); 166 - 167 - $user->endWriteLocking(); 168 - $user->saveTransaction(); 169 - 170 - return $this; 171 - } 172 - 173 134 /** 174 135 * @task role 175 136 */
+95
src/applications/people/xaction/PhabricatorUserEmpowerTransaction.php
··· 1 + <?php 2 + 3 + final class PhabricatorUserEmpowerTransaction 4 + extends PhabricatorUserTransactionType { 5 + 6 + const TRANSACTIONTYPE = 'user.admin'; 7 + 8 + public function generateOldValue($object) { 9 + return (bool)$object->getIsAdmin(); 10 + } 11 + 12 + public function generateNewValue($object, $value) { 13 + return (bool)$value; 14 + } 15 + 16 + public function applyInternalEffects($object, $value) { 17 + $object->setIsAdmin((int)$value); 18 + } 19 + 20 + public function applyExternalEffects($object, $value) { 21 + $user = $object; 22 + 23 + $this->newUserLog(PhabricatorUserLog::ACTION_ADMIN) 24 + ->setOldValue($this->getOldValue()) 25 + ->setNewValue($value) 26 + ->save(); 27 + } 28 + 29 + public function validateTransactions($object, array $xactions) { 30 + $user = $object; 31 + $actor = $this->getActor(); 32 + 33 + $errors = array(); 34 + foreach ($xactions as $xaction) { 35 + $old = $xaction->getOldValue(); 36 + $new = $xaction->getNewValue(); 37 + 38 + if ($old === $new) { 39 + continue; 40 + } 41 + 42 + if ($user->getPHID() === $actor->getPHID()) { 43 + $errors[] = $this->newInvalidError( 44 + pht('After a time, your efforts fail. You can not adjust your own '. 45 + 'status as an administrator.'), $xaction); 46 + } 47 + 48 + if (!$actor->getIsAdmin()) { 49 + $errors[] = $this->newInvalidError( 50 + pht('You must be an administrator to create administrators.'), 51 + $xaction); 52 + } 53 + } 54 + 55 + return $errors; 56 + } 57 + 58 + public function getTitle() { 59 + $new = $this->getNewValue(); 60 + if ($new) { 61 + return pht( 62 + '%s empowered this user as an administrator.', 63 + $this->renderAuthor()); 64 + } else { 65 + return pht( 66 + '%s defrocked this user.', 67 + $this->renderAuthor()); 68 + } 69 + } 70 + 71 + public function getTitleForFeed() { 72 + $new = $this->getNewValue(); 73 + if ($new) { 74 + return pht( 75 + '%s empowered %s as an administrator.', 76 + $this->renderAuthor(), 77 + $this->renderObject()); 78 + } else { 79 + return pht( 80 + '%s defrocked %s.', 81 + $this->renderAuthor(), 82 + $this->renderObject()); 83 + } 84 + } 85 + 86 + public function getRequiredCapabilities( 87 + $object, 88 + PhabricatorApplicationTransaction $xaction) { 89 + 90 + // Unlike normal user edits, admin promotions require admin 91 + // permissions, which is enforced by validateTransactions(). 92 + 93 + return null; 94 + } 95 + }