@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.

Allow contact numbers to be enabled and disabled

Summary: Depends on D20008. Ref T920. Continue fleshing out contact number behaviors.

Test Plan:
- Enabled and disabled a contact number.
- Saw list, detail views reflect change.
- Added number X, disabled it, added it again (allowed), enabled the disabled one ("already in use" exception).

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T920

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

+197 -1
+4
src/__phutil_library_map__.php
··· 2201 2201 'PhabricatorAuthConfirmLinkController' => 'applications/auth/controller/PhabricatorAuthConfirmLinkController.php', 2202 2202 'PhabricatorAuthContactNumber' => 'applications/auth/storage/PhabricatorAuthContactNumber.php', 2203 2203 'PhabricatorAuthContactNumberController' => 'applications/auth/controller/contact/PhabricatorAuthContactNumberController.php', 2204 + 'PhabricatorAuthContactNumberDisableController' => 'applications/auth/controller/contact/PhabricatorAuthContactNumberDisableController.php', 2204 2205 'PhabricatorAuthContactNumberEditController' => 'applications/auth/controller/contact/PhabricatorAuthContactNumberEditController.php', 2205 2206 'PhabricatorAuthContactNumberEditEngine' => 'applications/auth/editor/PhabricatorAuthContactNumberEditEngine.php', 2206 2207 'PhabricatorAuthContactNumberEditor' => 'applications/auth/editor/PhabricatorAuthContactNumberEditor.php', 2207 2208 'PhabricatorAuthContactNumberNumberTransaction' => 'applications/auth/xaction/PhabricatorAuthContactNumberNumberTransaction.php', 2208 2209 'PhabricatorAuthContactNumberPHIDType' => 'applications/auth/phid/PhabricatorAuthContactNumberPHIDType.php', 2209 2210 'PhabricatorAuthContactNumberQuery' => 'applications/auth/query/PhabricatorAuthContactNumberQuery.php', 2211 + 'PhabricatorAuthContactNumberStatusTransaction' => 'applications/auth/xaction/PhabricatorAuthContactNumberStatusTransaction.php', 2210 2212 'PhabricatorAuthContactNumberTransaction' => 'applications/auth/storage/PhabricatorAuthContactNumberTransaction.php', 2211 2213 'PhabricatorAuthContactNumberTransactionQuery' => 'applications/auth/query/PhabricatorAuthContactNumberTransactionQuery.php', 2212 2214 'PhabricatorAuthContactNumberTransactionType' => 'applications/auth/xaction/PhabricatorAuthContactNumberTransactionType.php', ··· 7904 7906 'PhabricatorDestructibleInterface', 7905 7907 ), 7906 7908 'PhabricatorAuthContactNumberController' => 'PhabricatorAuthController', 7909 + 'PhabricatorAuthContactNumberDisableController' => 'PhabricatorAuthContactNumberController', 7907 7910 'PhabricatorAuthContactNumberEditController' => 'PhabricatorAuthContactNumberController', 7908 7911 'PhabricatorAuthContactNumberEditEngine' => 'PhabricatorEditEngine', 7909 7912 'PhabricatorAuthContactNumberEditor' => 'PhabricatorApplicationTransactionEditor', 7910 7913 'PhabricatorAuthContactNumberNumberTransaction' => 'PhabricatorAuthContactNumberTransactionType', 7911 7914 'PhabricatorAuthContactNumberPHIDType' => 'PhabricatorPHIDType', 7912 7915 'PhabricatorAuthContactNumberQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 7916 + 'PhabricatorAuthContactNumberStatusTransaction' => 'PhabricatorAuthContactNumberTransactionType', 7913 7917 'PhabricatorAuthContactNumberTransaction' => 'PhabricatorModularTransaction', 7914 7918 'PhabricatorAuthContactNumberTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 7915 7919 'PhabricatorAuthContactNumberTransactionType' => 'PhabricatorModularTransactionType',
+2
src/applications/auth/application/PhabricatorAuthApplication.php
··· 111 111 'PhabricatorAuthContactNumberEditController', 112 112 '(?P<id>[1-9]\d*)/' => 113 113 'PhabricatorAuthContactNumberViewController', 114 + '(?P<action>disable|enable)/(?P<id>[1-9]\d*)/' => 115 + 'PhabricatorAuthContactNumberDisableController', 114 116 ), 115 117 ), 116 118
+87
src/applications/auth/controller/contact/PhabricatorAuthContactNumberDisableController.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthContactNumberDisableController 4 + extends PhabricatorAuthContactNumberController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $request->getViewer(); 8 + $id = $request->getURIData('id'); 9 + 10 + $number = id(new PhabricatorAuthContactNumberQuery()) 11 + ->setViewer($viewer) 12 + ->withIDs(array($id)) 13 + ->requireCapabilities( 14 + array( 15 + PhabricatorPolicyCapability::CAN_VIEW, 16 + PhabricatorPolicyCapability::CAN_EDIT, 17 + )) 18 + ->executeOne(); 19 + if (!$number) { 20 + return new Aphront404Response(); 21 + } 22 + 23 + $is_disable = ($request->getURIData('action') == 'disable'); 24 + $id = $number->getID(); 25 + $cancel_uri = $number->getURI(); 26 + 27 + if ($request->isFormPost()) { 28 + $xactions = array(); 29 + 30 + if ($is_disable) { 31 + $new_status = PhabricatorAuthContactNumber::STATUS_DISABLED; 32 + } else { 33 + $new_status = PhabricatorAuthContactNumber::STATUS_ACTIVE; 34 + } 35 + 36 + $xactions[] = id(new PhabricatorAuthContactNumberTransaction()) 37 + ->setTransactionType( 38 + PhabricatorAuthContactNumberStatusTransaction::TRANSACTIONTYPE) 39 + ->setNewValue($new_status); 40 + 41 + $editor = id(new PhabricatorAuthContactNumberEditor()) 42 + ->setActor($viewer) 43 + ->setContentSourceFromRequest($request) 44 + ->setContinueOnNoEffect(true) 45 + ->setContinueOnMissingFields(true); 46 + 47 + try { 48 + $editor->applyTransactions($number, $xactions); 49 + } catch (PhabricatorApplicationTransactionValidationException $ex) { 50 + // This happens when you enable a number which collides with another 51 + // number. 52 + return $this->newDialog() 53 + ->setTitle(pht('Changing Status Failed')) 54 + ->setValidationException($ex) 55 + ->addCancelButton($cancel_uri); 56 + } 57 + 58 + return id(new AphrontRedirectResponse())->setURI($cancel_uri); 59 + } 60 + 61 + $number_display = phutil_tag( 62 + 'strong', 63 + array(), 64 + $number->getDisplayName()); 65 + 66 + if ($is_disable) { 67 + $title = pht('Disable Contact Number'); 68 + $body = pht( 69 + 'Disable the contact number %s?', 70 + $number_display); 71 + $button = pht('Disable Number'); 72 + } else { 73 + $title = pht('Enable Contact Number'); 74 + $body = pht( 75 + 'Enable the contact number %s?', 76 + $number_display); 77 + $button = pht('Enable Number'); 78 + } 79 + 80 + return $this->newDialog() 81 + ->setTitle($title) 82 + ->appendParagraph($body) 83 + ->addSubmitButton($button) 84 + ->addCancelButton($cancel_uri); 85 + } 86 + 87 + }
+22
src/applications/auth/controller/contact/PhabricatorAuthContactNumberViewController.php
··· 54 54 ->setHeader($number->getObjectName()) 55 55 ->setPolicyObject($number); 56 56 57 + if ($number->isDisabled()) { 58 + $view->setStatus('fa-ban', 'red', pht('Disabled')); 59 + } 60 + 57 61 return $view; 58 62 } 59 63 ··· 91 95 ->setHref($this->getApplicationURI("contact/edit/{$id}/")) 92 96 ->setDisabled(!$can_edit) 93 97 ->setWorkflow(!$can_edit)); 98 + 99 + 100 + if ($number->isDisabled()) { 101 + $disable_uri = $this->getApplicationURI("contact/enable/{$id}/"); 102 + $disable_name = pht('Enable Contact Number'); 103 + $disable_icon = 'fa-check'; 104 + } else { 105 + $disable_uri = $this->getApplicationURI("contact/disable/{$id}/"); 106 + $disable_name = pht('Disable Contact Number'); 107 + $disable_icon = 'fa-ban'; 108 + } 109 + 110 + $curtain->addAction( 111 + id(new PhabricatorActionView()) 112 + ->setName($disable_name) 113 + ->setIcon($disable_icon) 114 + ->setHref($disable_uri) 115 + ->setWorkflow(true)); 94 116 95 117 return $curtain; 96 118 }
+23 -1
src/applications/auth/storage/PhabricatorAuthContactNumber.php
··· 93 93 } 94 94 95 95 public function save() { 96 - $this->uniqueKey = $this->newUniqueKey(); 96 + // We require that active contact numbers be unique, but it's okay to 97 + // disable a number and then reuse it somewhere else. 98 + if ($this->isDisabled()) { 99 + $this->uniqueKey = null; 100 + } else { 101 + $this->uniqueKey = $this->newUniqueKey(); 102 + } 103 + 97 104 return parent::save(); 105 + } 106 + 107 + public static function getStatusNameMap() { 108 + return ipull(self::getStatusPropertyMap(), 'name'); 109 + } 110 + 111 + private static function getStatusPropertyMap() { 112 + return array( 113 + self::STATUS_ACTIVE => array( 114 + 'name' => pht('Active'), 115 + ), 116 + self::STATUS_DISABLED => array( 117 + 'name' => pht('Disabled'), 118 + ), 119 + ); 98 120 } 99 121 100 122
+59
src/applications/auth/xaction/PhabricatorAuthContactNumberStatusTransaction.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthContactNumberStatusTransaction 4 + extends PhabricatorAuthContactNumberTransactionType { 5 + 6 + const TRANSACTIONTYPE = 'status'; 7 + 8 + public function generateOldValue($object) { 9 + return $object->getStatus(); 10 + } 11 + 12 + public function applyInternalEffects($object, $value) { 13 + $object->setStatus($value); 14 + } 15 + 16 + public function getTitle() { 17 + $new = $this->getNewValue(); 18 + 19 + if ($new === PhabricatorAuthContactNumber::STATUS_DISABLED) { 20 + return pht( 21 + '%s disabled this contact number.', 22 + $this->renderAuthor()); 23 + } else { 24 + return pht( 25 + '%s enabled this contact number.', 26 + $this->renderAuthor()); 27 + } 28 + } 29 + 30 + public function validateTransactions($object, array $xactions) { 31 + $errors = array(); 32 + 33 + $map = PhabricatorAuthContactNumber::getStatusNameMap(); 34 + 35 + foreach ($xactions as $xaction) { 36 + $new_value = $xaction->getNewValue(); 37 + 38 + if (!isset($map[$new_value])) { 39 + $errors[] = $this->newInvalidError( 40 + pht( 41 + 'Status ("%s") is not a valid contact number status. Valid '. 42 + 'status constants are: %s.', 43 + $new_value, 44 + implode(', ', array_keys($map))), 45 + $xaction); 46 + continue; 47 + } 48 + 49 + // NOTE: Enabling a contact number may cause us to collide with another 50 + // active contact number. However, there might also be a transaction in 51 + // this group that changes the number itself. Since we can't easily 52 + // predict if we'll collide or not, just let the duplicate key logic 53 + // handle it when we do. 54 + } 55 + 56 + return $errors; 57 + } 58 + 59 + }