mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-26 07:20:57 +01:00
Roughly support external/email user views of Phortune recipts and invoices
Summary: Ref T13366. This gives each account email address an "external portal" section so they can access invoices and receipts without an account. Test Plan: Viewed portal as user with authority and in an incognito window. Maniphest Tasks: T13366 Differential Revision: https://secure.phabricator.com/D20737
This commit is contained in:
parent
a39a37fc0e
commit
8f6a1ab015
8 changed files with 293 additions and 10 deletions
|
@ -5294,6 +5294,8 @@ phutil_register_library_map(array(
|
|||
'PhortuneDAO' => 'applications/phortune/storage/PhortuneDAO.php',
|
||||
'PhortuneDisplayException' => 'applications/phortune/exception/PhortuneDisplayException.php',
|
||||
'PhortuneErrCode' => 'applications/phortune/constants/PhortuneErrCode.php',
|
||||
'PhortuneExternalController' => 'applications/phortune/controller/external/PhortuneExternalController.php',
|
||||
'PhortuneExternalOverviewController' => 'applications/phortune/controller/external/PhortuneExternalOverviewController.php',
|
||||
'PhortuneInvoiceView' => 'applications/phortune/view/PhortuneInvoiceView.php',
|
||||
'PhortuneLandingController' => 'applications/phortune/controller/PhortuneLandingController.php',
|
||||
'PhortuneMemberHasAccountEdgeType' => 'applications/phortune/edge/PhortuneMemberHasAccountEdgeType.php',
|
||||
|
@ -11879,6 +11881,8 @@ phutil_register_library_map(array(
|
|||
'PhortuneDAO' => 'PhabricatorLiskDAO',
|
||||
'PhortuneDisplayException' => 'Exception',
|
||||
'PhortuneErrCode' => 'PhortuneConstants',
|
||||
'PhortuneExternalController' => 'PhortuneController',
|
||||
'PhortuneExternalOverviewController' => 'PhortuneExternalController',
|
||||
'PhortuneInvoiceView' => 'AphrontTagView',
|
||||
'PhortuneLandingController' => 'PhortuneController',
|
||||
'PhortuneMemberHasAccountEdgeType' => 'PhabricatorEdgeType',
|
||||
|
|
|
@ -104,6 +104,9 @@ final class PhabricatorPhortuneApplication extends PhabricatorApplication {
|
|||
'(?P<id>\d+)/(?P<action>[^/]+)/'
|
||||
=> 'PhortuneProviderActionController',
|
||||
),
|
||||
'external/(?P<addressKey>[^/]+)/(?P<accessKey>[^/]+)/' => array(
|
||||
'' => 'PhortuneExternalOverviewController',
|
||||
),
|
||||
'merchant/' => array(
|
||||
$this->getQueryRoutePattern()
|
||||
=> 'PhortuneMerchantListController',
|
||||
|
|
|
@ -67,6 +67,12 @@ final class PhortuneAccountEmailViewController
|
|||
$account->getID(),
|
||||
$address->getID()));
|
||||
|
||||
if ($can_edit) {
|
||||
$external_uri = $address->getExternalURI();
|
||||
} else {
|
||||
$external_uri = null;
|
||||
}
|
||||
|
||||
$curtain = $this->newCurtainView($account);
|
||||
|
||||
$curtain->addAction(
|
||||
|
@ -77,6 +83,14 @@ final class PhortuneAccountEmailViewController
|
|||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Show External View'))
|
||||
->setIcon('fa-eye')
|
||||
->setHref($external_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setOpenInNewWindow(true));
|
||||
|
||||
return $curtain;
|
||||
}
|
||||
|
||||
|
|
147
src/applications/phortune/controller/external/PhortuneExternalController.php
vendored
Normal file
147
src/applications/phortune/controller/external/PhortuneExternalController.php
vendored
Normal file
|
@ -0,0 +1,147 @@
|
|||
<?php
|
||||
|
||||
abstract class PhortuneExternalController
|
||||
extends PhortuneController {
|
||||
|
||||
private $email;
|
||||
|
||||
final public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
abstract protected function handleExternalRequest(AphrontRequest $request);
|
||||
|
||||
final protected function hasAccountEmail() {
|
||||
return (bool)$this->email;
|
||||
}
|
||||
|
||||
final protected function getAccountEmail() {
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
final protected function getExternalViewer() {
|
||||
return PhabricatorUser::getOmnipotentUser();
|
||||
}
|
||||
|
||||
final public function handleRequest(AphrontRequest $request) {
|
||||
$address_key = $request->getURIData('addressKey');
|
||||
$access_key = $request->getURIData('accessKey');
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$xviewer = $this->getExternalViewer();
|
||||
|
||||
$email = id(new PhortuneAccountEmailQuery())
|
||||
->setViewer($xviewer)
|
||||
->withAddressKeys(array($address_key))
|
||||
->executeOne();
|
||||
if (!$email) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$account = $email->getAccount();
|
||||
|
||||
$can_see = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$account,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$email_display = phutil_tag('strong', array(), $email->getAddress());
|
||||
$user_display = phutil_tag('strong', array(), $viewer->getUsername());
|
||||
|
||||
$actual_key = $email->getAccessKey();
|
||||
if (!phutil_hashes_are_identical($access_key, $actual_key)) {
|
||||
$dialog = $this->newDialog()
|
||||
->setTitle(pht('Email Access Link Out of Date'))
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'You are trying to access this payment account as: %s',
|
||||
$email_display))
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'The access link you have followed is out of date and no longer '.
|
||||
'works.'));
|
||||
|
||||
if ($can_see) {
|
||||
$dialog->appendParagraph(
|
||||
pht(
|
||||
'You are currently logged in as a user (%s) who has '.
|
||||
'permission to manage the payment account, so you can '.
|
||||
'continue to the updated link.',
|
||||
$user_display));
|
||||
|
||||
$dialog->addCancelButton(
|
||||
$email->getExternalURI(),
|
||||
pht('Continue to Updated Link'));
|
||||
} else {
|
||||
$dialog->appendParagraph(
|
||||
pht(
|
||||
'To access information about this payment account, follow '.
|
||||
'a more recent link or ask a user with access to give you '.
|
||||
'an updated link.'));
|
||||
}
|
||||
|
||||
return $dialog;
|
||||
}
|
||||
|
||||
// TODO: Test that status is good.
|
||||
|
||||
$this->email = $email;
|
||||
|
||||
return $this->handleExternalRequest($request);
|
||||
}
|
||||
|
||||
final protected function newExternalCrumbs() {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$crumbs = new PHUICrumbsView();
|
||||
|
||||
if ($this->hasAccountEmail()) {
|
||||
$email = $this->getAccountEmail();
|
||||
$account = $email->getAccount();
|
||||
|
||||
$crumb_name = pht(
|
||||
'Payment Account: %s',
|
||||
$account->getName());
|
||||
|
||||
$crumb = id(new PHUICrumbView())
|
||||
->setIcon('fa-diamond')
|
||||
->setName($crumb_name);
|
||||
|
||||
$can_see = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$account,
|
||||
PhabricatorPolicyCapability::CAN_VIEW);
|
||||
if ($can_see) {
|
||||
$crumb->setHref($account->getURI());
|
||||
}
|
||||
|
||||
$crumbs
|
||||
->addCrumb($crumb)
|
||||
->addTextCrumb(pht('Viewing As "%s"', $email->getAddress()));
|
||||
} else {
|
||||
$crumb = id(new PHUICrumbView())
|
||||
->setIcon('fa-diamond')
|
||||
->setText(pht('External Account View'));
|
||||
|
||||
$crumbs->addCrumb($crumb);
|
||||
}
|
||||
|
||||
return $crumbs;
|
||||
}
|
||||
|
||||
final protected function newExternalView() {
|
||||
$email = $this->getAccountEmail();
|
||||
|
||||
$messages = array();
|
||||
$messages[] = pht(
|
||||
'You are viewing this payment account as: %s',
|
||||
phutil_tag('strong', array(), $email->getAddress()));
|
||||
$messages[] = pht(
|
||||
'Anyone who has a link to this page can view order history for '.
|
||||
'this payment account.');
|
||||
|
||||
return id(new PHUIInfoView())
|
||||
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
|
||||
->setErrors($messages);
|
||||
}
|
||||
}
|
91
src/applications/phortune/controller/external/PhortuneExternalOverviewController.php
vendored
Normal file
91
src/applications/phortune/controller/external/PhortuneExternalOverviewController.php
vendored
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
final class PhortuneExternalOverviewController
|
||||
extends PhortuneExternalController {
|
||||
|
||||
protected function handleExternalRequest(AphrontRequest $request) {
|
||||
$xviewer = $this->getExternalViewer();
|
||||
$email = $this->getAccountEmail();
|
||||
$account = $email->getAccount();
|
||||
|
||||
$crumbs = $this->newExternalCrumbs()
|
||||
->setBorder(true);
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Invoices and Receipts: %s', $account->getName()));
|
||||
|
||||
$external_view = $this->newExternalView();
|
||||
$invoices_view = $this->newInvoicesView();
|
||||
$receipts_view = $this->newReceiptsView();
|
||||
|
||||
$column_view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter(
|
||||
array(
|
||||
$external_view,
|
||||
$invoices_view,
|
||||
$receipts_view,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setCrumbs($crumbs)
|
||||
->setTitle(
|
||||
array(
|
||||
pht('Invoices and Receipts'),
|
||||
$account->getName(),
|
||||
))
|
||||
->appendChild($column_view);
|
||||
}
|
||||
|
||||
private function newInvoicesView() {
|
||||
$xviewer = $this->getExternalViewer();
|
||||
$email = $this->getAccountEmail();
|
||||
$account = $email->getAccount();
|
||||
|
||||
$invoices = id(new PhortuneCartQuery())
|
||||
->setViewer($xviewer)
|
||||
->withAccountPHIDs(array($account->getPHID()))
|
||||
->needPurchases(true)
|
||||
->withInvoices(true)
|
||||
->execute();
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Invoices'));
|
||||
|
||||
$invoices_table = id(new PhortuneOrderTableView())
|
||||
->setViewer($xviewer)
|
||||
->setCarts($invoices)
|
||||
->setIsInvoices(true);
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setTable($invoices_table);
|
||||
}
|
||||
|
||||
private function newReceiptsView() {
|
||||
$xviewer = $this->getExternalViewer();
|
||||
$email = $this->getAccountEmail();
|
||||
$account = $email->getAccount();
|
||||
|
||||
$receipts = id(new PhortuneCartQuery())
|
||||
->setViewer($xviewer)
|
||||
->withAccountPHIDs(array($account->getPHID()))
|
||||
->needPurchases(true)
|
||||
->withInvoices(false)
|
||||
->execute();
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Receipts'));
|
||||
|
||||
$receipts_table = id(new PhortuneOrderTableView())
|
||||
->setViewer($xviewer)
|
||||
->setCarts($receipts);
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setTable($receipts_table);
|
||||
}
|
||||
|
||||
}
|
|
@ -6,6 +6,7 @@ final class PhortuneAccountEmailQuery
|
|||
private $ids;
|
||||
private $phids;
|
||||
private $accountPHIDs;
|
||||
private $addressKeys;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -22,6 +23,11 @@ final class PhortuneAccountEmailQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withAddressKeys(array $keys) {
|
||||
$this->addressKeys = $keys;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function newResultObject() {
|
||||
return new PhortuneAccountEmail();
|
||||
}
|
||||
|
@ -77,6 +83,13 @@ final class PhortuneAccountEmailQuery
|
|||
$this->accountPHIDs);
|
||||
}
|
||||
|
||||
if ($this->addressKeys !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'address.addressKey IN (%Ls)',
|
||||
$this->addressKeys);
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
|
|
|
@ -78,6 +78,13 @@ final class PhortuneAccountEmail
|
|||
$this->getID());
|
||||
}
|
||||
|
||||
public function getExternalURI() {
|
||||
return urisprintf(
|
||||
'/phortune/external/%s/%s/',
|
||||
$this->getAddressKey(),
|
||||
$this->getAccessKey());
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ final class PhortuneOrderTableView extends AphrontView {
|
|||
|
||||
$is_invoices = $this->getIsInvoices();
|
||||
$is_merchant = $this->getIsMerchantView();
|
||||
$is_external = (!$viewer->getPHID());
|
||||
|
||||
$phids = array();
|
||||
foreach ($carts as $cart) {
|
||||
|
@ -69,14 +70,18 @@ final class PhortuneOrderTableView extends AphrontView {
|
|||
|
||||
if (count($purchases) == 1) {
|
||||
$purchase = head($purchases);
|
||||
$purchase_name = $handles[$purchase->getPHID()]->renderLink();
|
||||
$purchase_name = $handles[$purchase->getPHID()]->getName();
|
||||
$purchases = array();
|
||||
} else {
|
||||
$purchase_name = '';
|
||||
}
|
||||
|
||||
if ($is_invoices) {
|
||||
$merchant_link = $handles[$cart->getMerchantPHID()]->renderLink();
|
||||
if ($is_external) {
|
||||
$merchant_link = $handles[$cart->getMerchantPHID()]->getName();
|
||||
} else {
|
||||
$merchant_link = $handles[$cart->getMerchantPHID()]->renderLink();
|
||||
}
|
||||
} else {
|
||||
$merchant_link = null;
|
||||
}
|
||||
|
@ -97,13 +102,12 @@ final class PhortuneOrderTableView extends AphrontView {
|
|||
PhortuneCart::getNameForStatus($cart->getStatus()),
|
||||
phabricator_datetime($cart->getDateModified(), $viewer),
|
||||
phabricator_datetime($cart->getDateCreated(), $viewer),
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $cart->getCheckoutURI(),
|
||||
'class' => 'small button button-green',
|
||||
),
|
||||
pht('Pay Now')),
|
||||
id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setColor('green')
|
||||
->setHref($cart->getCheckoutURI())
|
||||
->setText(pht('Pay Now'))
|
||||
->setIcon('fa-credit-card'),
|
||||
);
|
||||
foreach ($purchases as $purchase) {
|
||||
$id = $purchase->getID();
|
||||
|
@ -164,7 +168,7 @@ final class PhortuneOrderTableView extends AphrontView {
|
|||
|
||||
// We show "Pay Now" for due invoices, but not if the viewer is the
|
||||
// merchant, since it doesn't make sense for them to pay.
|
||||
($is_invoices && !$is_merchant),
|
||||
($is_invoices && !$is_merchant && !$is_external),
|
||||
));
|
||||
|
||||
return $table;
|
||||
|
|
Loading…
Reference in a new issue