1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-26 00:32:42 +01:00

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
This commit is contained in:
epriestley 2019-08-02 12:14:58 -07:00
parent 719a7d82c5
commit e3ba53078e
20 changed files with 829 additions and 1 deletions

View file

@ -0,0 +1,12 @@
CREATE TABLE {$NAMESPACE}_phortune.phortune_accountemail (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
phid VARBINARY(64) NOT NULL,
accountPHID VARBINARY(64) NOT NULL,
authorPHID VARBINARY(64) NOT NULL,
address VARCHAR(128) NOT NULL COLLATE {$COLLATE_SORT},
status VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
addressKey VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
accessKey VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
dateCreated INT UNSIGNED NOT NULL,
dateModified INT UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,19 @@
CREATE TABLE {$NAMESPACE}_phortune.phortune_accountemailtransaction (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
phid VARBINARY(64) NOT NULL,
authorPHID VARBINARY(64) NOT NULL,
objectPHID VARBINARY(64) NOT NULL,
viewPolicy VARBINARY(64) NOT NULL,
editPolicy VARBINARY(64) NOT NULL,
commentPHID VARBINARY(64) DEFAULT NULL,
commentVersion INT UNSIGNED NOT NULL,
transactionType VARCHAR(32) NOT NULL,
oldValue LONGTEXT NOT NULL,
newValue LONGTEXT NOT NULL,
contentSource LONGTEXT NOT NULL,
metadata LONGTEXT NOT NULL,
dateCreated INT UNSIGNED NOT NULL,
dateModified INT UNSIGNED NOT NULL,
UNIQUE KEY `key_phid` (`phid`),
KEY `key_object` (`objectPHID`)
) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE {$COLLATE_TEXT};

View file

@ -5229,6 +5229,19 @@ phutil_register_library_map(array(
'PhortuneAccountEditController' => 'applications/phortune/controller/account/PhortuneAccountEditController.php',
'PhortuneAccountEditEngine' => 'applications/phortune/editor/PhortuneAccountEditEngine.php',
'PhortuneAccountEditor' => 'applications/phortune/editor/PhortuneAccountEditor.php',
'PhortuneAccountEmail' => 'applications/phortune/storage/PhortuneAccountEmail.php',
'PhortuneAccountEmailAddressTransaction' => 'applications/phortune/xaction/PhortuneAccountEmailAddressTransaction.php',
'PhortuneAccountEmailAddressesController' => 'applications/phortune/controller/account/PhortuneAccountEmailAddressesController.php',
'PhortuneAccountEmailEditController' => 'applications/phortune/controller/account/PhortuneAccountEmailEditController.php',
'PhortuneAccountEmailEditEngine' => 'applications/phortune/editor/PhortuneAccountEmailEditEngine.php',
'PhortuneAccountEmailEditor' => 'applications/phortune/editor/PhortuneAccountEmailEditor.php',
'PhortuneAccountEmailPHIDType' => 'applications/phortune/phid/PhortuneAccountEmailPHIDType.php',
'PhortuneAccountEmailQuery' => 'applications/phortune/query/PhortuneAccountEmailQuery.php',
'PhortuneAccountEmailStatus' => 'applications/phortune/constants/PhortuneAccountEmailStatus.php',
'PhortuneAccountEmailTransaction' => 'applications/phortune/storage/PhortuneAccountEmailTransaction.php',
'PhortuneAccountEmailTransactionQuery' => 'applications/phortune/query/PhortuneAccountEmailTransactionQuery.php',
'PhortuneAccountEmailTransactionType' => 'applications/phortune/xaction/PhortuneAccountEmailTransactionType.php',
'PhortuneAccountEmailViewController' => 'applications/phortune/controller/account/PhortuneAccountEmailViewController.php',
'PhortuneAccountHasMemberEdgeType' => 'applications/phortune/edge/PhortuneAccountHasMemberEdgeType.php',
'PhortuneAccountListController' => 'applications/phortune/controller/account/PhortuneAccountListController.php',
'PhortuneAccountManagersController' => 'applications/phortune/controller/account/PhortuneAccountManagersController.php',
@ -11764,6 +11777,24 @@ phutil_register_library_map(array(
'PhortuneAccountEditController' => 'PhortuneController',
'PhortuneAccountEditEngine' => 'PhabricatorEditEngine',
'PhortuneAccountEditor' => 'PhabricatorApplicationTransactionEditor',
'PhortuneAccountEmail' => array(
'PhortuneDAO',
'PhabricatorApplicationTransactionInterface',
'PhabricatorPolicyInterface',
'PhabricatorExtendedPolicyInterface',
),
'PhortuneAccountEmailAddressTransaction' => 'PhortuneAccountEmailTransactionType',
'PhortuneAccountEmailAddressesController' => 'PhortuneAccountProfileController',
'PhortuneAccountEmailEditController' => 'PhortuneAccountController',
'PhortuneAccountEmailEditEngine' => 'PhabricatorEditEngine',
'PhortuneAccountEmailEditor' => 'PhabricatorApplicationTransactionEditor',
'PhortuneAccountEmailPHIDType' => 'PhabricatorPHIDType',
'PhortuneAccountEmailQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhortuneAccountEmailStatus' => 'Phobject',
'PhortuneAccountEmailTransaction' => 'PhabricatorModularTransaction',
'PhortuneAccountEmailTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhortuneAccountEmailTransactionType' => 'PhabricatorModularTransactionType',
'PhortuneAccountEmailViewController' => 'PhortuneAccountController',
'PhortuneAccountHasMemberEdgeType' => 'PhabricatorEdgeType',
'PhortuneAccountListController' => 'PhortuneController',
'PhortuneAccountManagersController' => 'PhortuneAccountProfileController',

View file

@ -80,8 +80,18 @@ final class PhabricatorPhortuneApplication extends PhabricatorApplication {
'' => 'PhortuneAccountManagersController',
'add/' => 'PhortuneAccountAddManagerController',
),
'addresses/' => array(
'' => 'PhortuneAccountEmailAddressesController',
$this->getEditRoutePattern('edit/')
=> 'PhortuneAccountEmailEditController',
),
),
),
'address/' => array(
'(?P<id>\d+)/' => 'PhortuneAccountEmailViewController',
$this->getEditRoutePattern('edit/')
=> 'PhortuneAccountEmailEditController',
),
'product/' => array(
'' => 'PhortuneProductListController',
'view/(?P<id>\d+)/' => 'PhortuneProductViewController',

View file

@ -0,0 +1,31 @@
<?php
final class PhortuneAccountEmailStatus
extends Phobject {
const STATUS_ACTIVE = 'active';
const STATUS_DISABLED = 'disabled';
const STATUS_UNSUBSCRIBED = 'unsubscribed';
public static function getDefaultStatusConstant() {
return self::STATUS_ACTIVE;
}
private static function getMap() {
return array(
self::STATUS_ACTIVE => array(
'name' => pht('Active'),
'closed' => false,
),
self::STATUS_DISABLED => array(
'name' => pht('Disabled'),
'closed' => true,
),
self::STATUS_UNSUBSCRIBED => array(
'name' => pht('Unsubscribed'),
'closed' => true,
),
);
}
}

View file

@ -9,6 +9,11 @@ abstract class PhortuneAccountController
return $this->account;
}
protected function setAccount(PhortuneAccount $account) {
$this->account = $account;
return $this;
}
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
@ -29,7 +34,6 @@ abstract class PhortuneAccountController
return $this->loadAccountForEdit();
}
protected function loadAccountForEdit() {
$viewer = $this->getViewer();
$request = $this->getRequest();

View file

@ -0,0 +1,90 @@
<?php
final class PhortuneAccountEmailAddressesController
extends PhortuneAccountProfileController {
public function handleRequest(AphrontRequest $request) {
$response = $this->loadAccount();
if ($response) {
return $response;
}
$account = $this->getAccount();
$title = $account->getName();
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Email Addresses'));
$header = $this->buildHeaderView();
$addresses = $this->buildAddressesSection($account);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(
array(
$addresses,
));
$navigation = $this->buildSideNavView('addresses');
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->setNavigation($navigation)
->appendChild($view);
}
private function buildAddressesSection(PhortuneAccount $account) {
$viewer = $this->getViewer();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$account,
PhabricatorPolicyCapability::CAN_EDIT);
$id = $account->getID();
$add = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Add Address'))
->setIcon('fa-plus')
->setWorkflow(!$can_edit)
->setDisabled(!$can_edit)
->setHref("/phortune/account/{$id}/addresses/edit/");
$header = id(new PHUIHeaderView())
->setHeader(pht('Billing Email Addresses'))
->addActionLink($add);
$addresses = id(new PhortuneAccountEmailQuery())
->setViewer($viewer)
->withAccountPHIDs(array($account->getPHID()))
->execute();
$list = id(new PHUIObjectItemListView())
->setUser($viewer)
->setNoDataString(
pht(
'There are no billing email addresses associated '.
'with this account.'));
$addresses = id(new PhortuneAccountEmailQuery())
->setViewer($viewer)
->withAccountPHIDs(array($account->getPHID()))
->execute();
foreach ($addresses as $address) {
$item = id(new PHUIObjectItemView())
->setObjectName($address->getObjectName())
->setHeader($address->getAddress())
->setHref($address->getURI());
$list->addItem($item);
}
return id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setObjectList($list);
}
}

View file

@ -0,0 +1,28 @@
<?php
final class PhortuneAccountEmailEditController
extends PhortuneAccountController {
public function handleRequest(AphrontRequest $request) {
$engine = id(new PhortuneAccountEmailEditEngine())
->setController($this);
if (!$request->getURIData('id')) {
if (!$request->getURIData('accountID')) {
return new Aphront404Response();
}
$response = $this->loadAccount();
if ($response) {
return $response;
}
$account = $this->getAccount();
$engine->setAccount($account);
}
return $engine->buildResponse();
}
}

View file

@ -0,0 +1,93 @@
<?php
final class PhortuneAccountEmailViewController
extends PhortuneAccountController {
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$address = id(new PhortuneAccountEmailQuery())
->setViewer($viewer)
->withIDs(array($request->getURIData('id')))
->executeOne();
if (!$address) {
return new Aphront404Response();
}
$account = $address->getAccount();
$this->setAccount($account);
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb(pht('Email Addresses'), $account->getEmailAddressesURI())
->addTextCrumb($address->getObjectName())
->setBorder(true);
$header = id(new PHUIHeaderView())
->setHeader(pht('Account Email: %s', $address->getAddress()));
$details = $this->newDetailsView($address);
$timeline = $this->buildTransactionTimeline(
$address,
new PhortuneAccountEmailTransactionQuery());
$timeline->setShouldTerminate(true);
$curtain = $this->buildCurtainView($address);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->setMainColumn(
array(
$details,
$timeline,
));
return $this->newPage()
->setTitle($address->getObjectName())
->setCrumbs($crumbs)
->appendChild($view);
}
private function buildCurtainView(PhortuneAccountEmail $address) {
$viewer = $this->getViewer();
$account = $address->getAccount();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$address,
PhabricatorPolicyCapability::CAN_EDIT);
$edit_uri = $this->getApplicationURI(
urisprintf(
'address/edit/%d/',
$address->getID()));
$curtain = $this->newCurtainView($account);
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Address'))
->setIcon('fa-pencil')
->setHref($edit_uri)
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
return $curtain;
}
private function newDetailsView(PhortuneAccountEmail $address) {
$viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
->setUser($viewer);
$view->addProperty(pht('Email Address'), $address->getAddress());
return id(new PHUIObjectBoxView())
->setHeaderText(pht('Email Address Details'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($view);
}
}

View file

@ -82,6 +82,12 @@ abstract class PhortuneAccountProfileController
$this->getApplicationURI("/account/{$id}/managers/"),
'fa-group');
$nav->addFilter(
'addresses',
pht('Email Addresses'),
$this->getApplicationURI("/account/{$id}/addresses/"),
'fa-envelope-o');
$nav->selectFilter($filter);
return $nav;

View file

@ -0,0 +1,114 @@
<?php
final class PhortuneAccountEmailEditEngine
extends PhabricatorEditEngine {
const ENGINECONST = 'phortune.account.email';
private $account;
public function setAccount(PhortuneAccount $account) {
$this->account = $account;
return $this;
}
public function getAccount() {
return $this->account;
}
public function getEngineName() {
return pht('Phortune Account Emails');
}
public function getEngineApplicationClass() {
return 'PhabricatorPhortuneApplication';
}
public function getSummaryHeader() {
return pht('Configure Phortune Account Email Forms');
}
public function getSummaryText() {
return pht(
'Configure creation and editing forms for Phortune Account '.
'Email Addresses.');
}
public function isEngineConfigurable() {
return false;
}
protected function newEditableObject() {
$viewer = $this->getViewer();
$account = $this->getAccount();
if (!$account) {
$account = new PhortuneAccount();
}
return PhortuneAccountEmail::initializeNewAddress(
$account,
$viewer->getPHID());
}
protected function newObjectQuery() {
return new PhortuneAccountEmailQuery();
}
protected function getObjectCreateTitleText($object) {
return pht('Add Email Address');
}
protected function getObjectEditTitleText($object) {
return pht('Edit Account Email: %s', $object->getAddress());
}
protected function getObjectEditShortText($object) {
return pht('%s', $object->getAddress());
}
protected function getObjectCreateShortText() {
return pht('Add Email Address');
}
protected function getObjectName() {
return pht('Account Email');
}
protected function getObjectCreateCancelURI($object) {
return $this->getAccount()->getEmailAddressesURI();
}
protected function getEditorURI() {
return $this->getApplication()->getApplicationURI('address/edit/');
}
protected function getObjectViewURI($object) {
return $object->getURI();
}
protected function buildCustomEditFields($object) {
$viewer = $this->getViewer();
if ($this->getIsCreate()) {
$address_field = id(new PhabricatorTextEditField())
->setTransactionType(
PhortuneAccountEmailAddressTransaction::TRANSACTIONTYPE)
->setIsRequired(true);
} else {
$address_field = new PhabricatorStaticEditField();
}
$address_field
->setKey('address')
->setLabel(pht('Email Address'))
->setDescription(pht('Email address.'))
->setConduitTypeDescription(pht('New email address.'))
->setValue($object->getAddress());
return array(
$address_field,
);
}
}

View file

@ -0,0 +1,36 @@
<?php
final class PhortuneAccountEmailEditor
extends PhabricatorApplicationTransactionEditor {
public function getEditorApplicationClass() {
return 'PhabricatorPhortuneApplication';
}
public function getEditorObjectsDescription() {
return pht('Phortune Account Emails');
}
public function getCreateObjectTitle($author, $object) {
return pht('%s created this account email.', $author);
}
protected function didCatchDuplicateKeyException(
PhabricatorLiskDAO $object,
array $xactions,
Exception $ex) {
$errors = array();
$errors[] = new PhabricatorApplicationTransactionValidationError(
PhortuneAccountEmailAddressTransaction::TRANSACTIONTYPE,
pht('Duplicate'),
pht(
'The email address "%s" is already attached to this account.',
$object->getAddress()),
null);
throw new PhabricatorApplicationTransactionValidationException($errors);
}
}

View file

@ -0,0 +1,41 @@
<?php
final class PhortuneAccountEmailPHIDType extends PhabricatorPHIDType {
const TYPECONST = 'AEML';
public function getTypeName() {
return pht('Phortune Account Email');
}
public function newObject() {
return new PhortuneAccountEmail();
}
public function getPHIDTypeApplicationClass() {
return 'PhabricatorPhortuneApplication';
}
protected function buildQueryForObjects(
PhabricatorObjectQuery $query,
array $phids) {
return id(new PhortuneAccountEmailQuery())
->withPHIDs($phids);
}
public function loadHandles(
PhabricatorHandleQuery $query,
array $handles,
array $objects) {
foreach ($handles as $phid => $handle) {
$email = $objects[$phid];
$id = $email->getID();
$handle->setName($email->getObjectName());
}
}
}

View file

@ -0,0 +1,91 @@
<?php
final class PhortuneAccountEmailQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $phids;
private $accountPHIDs;
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
public function withAccountPHIDs(array $phids) {
$this->accountPHIDs = $phids;
return $this;
}
public function newResultObject() {
return new PhortuneAccountEmail();
}
protected function loadPage() {
return $this->loadStandardPage($this->newResultObject());
}
protected function willFilterPage(array $addresses) {
$accounts = id(new PhortuneAccountQuery())
->setViewer($this->getViewer())
->setParentQuery($this)
->withPHIDs(mpull($addresses, 'getAccountPHID'))
->execute();
$accounts = mpull($accounts, null, 'getPHID');
foreach ($addresses as $key => $address) {
$account = idx($accounts, $address->getAccountPHID());
if (!$account) {
$this->didRejectResult($addresses[$key]);
unset($addresses[$key]);
continue;
}
$address->attachAccount($account);
}
return $addresses;
}
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->ids !== null) {
$where[] = qsprintf(
$conn,
'address.id IN (%Ld)',
$this->ids);
}
if ($this->phids !== null) {
$where[] = qsprintf(
$conn,
'address.phid IN (%Ls)',
$this->phids);
}
if ($this->accountPHIDs !== null) {
$where[] = qsprintf(
$conn,
'address.accountPHID IN (%Ls)',
$this->accountPHIDs);
}
return $where;
}
public function getQueryApplicationClass() {
return 'PhabricatorPhortuneApplication';
}
protected function getPrimaryTableAlias() {
return 'address';
}
}

View file

@ -0,0 +1,10 @@
<?php
final class PhortuneAccountEmailTransactionQuery
extends PhabricatorApplicationTransactionQuery {
public function getTemplateApplicationTransaction() {
return new PhortuneAccountEmailTransaction();
}
}

View file

@ -109,6 +109,12 @@ final class PhortuneAccount extends PhortuneDAO
$this->getID());
}
public function getEmailAddressesURI() {
return urisprintf(
'/phortune/account/%d/addresses/',
$this->getID());
}
/* -( PhabricatorApplicationTransactionInterface )------------------------- */

View file

@ -0,0 +1,121 @@
<?php
final class PhortuneAccountEmail
extends PhortuneDAO
implements
PhabricatorApplicationTransactionInterface,
PhabricatorPolicyInterface,
PhabricatorExtendedPolicyInterface {
protected $accountPHID;
protected $authorPHID;
protected $address;
protected $status;
protected $addressKey;
protected $accessKey;
private $account = self::ATTACHABLE;
protected function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_COLUMN_SCHEMA => array(
'address' => 'sort128',
'status' => 'text32',
'addressKey' => 'text32',
'accessKey' => 'text32',
),
self::CONFIG_KEY_SCHEMA => array(
'key_account' => array(
'columns' => array('accountPHID', 'address'),
'unique' => true,
),
'key_address' => array(
'columns' => array('addressKey'),
),
),
) + parent::getConfiguration();
}
public function getPHIDType() {
return PhortuneAccountEmailPHIDType::TYPECONST;
}
public static function initializeNewAddress(
PhortuneAccount $account,
$author_phid) {
$address_key = Filesystem::readRandomCharacters(16);
$access_key = Filesystem::readRandomCharacters(16);
$default_status = PhortuneAccountEmailStatus::getDefaultStatusConstant();
return id(new self())
->setAuthorPHID($author_phid)
->setAccountPHID($account->getPHID())
->setStatus($default_status)
->attachAccount($account)
->setAddressKey($address_key)
->setAccessKey($access_key);
}
public function attachAccount(PhortuneAccount $account) {
$this->account = $account;
return $this;
}
public function getAccount() {
return $this->assertAttached($this->account);
}
public function getObjectName() {
return pht('Account Email %d', $this->getID());
}
public function getURI() {
return urisprintf(
'/phortune/address/%d/',
$this->getID());
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
public function getPolicy($capability) {
return PhabricatorPolicies::getMostOpenPolicy();
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return false;
}
/* -( PhabricatorExtendedPolicyInterface )--------------------------------- */
public function getExtendedPolicy($capability, PhabricatorUser $viewer) {
return array(
array($this->getAccount(), $capability),
);
}
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
public function getApplicationTransactionEditor() {
return new PhortuneAccountEmailEditor();
}
public function getApplicationTransactionTemplate() {
return new PhortuneAccountEmailTransaction();
}
}

View file

@ -0,0 +1,18 @@
<?php
final class PhortuneAccountEmailTransaction
extends PhabricatorModularTransaction {
public function getApplicationName() {
return 'phortune';
}
public function getApplicationTransactionType() {
return PhortuneAccountEmailPHIDType::TYPECONST;
}
public function getBaseTransactionClass() {
return 'PhortuneAccountEmailTransactionType';
}
}

View file

@ -0,0 +1,63 @@
<?php
final class PhortuneAccountEmailAddressTransaction
extends PhortuneAccountEmailTransactionType {
const TRANSACTIONTYPE = 'address';
public function generateOldValue($object) {
return $object->getAddress();
}
public function applyInternalEffects($object, $value) {
$object->setAddress($value);
}
public function validateTransactions($object, array $xactions) {
$errors = array();
if ($this->isEmptyTextTransaction($object->getAddress(), $xactions)) {
$errors[] = $this->newRequiredError(
pht('You must provide an email address.'));
}
$max_length = $object->getColumnMaximumByteLength('address');
foreach ($xactions as $xaction) {
$old_value = $xaction->getOldValue();
$new_value = $xaction->getNewValue();
$new_length = strlen($new_value);
if ($new_length > $max_length) {
$errors[] = $this->newInvalidError(
pht(
'The address can be no longer than %s characters.',
new PhutilNumber($max_length)),
$xaction);
continue;
}
if (!PhabricatorUserEmail::isValidAddress($new_value)) {
$errors[] = $this->newInvalidError(
PhabricatorUserEmail::describeValidAddresses(),
$xaction);
continue;
}
if ($new_value !== $old_value) {
if (!$this->isNewObject()) {
$errors[] = $this->newInvalidError(
pht(
'Account email addresses can not be edited once they are '.
'created. To change the billing address for an account, '.
'disable the old address and then add a new address.'),
$xaction);
continue;
}
}
}
return $errors;
}
}

View file

@ -0,0 +1,4 @@
<?php
abstract class PhortuneAccountEmailTransactionType
extends PhabricatorModularTransactionType {}