mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-11 07:11:04 +01:00
Add credential rotation and statuses (disabled, unsubscribed) to Phortune external email
Summary: Depends on D20737. Ref T13367. Allow external addresses to have their access key rotated. Account managers can disable them, and anyone with the link can permanently unsubscribe them. Test Plan: Enabled/disabled addresses; permanently unsubscribed addresses. Maniphest Tasks: T13367 Differential Revision: https://secure.phabricator.com/D20738
This commit is contained in:
parent
8f6a1ab015
commit
4e13551e85
11 changed files with 434 additions and 4 deletions
|
@ -5237,7 +5237,11 @@ phutil_register_library_map(array(
|
||||||
'PhortuneAccountEmailEditor' => 'applications/phortune/editor/PhortuneAccountEmailEditor.php',
|
'PhortuneAccountEmailEditor' => 'applications/phortune/editor/PhortuneAccountEmailEditor.php',
|
||||||
'PhortuneAccountEmailPHIDType' => 'applications/phortune/phid/PhortuneAccountEmailPHIDType.php',
|
'PhortuneAccountEmailPHIDType' => 'applications/phortune/phid/PhortuneAccountEmailPHIDType.php',
|
||||||
'PhortuneAccountEmailQuery' => 'applications/phortune/query/PhortuneAccountEmailQuery.php',
|
'PhortuneAccountEmailQuery' => 'applications/phortune/query/PhortuneAccountEmailQuery.php',
|
||||||
|
'PhortuneAccountEmailRotateController' => 'applications/phortune/controller/account/PhortuneAccountEmailRotateController.php',
|
||||||
|
'PhortuneAccountEmailRotateTransaction' => 'applications/phortune/xaction/PhortuneAccountEmailRotateTransaction.php',
|
||||||
'PhortuneAccountEmailStatus' => 'applications/phortune/constants/PhortuneAccountEmailStatus.php',
|
'PhortuneAccountEmailStatus' => 'applications/phortune/constants/PhortuneAccountEmailStatus.php',
|
||||||
|
'PhortuneAccountEmailStatusController' => 'applications/phortune/controller/account/PhortuneAccountEmailStatusController.php',
|
||||||
|
'PhortuneAccountEmailStatusTransaction' => 'applications/phortune/xaction/PhortuneAccountEmailStatusTransaction.php',
|
||||||
'PhortuneAccountEmailTransaction' => 'applications/phortune/storage/PhortuneAccountEmailTransaction.php',
|
'PhortuneAccountEmailTransaction' => 'applications/phortune/storage/PhortuneAccountEmailTransaction.php',
|
||||||
'PhortuneAccountEmailTransactionQuery' => 'applications/phortune/query/PhortuneAccountEmailTransactionQuery.php',
|
'PhortuneAccountEmailTransactionQuery' => 'applications/phortune/query/PhortuneAccountEmailTransactionQuery.php',
|
||||||
'PhortuneAccountEmailTransactionType' => 'applications/phortune/xaction/PhortuneAccountEmailTransactionType.php',
|
'PhortuneAccountEmailTransactionType' => 'applications/phortune/xaction/PhortuneAccountEmailTransactionType.php',
|
||||||
|
@ -5296,6 +5300,7 @@ phutil_register_library_map(array(
|
||||||
'PhortuneErrCode' => 'applications/phortune/constants/PhortuneErrCode.php',
|
'PhortuneErrCode' => 'applications/phortune/constants/PhortuneErrCode.php',
|
||||||
'PhortuneExternalController' => 'applications/phortune/controller/external/PhortuneExternalController.php',
|
'PhortuneExternalController' => 'applications/phortune/controller/external/PhortuneExternalController.php',
|
||||||
'PhortuneExternalOverviewController' => 'applications/phortune/controller/external/PhortuneExternalOverviewController.php',
|
'PhortuneExternalOverviewController' => 'applications/phortune/controller/external/PhortuneExternalOverviewController.php',
|
||||||
|
'PhortuneExternalUnsubscribeController' => 'applications/phortune/controller/external/PhortuneExternalUnsubscribeController.php',
|
||||||
'PhortuneInvoiceView' => 'applications/phortune/view/PhortuneInvoiceView.php',
|
'PhortuneInvoiceView' => 'applications/phortune/view/PhortuneInvoiceView.php',
|
||||||
'PhortuneLandingController' => 'applications/phortune/controller/PhortuneLandingController.php',
|
'PhortuneLandingController' => 'applications/phortune/controller/PhortuneLandingController.php',
|
||||||
'PhortuneMemberHasAccountEdgeType' => 'applications/phortune/edge/PhortuneMemberHasAccountEdgeType.php',
|
'PhortuneMemberHasAccountEdgeType' => 'applications/phortune/edge/PhortuneMemberHasAccountEdgeType.php',
|
||||||
|
@ -11815,7 +11820,11 @@ phutil_register_library_map(array(
|
||||||
'PhortuneAccountEmailEditor' => 'PhabricatorApplicationTransactionEditor',
|
'PhortuneAccountEmailEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||||
'PhortuneAccountEmailPHIDType' => 'PhabricatorPHIDType',
|
'PhortuneAccountEmailPHIDType' => 'PhabricatorPHIDType',
|
||||||
'PhortuneAccountEmailQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhortuneAccountEmailQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'PhortuneAccountEmailRotateController' => 'PhortuneAccountController',
|
||||||
|
'PhortuneAccountEmailRotateTransaction' => 'PhortuneAccountEmailTransactionType',
|
||||||
'PhortuneAccountEmailStatus' => 'Phobject',
|
'PhortuneAccountEmailStatus' => 'Phobject',
|
||||||
|
'PhortuneAccountEmailStatusController' => 'PhortuneAccountController',
|
||||||
|
'PhortuneAccountEmailStatusTransaction' => 'PhortuneAccountEmailTransactionType',
|
||||||
'PhortuneAccountEmailTransaction' => 'PhabricatorModularTransaction',
|
'PhortuneAccountEmailTransaction' => 'PhabricatorModularTransaction',
|
||||||
'PhortuneAccountEmailTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
'PhortuneAccountEmailTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
'PhortuneAccountEmailTransactionType' => 'PhabricatorModularTransactionType',
|
'PhortuneAccountEmailTransactionType' => 'PhabricatorModularTransactionType',
|
||||||
|
@ -11883,6 +11892,7 @@ phutil_register_library_map(array(
|
||||||
'PhortuneErrCode' => 'PhortuneConstants',
|
'PhortuneErrCode' => 'PhortuneConstants',
|
||||||
'PhortuneExternalController' => 'PhortuneController',
|
'PhortuneExternalController' => 'PhortuneController',
|
||||||
'PhortuneExternalOverviewController' => 'PhortuneExternalController',
|
'PhortuneExternalOverviewController' => 'PhortuneExternalController',
|
||||||
|
'PhortuneExternalUnsubscribeController' => 'PhortuneExternalController',
|
||||||
'PhortuneInvoiceView' => 'AphrontTagView',
|
'PhortuneInvoiceView' => 'AphrontTagView',
|
||||||
'PhortuneLandingController' => 'PhortuneController',
|
'PhortuneLandingController' => 'PhortuneController',
|
||||||
'PhortuneMemberHasAccountEdgeType' => 'PhabricatorEdgeType',
|
'PhortuneMemberHasAccountEdgeType' => 'PhabricatorEdgeType',
|
||||||
|
|
|
@ -87,7 +87,12 @@ final class PhabricatorPhortuneApplication extends PhabricatorApplication {
|
||||||
),
|
),
|
||||||
'addresses/' => array(
|
'addresses/' => array(
|
||||||
'' => 'PhortuneAccountEmailAddressesController',
|
'' => 'PhortuneAccountEmailAddressesController',
|
||||||
'(?P<id>\d+)/' => 'PhortuneAccountEmailViewController',
|
'(?P<addressID>\d+)/' => array(
|
||||||
|
'' => 'PhortuneAccountEmailViewController',
|
||||||
|
'rotate/' => 'PhortuneAccountEmailRotateController',
|
||||||
|
'(?P<action>disable|enable)/'
|
||||||
|
=> 'PhortuneAccountEmailStatusController',
|
||||||
|
),
|
||||||
$this->getEditRoutePattern('edit/')
|
$this->getEditRoutePattern('edit/')
|
||||||
=> 'PhortuneAccountEmailEditController',
|
=> 'PhortuneAccountEmailEditController',
|
||||||
),
|
),
|
||||||
|
@ -106,6 +111,7 @@ final class PhabricatorPhortuneApplication extends PhabricatorApplication {
|
||||||
),
|
),
|
||||||
'external/(?P<addressKey>[^/]+)/(?P<accessKey>[^/]+)/' => array(
|
'external/(?P<addressKey>[^/]+)/(?P<accessKey>[^/]+)/' => array(
|
||||||
'' => 'PhortuneExternalOverviewController',
|
'' => 'PhortuneExternalOverviewController',
|
||||||
|
'unsubscribe/' => 'PhortuneExternalUnsubscribeController',
|
||||||
),
|
),
|
||||||
'merchant/' => array(
|
'merchant/' => array(
|
||||||
$this->getQueryRoutePattern()
|
$this->getQueryRoutePattern()
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhortuneAccountEmailRotateController
|
||||||
|
extends PhortuneAccountController {
|
||||||
|
|
||||||
|
protected function shouldRequireAccountEditCapability() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleAccountRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$account = $this->getAccount();
|
||||||
|
|
||||||
|
$address = id(new PhortuneAccountEmailQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withAccountPHIDs(array($account->getPHID()))
|
||||||
|
->withIDs(array($request->getURIData('addressID')))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
|
->executeOne();
|
||||||
|
if (!$address) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$address_uri = $address->getURI();
|
||||||
|
|
||||||
|
if ($request->isFormOrHisecPost()) {
|
||||||
|
$xactions = array();
|
||||||
|
|
||||||
|
$xactions[] = $address->getApplicationTransactionTemplate()
|
||||||
|
->setTransactionType(
|
||||||
|
PhortuneAccountEmailRotateTransaction::TRANSACTIONTYPE)
|
||||||
|
->setNewValue(true);
|
||||||
|
|
||||||
|
$address->getApplicationTransactionEditor()
|
||||||
|
->setActor($viewer)
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setContinueOnMissingFields(true)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
|
->setCancelURI($address_uri)
|
||||||
|
->applyTransactions($address, $xactions);
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($address_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Rotate Access Key'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'Rotate the access key for email address %s?',
|
||||||
|
phutil_tag('strong', array(), $address->getAddress())))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'Existing access links which have been sent to this email address '.
|
||||||
|
'will stop working.'))
|
||||||
|
->addSubmitButton(pht('Rotate Access Key'))
|
||||||
|
->addCancelButton($address_uri);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,137 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhortuneAccountEmailStatusController
|
||||||
|
extends PhortuneAccountController {
|
||||||
|
|
||||||
|
protected function shouldRequireAccountEditCapability() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleAccountRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$account = $this->getAccount();
|
||||||
|
|
||||||
|
$address = id(new PhortuneAccountEmailQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withAccountPHIDs(array($account->getPHID()))
|
||||||
|
->withIDs(array($request->getURIData('addressID')))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
|
->executeOne();
|
||||||
|
if (!$address) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$address_uri = $address->getURI();
|
||||||
|
|
||||||
|
$is_enable = false;
|
||||||
|
$is_disable = false;
|
||||||
|
|
||||||
|
$old_status = $address->getStatus();
|
||||||
|
switch ($request->getURIData('action')) {
|
||||||
|
case 'enable':
|
||||||
|
if ($old_status === PhortuneAccountEmailStatus::STATUS_ACTIVE) {
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Already Enabled'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'You can not enable this address because it is already '.
|
||||||
|
'active.'))
|
||||||
|
->addCancelButton($address_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($old_status === PhortuneAccountEmailStatus::STATUS_UNSUBSCRIBED) {
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Permanently Unsubscribed'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'You can not enable this address because it has been '.
|
||||||
|
'permanently unsubscribed.'))
|
||||||
|
->addCancelButton($address_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_status = PhortuneAccountEmailStatus::STATUS_ACTIVE;
|
||||||
|
$is_enable = true;
|
||||||
|
break;
|
||||||
|
case 'disable':
|
||||||
|
if ($old_status === PhortuneAccountEmailStatus::STATUS_DISABLED) {
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Already Disabled'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'You can not disabled this address because it is already '.
|
||||||
|
'disabled.'))
|
||||||
|
->addCancelButton($address_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($old_status === PhortuneAccountEmailStatus::STATUS_UNSUBSCRIBED) {
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Permanently Unsubscribed'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'You can not disable this address because it has been '.
|
||||||
|
'permanently unsubscribed.'))
|
||||||
|
->addCancelButton($address_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_status = PhortuneAccountEmailStatus::STATUS_DISABLED;
|
||||||
|
$is_disable = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->isFormOrHisecPost()) {
|
||||||
|
$xactions = array();
|
||||||
|
|
||||||
|
$xactions[] = $address->getApplicationTransactionTemplate()
|
||||||
|
->setTransactionType(
|
||||||
|
PhortuneAccountEmailStatusTransaction::TRANSACTIONTYPE)
|
||||||
|
->setNewValue($new_status);
|
||||||
|
|
||||||
|
$address->getApplicationTransactionEditor()
|
||||||
|
->setActor($viewer)
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setContinueOnMissingFields(true)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
|
->setCancelURI($address_uri)
|
||||||
|
->applyTransactions($address, $xactions);
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($address_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
$dialog = $this->newDialog();
|
||||||
|
|
||||||
|
$body = array();
|
||||||
|
|
||||||
|
if ($is_disable) {
|
||||||
|
$title = pht('Disable Address');
|
||||||
|
|
||||||
|
$body[] = pht(
|
||||||
|
'This address will no longer receive email, and access links will '.
|
||||||
|
'no longer function.');
|
||||||
|
|
||||||
|
$submit = pht('Disable Address');
|
||||||
|
} else {
|
||||||
|
$title = pht('Enable Address');
|
||||||
|
|
||||||
|
$body[] = pht(
|
||||||
|
'This address will receive email again, and existing links '.
|
||||||
|
'to access order history will work again.');
|
||||||
|
|
||||||
|
$submit = pht('Enable Address');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($body as $graph) {
|
||||||
|
$dialog->appendParagraph($graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dialog
|
||||||
|
->setTitle($title)
|
||||||
|
->addCancelButton($address_uri)
|
||||||
|
->addSubmitButton($submit);
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ final class PhortuneAccountEmailViewController
|
||||||
$address = id(new PhortuneAccountEmailQuery())
|
$address = id(new PhortuneAccountEmailQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withAccountPHIDs(array($account->getPHID()))
|
->withAccountPHIDs(array($account->getPHID()))
|
||||||
->withIDs(array($request->getURIData('id')))
|
->withIDs(array($request->getURIData('addressID')))
|
||||||
->executeOne();
|
->executeOne();
|
||||||
if (!$address) {
|
if (!$address) {
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
|
@ -83,6 +83,56 @@ final class PhortuneAccountEmailViewController
|
||||||
->setDisabled(!$can_edit)
|
->setDisabled(!$can_edit)
|
||||||
->setWorkflow(!$can_edit));
|
->setWorkflow(!$can_edit));
|
||||||
|
|
||||||
|
switch ($address->getStatus()) {
|
||||||
|
case PhortuneAccountEmailStatus::STATUS_ACTIVE:
|
||||||
|
$disable_name = pht('Disable Address');
|
||||||
|
$disable_icon = 'fa-times';
|
||||||
|
$can_disable = true;
|
||||||
|
$disable_action = 'disable';
|
||||||
|
break;
|
||||||
|
case PhortuneAccountEmailStatus::STATUS_DISABLED:
|
||||||
|
$disable_name = pht('Enable Address');
|
||||||
|
$disable_icon = 'fa-check';
|
||||||
|
$can_disable = true;
|
||||||
|
$disable_action = 'enable';
|
||||||
|
break;
|
||||||
|
case PhortuneAccountEmailStatus::STATUS_UNSUBSCRIBED:
|
||||||
|
$disable_name = pht('Disable Address');
|
||||||
|
$disable_icon = 'fa-times';
|
||||||
|
$can_disable = false;
|
||||||
|
$disable_action = 'disable';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$disable_uri = $this->getApplicationURI(
|
||||||
|
urisprintf(
|
||||||
|
'account/%d/addresses/%d/%s/',
|
||||||
|
$account->getID(),
|
||||||
|
$address->getID(),
|
||||||
|
$disable_action));
|
||||||
|
|
||||||
|
$curtain->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName($disable_name)
|
||||||
|
->setIcon($disable_icon)
|
||||||
|
->setHref($disable_uri)
|
||||||
|
->setDisabled(!$can_disable)
|
||||||
|
->setWorkflow(true));
|
||||||
|
|
||||||
|
$rotate_uri = $this->getApplicationURI(
|
||||||
|
urisprintf(
|
||||||
|
'account/%d/addresses/%d/rotate/',
|
||||||
|
$account->getID(),
|
||||||
|
$address->getID()));
|
||||||
|
|
||||||
|
$curtain->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('Rotate Access Key'))
|
||||||
|
->setIcon('fa-refresh')
|
||||||
|
->setHref($rotate_uri)
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(true));
|
||||||
|
|
||||||
$curtain->addAction(
|
$curtain->addAction(
|
||||||
id(new PhabricatorActionView())
|
id(new PhabricatorActionView())
|
||||||
->setName(pht('Show External View'))
|
->setName(pht('Show External View'))
|
||||||
|
@ -100,7 +150,23 @@ final class PhortuneAccountEmailViewController
|
||||||
$view = id(new PHUIPropertyListView())
|
$view = id(new PHUIPropertyListView())
|
||||||
->setUser($viewer);
|
->setUser($viewer);
|
||||||
|
|
||||||
|
$access_key = $address->getAccessKey();
|
||||||
|
|
||||||
|
// This is not a meaningful security barrier: the full plaintext of the
|
||||||
|
// access key is visible on the page in the link target of the "Show
|
||||||
|
// External View" action. It's just here to make it clear "Rotate Access
|
||||||
|
// Key" actually does something.
|
||||||
|
|
||||||
|
$prefix_length = 4;
|
||||||
|
$visible_part = substr($access_key, 0, $prefix_length);
|
||||||
|
$masked_part = str_repeat(
|
||||||
|
"\xE2\x80\xA2",
|
||||||
|
strlen($access_key) - $prefix_length);
|
||||||
|
$access_display = $visible_part.$masked_part;
|
||||||
|
$access_display = phutil_tag('tt', array(), $access_display);
|
||||||
|
|
||||||
$view->addProperty(pht('Email Address'), $address->getAddress());
|
$view->addProperty(pht('Email Address'), $address->getAddress());
|
||||||
|
$view->addProperty(pht('Access Key'), $access_display);
|
||||||
|
|
||||||
return id(new PHUIObjectBoxView())
|
return id(new PHUIObjectBoxView())
|
||||||
->setHeaderText(pht('Email Address Details'))
|
->setHeaderText(pht('Email Address Details'))
|
||||||
|
|
|
@ -83,7 +83,29 @@ abstract class PhortuneExternalController
|
||||||
return $dialog;
|
return $dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test that status is good.
|
switch ($email->getStatus()) {
|
||||||
|
case PhortuneAccountEmailStatus::STATUS_ACTIVE:
|
||||||
|
break;
|
||||||
|
case PhortuneAccountEmailStatus::STATUS_DISABLED:
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Address Disabled'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'This email address (%s) has been disabled and no longer has '.
|
||||||
|
'access to this payment account.',
|
||||||
|
$email_display));
|
||||||
|
case PhortuneAccountEmailStatus::STATUS_UNSUBSCRIBED:
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Permanently Unsubscribed'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'This email address (%s) has been permanently unsubscribed '.
|
||||||
|
'and no longer has access to this payment account.',
|
||||||
|
$email_display));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
$this->email = $email;
|
$this->email = $email;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,14 @@ final class PhortuneExternalOverviewController
|
||||||
->setBorder(true);
|
->setBorder(true);
|
||||||
|
|
||||||
$header = id(new PHUIHeaderView())
|
$header = id(new PHUIHeaderView())
|
||||||
->setHeader(pht('Invoices and Receipts: %s', $account->getName()));
|
->setHeader(pht('Invoices and Receipts: %s', $account->getName()))
|
||||||
|
->addActionLink(
|
||||||
|
id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setIcon('fa-times')
|
||||||
|
->setText(pht('Unsubscribe'))
|
||||||
|
->setHref($email->getUnsubscribeURI())
|
||||||
|
->setWorkflow(true));
|
||||||
|
|
||||||
$external_view = $this->newExternalView();
|
$external_view = $this->newExternalView();
|
||||||
$invoices_view = $this->newInvoicesView();
|
$invoices_view = $this->newInvoicesView();
|
||||||
|
|
67
src/applications/phortune/controller/external/PhortuneExternalUnsubscribeController.php
vendored
Normal file
67
src/applications/phortune/controller/external/PhortuneExternalUnsubscribeController.php
vendored
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhortuneExternalUnsubscribeController
|
||||||
|
extends PhortuneExternalController {
|
||||||
|
|
||||||
|
protected function handleExternalRequest(AphrontRequest $request) {
|
||||||
|
$xviewer = $this->getExternalViewer();
|
||||||
|
$email = $this->getAccountEmail();
|
||||||
|
$account = $email->getAccount();
|
||||||
|
|
||||||
|
$email_uri = $email->getExternalURI();
|
||||||
|
|
||||||
|
if ($request->isFormOrHisecPost()) {
|
||||||
|
$xactions = array();
|
||||||
|
|
||||||
|
$xactions[] = $email->getApplicationTransactionTemplate()
|
||||||
|
->setTransactionType(
|
||||||
|
PhortuneAccountEmailStatusTransaction::TRANSACTIONTYPE)
|
||||||
|
->setNewValue(PhortuneAccountEmailStatus::STATUS_UNSUBSCRIBED);
|
||||||
|
|
||||||
|
$email->getApplicationTransactionEditor()
|
||||||
|
->setActor($xviewer)
|
||||||
|
->setActingAsPHID($email->getPHID())
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setContinueOnMissingFields(true)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
|
->setCancelURI($email_uri)
|
||||||
|
->applyTransactions($email, $xactions);
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($email_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
$email_display = phutil_tag(
|
||||||
|
'strong',
|
||||||
|
array(),
|
||||||
|
$email->getAddress());
|
||||||
|
|
||||||
|
$account_display = phutil_tag(
|
||||||
|
'strong',
|
||||||
|
array(),
|
||||||
|
$account->getName());
|
||||||
|
|
||||||
|
$submit = pht(
|
||||||
|
'Permanently Unsubscribe (%s)',
|
||||||
|
$email->getAddress());
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Permanently Unsubscribe'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'Permanently unsubscribe this email address (%s) from this '.
|
||||||
|
'payment account (%s)?',
|
||||||
|
$email_display,
|
||||||
|
$account_display))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'You will no longer receive email and access links will no longer '.
|
||||||
|
'function.'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'This action is permanent and can not be undone.'))
|
||||||
|
->addCancelButton($email_uri)
|
||||||
|
->addSubmitButton($submit);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -85,6 +85,13 @@ final class PhortuneAccountEmail
|
||||||
$this->getAccessKey());
|
$this->getAccessKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getUnsubscribeURI() {
|
||||||
|
return urisprintf(
|
||||||
|
'/phortune/external/%s/%s/unsubscribe/',
|
||||||
|
$this->getAddressKey(),
|
||||||
|
$this->getAccessKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhortuneAccountEmailRotateTransaction
|
||||||
|
extends PhortuneAccountEmailTransactionType {
|
||||||
|
|
||||||
|
const TRANSACTIONTYPE = 'rotate';
|
||||||
|
|
||||||
|
public function generateOldValue($object) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyInternalEffects($object, $value) {
|
||||||
|
$access_key = Filesystem::readRandomCharacters(16);
|
||||||
|
$object->setAccessKey($access_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
return pht(
|
||||||
|
'%s rotated the access key for this email address.',
|
||||||
|
$this->renderAuthor());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhortuneAccountEmailStatusTransaction
|
||||||
|
extends PhortuneAccountEmailTransactionType {
|
||||||
|
|
||||||
|
const TRANSACTIONTYPE = 'status';
|
||||||
|
|
||||||
|
public function generateOldValue($object) {
|
||||||
|
return $object->getStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyInternalEffects($object, $value) {
|
||||||
|
$object->setStatus($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
return pht(
|
||||||
|
'%s changed the status for this address to %s.',
|
||||||
|
$this->renderAuthor(),
|
||||||
|
$this->renderNewValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue