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

Add scaffolding for ad-hoc email addresses associated with Phortune accounts

Summary: Depends on D20697. Ref T8389. Add support for adding "billing@enterprise.com" and similar to Phortune accounts.

Test Plan: Added and edited email addresses for a payment account.

Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam

Maniphest Tasks: T8389

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

+829 -1
+12
resources/sql/autopatches/20190802.email.01.storage.sql
··· 1 + CREATE TABLE {$NAMESPACE}_phortune.phortune_accountemail ( 2 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 + phid VARBINARY(64) NOT NULL, 4 + accountPHID VARBINARY(64) NOT NULL, 5 + authorPHID VARBINARY(64) NOT NULL, 6 + address VARCHAR(128) NOT NULL COLLATE {$COLLATE_SORT}, 7 + status VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT}, 8 + addressKey VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT}, 9 + accessKey VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT}, 10 + dateCreated INT UNSIGNED NOT NULL, 11 + dateModified INT UNSIGNED NOT NULL 12 + ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE {$COLLATE_TEXT};
+19
resources/sql/autopatches/20190802.email.02.xaction.sql
··· 1 + CREATE TABLE {$NAMESPACE}_phortune.phortune_accountemailtransaction ( 2 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 + phid VARBINARY(64) NOT NULL, 4 + authorPHID VARBINARY(64) NOT NULL, 5 + objectPHID VARBINARY(64) NOT NULL, 6 + viewPolicy VARBINARY(64) NOT NULL, 7 + editPolicy VARBINARY(64) NOT NULL, 8 + commentPHID VARBINARY(64) DEFAULT NULL, 9 + commentVersion INT UNSIGNED NOT NULL, 10 + transactionType VARCHAR(32) NOT NULL, 11 + oldValue LONGTEXT NOT NULL, 12 + newValue LONGTEXT NOT NULL, 13 + contentSource LONGTEXT NOT NULL, 14 + metadata LONGTEXT NOT NULL, 15 + dateCreated INT UNSIGNED NOT NULL, 16 + dateModified INT UNSIGNED NOT NULL, 17 + UNIQUE KEY `key_phid` (`phid`), 18 + KEY `key_object` (`objectPHID`) 19 + ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE {$COLLATE_TEXT};
+31
src/__phutil_library_map__.php
··· 5229 5229 'PhortuneAccountEditController' => 'applications/phortune/controller/account/PhortuneAccountEditController.php', 5230 5230 'PhortuneAccountEditEngine' => 'applications/phortune/editor/PhortuneAccountEditEngine.php', 5231 5231 'PhortuneAccountEditor' => 'applications/phortune/editor/PhortuneAccountEditor.php', 5232 + 'PhortuneAccountEmail' => 'applications/phortune/storage/PhortuneAccountEmail.php', 5233 + 'PhortuneAccountEmailAddressTransaction' => 'applications/phortune/xaction/PhortuneAccountEmailAddressTransaction.php', 5234 + 'PhortuneAccountEmailAddressesController' => 'applications/phortune/controller/account/PhortuneAccountEmailAddressesController.php', 5235 + 'PhortuneAccountEmailEditController' => 'applications/phortune/controller/account/PhortuneAccountEmailEditController.php', 5236 + 'PhortuneAccountEmailEditEngine' => 'applications/phortune/editor/PhortuneAccountEmailEditEngine.php', 5237 + 'PhortuneAccountEmailEditor' => 'applications/phortune/editor/PhortuneAccountEmailEditor.php', 5238 + 'PhortuneAccountEmailPHIDType' => 'applications/phortune/phid/PhortuneAccountEmailPHIDType.php', 5239 + 'PhortuneAccountEmailQuery' => 'applications/phortune/query/PhortuneAccountEmailQuery.php', 5240 + 'PhortuneAccountEmailStatus' => 'applications/phortune/constants/PhortuneAccountEmailStatus.php', 5241 + 'PhortuneAccountEmailTransaction' => 'applications/phortune/storage/PhortuneAccountEmailTransaction.php', 5242 + 'PhortuneAccountEmailTransactionQuery' => 'applications/phortune/query/PhortuneAccountEmailTransactionQuery.php', 5243 + 'PhortuneAccountEmailTransactionType' => 'applications/phortune/xaction/PhortuneAccountEmailTransactionType.php', 5244 + 'PhortuneAccountEmailViewController' => 'applications/phortune/controller/account/PhortuneAccountEmailViewController.php', 5232 5245 'PhortuneAccountHasMemberEdgeType' => 'applications/phortune/edge/PhortuneAccountHasMemberEdgeType.php', 5233 5246 'PhortuneAccountListController' => 'applications/phortune/controller/account/PhortuneAccountListController.php', 5234 5247 'PhortuneAccountManagersController' => 'applications/phortune/controller/account/PhortuneAccountManagersController.php', ··· 11764 11777 'PhortuneAccountEditController' => 'PhortuneController', 11765 11778 'PhortuneAccountEditEngine' => 'PhabricatorEditEngine', 11766 11779 'PhortuneAccountEditor' => 'PhabricatorApplicationTransactionEditor', 11780 + 'PhortuneAccountEmail' => array( 11781 + 'PhortuneDAO', 11782 + 'PhabricatorApplicationTransactionInterface', 11783 + 'PhabricatorPolicyInterface', 11784 + 'PhabricatorExtendedPolicyInterface', 11785 + ), 11786 + 'PhortuneAccountEmailAddressTransaction' => 'PhortuneAccountEmailTransactionType', 11787 + 'PhortuneAccountEmailAddressesController' => 'PhortuneAccountProfileController', 11788 + 'PhortuneAccountEmailEditController' => 'PhortuneAccountController', 11789 + 'PhortuneAccountEmailEditEngine' => 'PhabricatorEditEngine', 11790 + 'PhortuneAccountEmailEditor' => 'PhabricatorApplicationTransactionEditor', 11791 + 'PhortuneAccountEmailPHIDType' => 'PhabricatorPHIDType', 11792 + 'PhortuneAccountEmailQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 11793 + 'PhortuneAccountEmailStatus' => 'Phobject', 11794 + 'PhortuneAccountEmailTransaction' => 'PhabricatorModularTransaction', 11795 + 'PhortuneAccountEmailTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 11796 + 'PhortuneAccountEmailTransactionType' => 'PhabricatorModularTransactionType', 11797 + 'PhortuneAccountEmailViewController' => 'PhortuneAccountController', 11767 11798 'PhortuneAccountHasMemberEdgeType' => 'PhabricatorEdgeType', 11768 11799 'PhortuneAccountListController' => 'PhortuneController', 11769 11800 'PhortuneAccountManagersController' => 'PhortuneAccountProfileController',
+10
src/applications/phortune/application/PhabricatorPhortuneApplication.php
··· 80 80 '' => 'PhortuneAccountManagersController', 81 81 'add/' => 'PhortuneAccountAddManagerController', 82 82 ), 83 + 'addresses/' => array( 84 + '' => 'PhortuneAccountEmailAddressesController', 85 + $this->getEditRoutePattern('edit/') 86 + => 'PhortuneAccountEmailEditController', 87 + ), 83 88 ), 89 + ), 90 + 'address/' => array( 91 + '(?P<id>\d+)/' => 'PhortuneAccountEmailViewController', 92 + $this->getEditRoutePattern('edit/') 93 + => 'PhortuneAccountEmailEditController', 84 94 ), 85 95 'product/' => array( 86 96 '' => 'PhortuneProductListController',
+31
src/applications/phortune/constants/PhortuneAccountEmailStatus.php
··· 1 + <?php 2 + 3 + final class PhortuneAccountEmailStatus 4 + extends Phobject { 5 + 6 + const STATUS_ACTIVE = 'active'; 7 + const STATUS_DISABLED = 'disabled'; 8 + const STATUS_UNSUBSCRIBED = 'unsubscribed'; 9 + 10 + public static function getDefaultStatusConstant() { 11 + return self::STATUS_ACTIVE; 12 + } 13 + 14 + private static function getMap() { 15 + return array( 16 + self::STATUS_ACTIVE => array( 17 + 'name' => pht('Active'), 18 + 'closed' => false, 19 + ), 20 + self::STATUS_DISABLED => array( 21 + 'name' => pht('Disabled'), 22 + 'closed' => true, 23 + ), 24 + self::STATUS_UNSUBSCRIBED => array( 25 + 'name' => pht('Unsubscribed'), 26 + 'closed' => true, 27 + ), 28 + ); 29 + } 30 + 31 + }
+5 -1
src/applications/phortune/controller/account/PhortuneAccountController.php
··· 9 9 return $this->account; 10 10 } 11 11 12 + protected function setAccount(PhortuneAccount $account) { 13 + $this->account = $account; 14 + return $this; 15 + } 16 + 12 17 protected function buildApplicationCrumbs() { 13 18 $crumbs = parent::buildApplicationCrumbs(); 14 19 ··· 28 33 // too, just with less information. 29 34 return $this->loadAccountForEdit(); 30 35 } 31 - 32 36 33 37 protected function loadAccountForEdit() { 34 38 $viewer = $this->getViewer();
+90
src/applications/phortune/controller/account/PhortuneAccountEmailAddressesController.php
··· 1 + <?php 2 + 3 + final class PhortuneAccountEmailAddressesController 4 + extends PhortuneAccountProfileController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $response = $this->loadAccount(); 8 + if ($response) { 9 + return $response; 10 + } 11 + 12 + $account = $this->getAccount(); 13 + $title = $account->getName(); 14 + 15 + $crumbs = $this->buildApplicationCrumbs(); 16 + $crumbs->addTextCrumb(pht('Email Addresses')); 17 + 18 + $header = $this->buildHeaderView(); 19 + $addresses = $this->buildAddressesSection($account); 20 + 21 + $view = id(new PHUITwoColumnView()) 22 + ->setHeader($header) 23 + ->setFooter( 24 + array( 25 + $addresses, 26 + )); 27 + 28 + $navigation = $this->buildSideNavView('addresses'); 29 + 30 + return $this->newPage() 31 + ->setTitle($title) 32 + ->setCrumbs($crumbs) 33 + ->setNavigation($navigation) 34 + ->appendChild($view); 35 + } 36 + 37 + private function buildAddressesSection(PhortuneAccount $account) { 38 + $viewer = $this->getViewer(); 39 + 40 + $can_edit = PhabricatorPolicyFilter::hasCapability( 41 + $viewer, 42 + $account, 43 + PhabricatorPolicyCapability::CAN_EDIT); 44 + 45 + $id = $account->getID(); 46 + 47 + $add = id(new PHUIButtonView()) 48 + ->setTag('a') 49 + ->setText(pht('Add Address')) 50 + ->setIcon('fa-plus') 51 + ->setWorkflow(!$can_edit) 52 + ->setDisabled(!$can_edit) 53 + ->setHref("/phortune/account/{$id}/addresses/edit/"); 54 + 55 + $header = id(new PHUIHeaderView()) 56 + ->setHeader(pht('Billing Email Addresses')) 57 + ->addActionLink($add); 58 + 59 + $addresses = id(new PhortuneAccountEmailQuery()) 60 + ->setViewer($viewer) 61 + ->withAccountPHIDs(array($account->getPHID())) 62 + ->execute(); 63 + 64 + $list = id(new PHUIObjectItemListView()) 65 + ->setUser($viewer) 66 + ->setNoDataString( 67 + pht( 68 + 'There are no billing email addresses associated '. 69 + 'with this account.')); 70 + 71 + $addresses = id(new PhortuneAccountEmailQuery()) 72 + ->setViewer($viewer) 73 + ->withAccountPHIDs(array($account->getPHID())) 74 + ->execute(); 75 + foreach ($addresses as $address) { 76 + $item = id(new PHUIObjectItemView()) 77 + ->setObjectName($address->getObjectName()) 78 + ->setHeader($address->getAddress()) 79 + ->setHref($address->getURI()); 80 + 81 + $list->addItem($item); 82 + } 83 + 84 + return id(new PHUIObjectBoxView()) 85 + ->setHeader($header) 86 + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 87 + ->setObjectList($list); 88 + } 89 + 90 + }
+28
src/applications/phortune/controller/account/PhortuneAccountEmailEditController.php
··· 1 + <?php 2 + 3 + final class PhortuneAccountEmailEditController 4 + extends PhortuneAccountController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $engine = id(new PhortuneAccountEmailEditEngine()) 8 + ->setController($this); 9 + 10 + if (!$request->getURIData('id')) { 11 + 12 + if (!$request->getURIData('accountID')) { 13 + return new Aphront404Response(); 14 + } 15 + 16 + $response = $this->loadAccount(); 17 + if ($response) { 18 + return $response; 19 + } 20 + 21 + $account = $this->getAccount(); 22 + 23 + $engine->setAccount($account); 24 + } 25 + 26 + return $engine->buildResponse(); 27 + } 28 + }
+93
src/applications/phortune/controller/account/PhortuneAccountEmailViewController.php
··· 1 + <?php 2 + 3 + final class PhortuneAccountEmailViewController 4 + extends PhortuneAccountController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $this->getViewer(); 8 + 9 + $address = id(new PhortuneAccountEmailQuery()) 10 + ->setViewer($viewer) 11 + ->withIDs(array($request->getURIData('id'))) 12 + ->executeOne(); 13 + if (!$address) { 14 + return new Aphront404Response(); 15 + } 16 + 17 + $account = $address->getAccount(); 18 + $this->setAccount($account); 19 + 20 + $crumbs = $this->buildApplicationCrumbs() 21 + ->addTextCrumb(pht('Email Addresses'), $account->getEmailAddressesURI()) 22 + ->addTextCrumb($address->getObjectName()) 23 + ->setBorder(true); 24 + 25 + $header = id(new PHUIHeaderView()) 26 + ->setHeader(pht('Account Email: %s', $address->getAddress())); 27 + 28 + $details = $this->newDetailsView($address); 29 + 30 + $timeline = $this->buildTransactionTimeline( 31 + $address, 32 + new PhortuneAccountEmailTransactionQuery()); 33 + $timeline->setShouldTerminate(true); 34 + 35 + $curtain = $this->buildCurtainView($address); 36 + 37 + $view = id(new PHUITwoColumnView()) 38 + ->setHeader($header) 39 + ->setCurtain($curtain) 40 + ->setMainColumn( 41 + array( 42 + $details, 43 + $timeline, 44 + )); 45 + 46 + return $this->newPage() 47 + ->setTitle($address->getObjectName()) 48 + ->setCrumbs($crumbs) 49 + ->appendChild($view); 50 + 51 + } 52 + 53 + private function buildCurtainView(PhortuneAccountEmail $address) { 54 + $viewer = $this->getViewer(); 55 + $account = $address->getAccount(); 56 + 57 + $can_edit = PhabricatorPolicyFilter::hasCapability( 58 + $viewer, 59 + $address, 60 + PhabricatorPolicyCapability::CAN_EDIT); 61 + 62 + $edit_uri = $this->getApplicationURI( 63 + urisprintf( 64 + 'address/edit/%d/', 65 + $address->getID())); 66 + 67 + $curtain = $this->newCurtainView($account); 68 + 69 + $curtain->addAction( 70 + id(new PhabricatorActionView()) 71 + ->setName(pht('Edit Address')) 72 + ->setIcon('fa-pencil') 73 + ->setHref($edit_uri) 74 + ->setDisabled(!$can_edit) 75 + ->setWorkflow(!$can_edit)); 76 + 77 + return $curtain; 78 + } 79 + 80 + private function newDetailsView(PhortuneAccountEmail $address) { 81 + $viewer = $this->getViewer(); 82 + 83 + $view = id(new PHUIPropertyListView()) 84 + ->setUser($viewer); 85 + 86 + $view->addProperty(pht('Email Address'), $address->getAddress()); 87 + 88 + return id(new PHUIObjectBoxView()) 89 + ->setHeaderText(pht('Email Address Details')) 90 + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 91 + ->addPropertyList($view); 92 + } 93 + }
+6
src/applications/phortune/controller/account/PhortuneAccountProfileController.php
··· 82 82 $this->getApplicationURI("/account/{$id}/managers/"), 83 83 'fa-group'); 84 84 85 + $nav->addFilter( 86 + 'addresses', 87 + pht('Email Addresses'), 88 + $this->getApplicationURI("/account/{$id}/addresses/"), 89 + 'fa-envelope-o'); 90 + 85 91 $nav->selectFilter($filter); 86 92 87 93 return $nav;
+114
src/applications/phortune/editor/PhortuneAccountEmailEditEngine.php
··· 1 + <?php 2 + 3 + final class PhortuneAccountEmailEditEngine 4 + extends PhabricatorEditEngine { 5 + 6 + const ENGINECONST = 'phortune.account.email'; 7 + 8 + private $account; 9 + 10 + public function setAccount(PhortuneAccount $account) { 11 + $this->account = $account; 12 + return $this; 13 + } 14 + 15 + public function getAccount() { 16 + return $this->account; 17 + } 18 + 19 + public function getEngineName() { 20 + return pht('Phortune Account Emails'); 21 + } 22 + 23 + public function getEngineApplicationClass() { 24 + return 'PhabricatorPhortuneApplication'; 25 + } 26 + 27 + public function getSummaryHeader() { 28 + return pht('Configure Phortune Account Email Forms'); 29 + } 30 + 31 + public function getSummaryText() { 32 + return pht( 33 + 'Configure creation and editing forms for Phortune Account '. 34 + 'Email Addresses.'); 35 + } 36 + 37 + public function isEngineConfigurable() { 38 + return false; 39 + } 40 + 41 + protected function newEditableObject() { 42 + $viewer = $this->getViewer(); 43 + 44 + $account = $this->getAccount(); 45 + if (!$account) { 46 + $account = new PhortuneAccount(); 47 + } 48 + 49 + return PhortuneAccountEmail::initializeNewAddress( 50 + $account, 51 + $viewer->getPHID()); 52 + } 53 + 54 + protected function newObjectQuery() { 55 + return new PhortuneAccountEmailQuery(); 56 + } 57 + 58 + protected function getObjectCreateTitleText($object) { 59 + return pht('Add Email Address'); 60 + } 61 + 62 + protected function getObjectEditTitleText($object) { 63 + return pht('Edit Account Email: %s', $object->getAddress()); 64 + } 65 + 66 + protected function getObjectEditShortText($object) { 67 + return pht('%s', $object->getAddress()); 68 + } 69 + 70 + protected function getObjectCreateShortText() { 71 + return pht('Add Email Address'); 72 + } 73 + 74 + protected function getObjectName() { 75 + return pht('Account Email'); 76 + } 77 + 78 + protected function getObjectCreateCancelURI($object) { 79 + return $this->getAccount()->getEmailAddressesURI(); 80 + } 81 + 82 + protected function getEditorURI() { 83 + return $this->getApplication()->getApplicationURI('address/edit/'); 84 + } 85 + 86 + protected function getObjectViewURI($object) { 87 + return $object->getURI(); 88 + } 89 + 90 + protected function buildCustomEditFields($object) { 91 + $viewer = $this->getViewer(); 92 + 93 + if ($this->getIsCreate()) { 94 + $address_field = id(new PhabricatorTextEditField()) 95 + ->setTransactionType( 96 + PhortuneAccountEmailAddressTransaction::TRANSACTIONTYPE) 97 + ->setIsRequired(true); 98 + } else { 99 + $address_field = new PhabricatorStaticEditField(); 100 + } 101 + 102 + $address_field 103 + ->setKey('address') 104 + ->setLabel(pht('Email Address')) 105 + ->setDescription(pht('Email address.')) 106 + ->setConduitTypeDescription(pht('New email address.')) 107 + ->setValue($object->getAddress()); 108 + 109 + return array( 110 + $address_field, 111 + ); 112 + } 113 + 114 + }
+36
src/applications/phortune/editor/PhortuneAccountEmailEditor.php
··· 1 + <?php 2 + 3 + final class PhortuneAccountEmailEditor 4 + extends PhabricatorApplicationTransactionEditor { 5 + 6 + public function getEditorApplicationClass() { 7 + return 'PhabricatorPhortuneApplication'; 8 + } 9 + 10 + public function getEditorObjectsDescription() { 11 + return pht('Phortune Account Emails'); 12 + } 13 + 14 + public function getCreateObjectTitle($author, $object) { 15 + return pht('%s created this account email.', $author); 16 + } 17 + 18 + protected function didCatchDuplicateKeyException( 19 + PhabricatorLiskDAO $object, 20 + array $xactions, 21 + Exception $ex) { 22 + 23 + $errors = array(); 24 + 25 + $errors[] = new PhabricatorApplicationTransactionValidationError( 26 + PhortuneAccountEmailAddressTransaction::TRANSACTIONTYPE, 27 + pht('Duplicate'), 28 + pht( 29 + 'The email address "%s" is already attached to this account.', 30 + $object->getAddress()), 31 + null); 32 + 33 + throw new PhabricatorApplicationTransactionValidationException($errors); 34 + } 35 + 36 + }
+41
src/applications/phortune/phid/PhortuneAccountEmailPHIDType.php
··· 1 + <?php 2 + 3 + final class PhortuneAccountEmailPHIDType extends PhabricatorPHIDType { 4 + 5 + const TYPECONST = 'AEML'; 6 + 7 + public function getTypeName() { 8 + return pht('Phortune Account Email'); 9 + } 10 + 11 + public function newObject() { 12 + return new PhortuneAccountEmail(); 13 + } 14 + 15 + public function getPHIDTypeApplicationClass() { 16 + return 'PhabricatorPhortuneApplication'; 17 + } 18 + 19 + protected function buildQueryForObjects( 20 + PhabricatorObjectQuery $query, 21 + array $phids) { 22 + 23 + return id(new PhortuneAccountEmailQuery()) 24 + ->withPHIDs($phids); 25 + } 26 + 27 + public function loadHandles( 28 + PhabricatorHandleQuery $query, 29 + array $handles, 30 + array $objects) { 31 + 32 + foreach ($handles as $phid => $handle) { 33 + $email = $objects[$phid]; 34 + 35 + $id = $email->getID(); 36 + 37 + $handle->setName($email->getObjectName()); 38 + } 39 + } 40 + 41 + }
+91
src/applications/phortune/query/PhortuneAccountEmailQuery.php
··· 1 + <?php 2 + 3 + final class PhortuneAccountEmailQuery 4 + extends PhabricatorCursorPagedPolicyAwareQuery { 5 + 6 + private $ids; 7 + private $phids; 8 + private $accountPHIDs; 9 + 10 + public function withIDs(array $ids) { 11 + $this->ids = $ids; 12 + return $this; 13 + } 14 + 15 + public function withPHIDs(array $phids) { 16 + $this->phids = $phids; 17 + return $this; 18 + } 19 + 20 + public function withAccountPHIDs(array $phids) { 21 + $this->accountPHIDs = $phids; 22 + return $this; 23 + } 24 + 25 + public function newResultObject() { 26 + return new PhortuneAccountEmail(); 27 + } 28 + 29 + protected function loadPage() { 30 + return $this->loadStandardPage($this->newResultObject()); 31 + } 32 + 33 + protected function willFilterPage(array $addresses) { 34 + $accounts = id(new PhortuneAccountQuery()) 35 + ->setViewer($this->getViewer()) 36 + ->setParentQuery($this) 37 + ->withPHIDs(mpull($addresses, 'getAccountPHID')) 38 + ->execute(); 39 + $accounts = mpull($accounts, null, 'getPHID'); 40 + 41 + foreach ($addresses as $key => $address) { 42 + $account = idx($accounts, $address->getAccountPHID()); 43 + 44 + if (!$account) { 45 + $this->didRejectResult($addresses[$key]); 46 + unset($addresses[$key]); 47 + continue; 48 + } 49 + 50 + $address->attachAccount($account); 51 + } 52 + 53 + return $addresses; 54 + } 55 + 56 + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { 57 + $where = parent::buildWhereClauseParts($conn); 58 + 59 + if ($this->ids !== null) { 60 + $where[] = qsprintf( 61 + $conn, 62 + 'address.id IN (%Ld)', 63 + $this->ids); 64 + } 65 + 66 + if ($this->phids !== null) { 67 + $where[] = qsprintf( 68 + $conn, 69 + 'address.phid IN (%Ls)', 70 + $this->phids); 71 + } 72 + 73 + if ($this->accountPHIDs !== null) { 74 + $where[] = qsprintf( 75 + $conn, 76 + 'address.accountPHID IN (%Ls)', 77 + $this->accountPHIDs); 78 + } 79 + 80 + return $where; 81 + } 82 + 83 + public function getQueryApplicationClass() { 84 + return 'PhabricatorPhortuneApplication'; 85 + } 86 + 87 + protected function getPrimaryTableAlias() { 88 + return 'address'; 89 + } 90 + 91 + }
+10
src/applications/phortune/query/PhortuneAccountEmailTransactionQuery.php
··· 1 + <?php 2 + 3 + final class PhortuneAccountEmailTransactionQuery 4 + extends PhabricatorApplicationTransactionQuery { 5 + 6 + public function getTemplateApplicationTransaction() { 7 + return new PhortuneAccountEmailTransaction(); 8 + } 9 + 10 + }
+6
src/applications/phortune/storage/PhortuneAccount.php
··· 109 109 $this->getID()); 110 110 } 111 111 112 + public function getEmailAddressesURI() { 113 + return urisprintf( 114 + '/phortune/account/%d/addresses/', 115 + $this->getID()); 116 + } 117 + 112 118 113 119 /* -( PhabricatorApplicationTransactionInterface )------------------------- */ 114 120
+121
src/applications/phortune/storage/PhortuneAccountEmail.php
··· 1 + <?php 2 + 3 + final class PhortuneAccountEmail 4 + extends PhortuneDAO 5 + implements 6 + PhabricatorApplicationTransactionInterface, 7 + PhabricatorPolicyInterface, 8 + PhabricatorExtendedPolicyInterface { 9 + 10 + protected $accountPHID; 11 + protected $authorPHID; 12 + protected $address; 13 + protected $status; 14 + protected $addressKey; 15 + protected $accessKey; 16 + 17 + private $account = self::ATTACHABLE; 18 + 19 + protected function getConfiguration() { 20 + return array( 21 + self::CONFIG_AUX_PHID => true, 22 + self::CONFIG_COLUMN_SCHEMA => array( 23 + 'address' => 'sort128', 24 + 'status' => 'text32', 25 + 'addressKey' => 'text32', 26 + 'accessKey' => 'text32', 27 + ), 28 + self::CONFIG_KEY_SCHEMA => array( 29 + 'key_account' => array( 30 + 'columns' => array('accountPHID', 'address'), 31 + 'unique' => true, 32 + ), 33 + 'key_address' => array( 34 + 'columns' => array('addressKey'), 35 + ), 36 + ), 37 + ) + parent::getConfiguration(); 38 + } 39 + 40 + public function getPHIDType() { 41 + return PhortuneAccountEmailPHIDType::TYPECONST; 42 + } 43 + 44 + public static function initializeNewAddress( 45 + PhortuneAccount $account, 46 + $author_phid) { 47 + 48 + $address_key = Filesystem::readRandomCharacters(16); 49 + $access_key = Filesystem::readRandomCharacters(16); 50 + $default_status = PhortuneAccountEmailStatus::getDefaultStatusConstant(); 51 + 52 + return id(new self()) 53 + ->setAuthorPHID($author_phid) 54 + ->setAccountPHID($account->getPHID()) 55 + ->setStatus($default_status) 56 + ->attachAccount($account) 57 + ->setAddressKey($address_key) 58 + ->setAccessKey($access_key); 59 + } 60 + 61 + public function attachAccount(PhortuneAccount $account) { 62 + $this->account = $account; 63 + return $this; 64 + } 65 + 66 + public function getAccount() { 67 + return $this->assertAttached($this->account); 68 + } 69 + 70 + public function getObjectName() { 71 + return pht('Account Email %d', $this->getID()); 72 + } 73 + 74 + public function getURI() { 75 + return urisprintf( 76 + '/phortune/address/%d/', 77 + $this->getID()); 78 + } 79 + 80 + 81 + /* -( PhabricatorPolicyInterface )----------------------------------------- */ 82 + 83 + 84 + public function getCapabilities() { 85 + return array( 86 + PhabricatorPolicyCapability::CAN_VIEW, 87 + PhabricatorPolicyCapability::CAN_EDIT, 88 + ); 89 + } 90 + 91 + public function getPolicy($capability) { 92 + return PhabricatorPolicies::getMostOpenPolicy(); 93 + } 94 + 95 + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 96 + return false; 97 + } 98 + 99 + 100 + /* -( PhabricatorExtendedPolicyInterface )--------------------------------- */ 101 + 102 + 103 + public function getExtendedPolicy($capability, PhabricatorUser $viewer) { 104 + return array( 105 + array($this->getAccount(), $capability), 106 + ); 107 + } 108 + 109 + 110 + /* -( PhabricatorApplicationTransactionInterface )------------------------- */ 111 + 112 + 113 + public function getApplicationTransactionEditor() { 114 + return new PhortuneAccountEmailEditor(); 115 + } 116 + 117 + public function getApplicationTransactionTemplate() { 118 + return new PhortuneAccountEmailTransaction(); 119 + } 120 + 121 + }
+18
src/applications/phortune/storage/PhortuneAccountEmailTransaction.php
··· 1 + <?php 2 + 3 + final class PhortuneAccountEmailTransaction 4 + extends PhabricatorModularTransaction { 5 + 6 + public function getApplicationName() { 7 + return 'phortune'; 8 + } 9 + 10 + public function getApplicationTransactionType() { 11 + return PhortuneAccountEmailPHIDType::TYPECONST; 12 + } 13 + 14 + public function getBaseTransactionClass() { 15 + return 'PhortuneAccountEmailTransactionType'; 16 + } 17 + 18 + }
+63
src/applications/phortune/xaction/PhortuneAccountEmailAddressTransaction.php
··· 1 + <?php 2 + 3 + final class PhortuneAccountEmailAddressTransaction 4 + extends PhortuneAccountEmailTransactionType { 5 + 6 + const TRANSACTIONTYPE = 'address'; 7 + 8 + public function generateOldValue($object) { 9 + return $object->getAddress(); 10 + } 11 + 12 + public function applyInternalEffects($object, $value) { 13 + $object->setAddress($value); 14 + } 15 + 16 + public function validateTransactions($object, array $xactions) { 17 + $errors = array(); 18 + 19 + if ($this->isEmptyTextTransaction($object->getAddress(), $xactions)) { 20 + $errors[] = $this->newRequiredError( 21 + pht('You must provide an email address.')); 22 + } 23 + 24 + $max_length = $object->getColumnMaximumByteLength('address'); 25 + foreach ($xactions as $xaction) { 26 + $old_value = $xaction->getOldValue(); 27 + $new_value = $xaction->getNewValue(); 28 + 29 + $new_length = strlen($new_value); 30 + if ($new_length > $max_length) { 31 + $errors[] = $this->newInvalidError( 32 + pht( 33 + 'The address can be no longer than %s characters.', 34 + new PhutilNumber($max_length)), 35 + $xaction); 36 + continue; 37 + } 38 + 39 + if (!PhabricatorUserEmail::isValidAddress($new_value)) { 40 + $errors[] = $this->newInvalidError( 41 + PhabricatorUserEmail::describeValidAddresses(), 42 + $xaction); 43 + continue; 44 + } 45 + 46 + if ($new_value !== $old_value) { 47 + if (!$this->isNewObject()) { 48 + $errors[] = $this->newInvalidError( 49 + pht( 50 + 'Account email addresses can not be edited once they are '. 51 + 'created. To change the billing address for an account, '. 52 + 'disable the old address and then add a new address.'), 53 + $xaction); 54 + continue; 55 + } 56 + } 57 + 58 + } 59 + 60 + return $errors; 61 + } 62 + 63 + }
+4
src/applications/phortune/xaction/PhortuneAccountEmailTransactionType.php
··· 1 + <?php 2 + 3 + abstract class PhortuneAccountEmailTransactionType 4 + extends PhabricatorModularTransactionType {}