mirror of
https://we.phorge.it/source/phorge.git
synced 2025-02-05 19:38:27 +01:00
Add boilerplate scaffolding for Phortune subscriptions
Summary: Ref T6881. This roughs in the major objects, support classes, and controllers. - Show subscriptions on account detail. - Browse all account subscriptions. - Link to active subsciptions from merchant detail. Test Plan: Clicked around in the UI. There's no way to create subscriptions yet, so I basically just kicked the tires on this. I probably missed a few things that I'll clean up in followups. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T6881 Differential Revision: https://secure.phabricator.com/D11482
This commit is contained in:
parent
5b6b2ee850
commit
7720b799e4
12 changed files with 744 additions and 1 deletions
20
resources/sql/autopatches/20150124.subs.1.sql
Normal file
20
resources/sql/autopatches/20150124.subs.1.sql
Normal file
|
@ -0,0 +1,20 @@
|
|||
CREATE TABLE {$NAMESPACE}_phortune.phortune_subscription (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
phid VARBINARY(64) NOT NULL,
|
||||
accountPHID VARBINARY(64) NOT NULL,
|
||||
merchantPHID VARBINARY(64) NOT NULL,
|
||||
triggerPHID VARBINARY(64) NOT NULL,
|
||||
authorPHID VARBINARY(64) NOT NULL,
|
||||
subscriptionClassKey BINARY(12) NOT NULL,
|
||||
subscriptionClass VARCHAR(128) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||
subscriptionRefKey BINARY(12) NOT NULL,
|
||||
subscriptionRef VARCHAR(128) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||
status VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||
metadata LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL,
|
||||
UNIQUE KEY `key_phid` (phid),
|
||||
UNIQUE KEY `key_subscription` (subscriptionClassKey, subscriptionRefKey),
|
||||
KEY `key_account` (accountPHID),
|
||||
KEY `key_merchant` (merchantPHID)
|
||||
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
|
@ -2804,6 +2804,13 @@ phutil_register_library_map(array(
|
|||
'PhortunePurchaseQuery' => 'applications/phortune/query/PhortunePurchaseQuery.php',
|
||||
'PhortuneSchemaSpec' => 'applications/phortune/storage/PhortuneSchemaSpec.php',
|
||||
'PhortuneStripePaymentProvider' => 'applications/phortune/provider/PhortuneStripePaymentProvider.php',
|
||||
'PhortuneSubscription' => 'applications/phortune/storage/PhortuneSubscription.php',
|
||||
'PhortuneSubscriptionImplementation' => 'applications/phortune/subscription/PhortuneSubscriptionImplementation.php',
|
||||
'PhortuneSubscriptionListController' => 'applications/phortune/controller/PhortuneSubscriptionListController.php',
|
||||
'PhortuneSubscriptionPHIDType' => 'applications/phortune/phid/PhortuneSubscriptionPHIDType.php',
|
||||
'PhortuneSubscriptionQuery' => 'applications/phortune/query/PhortuneSubscriptionQuery.php',
|
||||
'PhortuneSubscriptionSearchEngine' => 'applications/phortune/query/PhortuneSubscriptionSearchEngine.php',
|
||||
'PhortuneSubscriptionTableView' => 'applications/phortune/view/PhortuneSubscriptionTableView.php',
|
||||
'PhortuneTestPaymentProvider' => 'applications/phortune/provider/PhortuneTestPaymentProvider.php',
|
||||
'PhortuneWePayPaymentProvider' => 'applications/phortune/provider/PhortuneWePayPaymentProvider.php',
|
||||
'PhragmentBrowseController' => 'applications/phragment/controller/PhragmentBrowseController.php',
|
||||
|
@ -6144,6 +6151,15 @@ phutil_register_library_map(array(
|
|||
'PhortunePurchaseQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhortuneSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||
'PhortuneStripePaymentProvider' => 'PhortunePaymentProvider',
|
||||
'PhortuneSubscription' => array(
|
||||
'PhortuneDAO',
|
||||
'PhabricatorPolicyInterface',
|
||||
),
|
||||
'PhortuneSubscriptionListController' => 'PhortuneController',
|
||||
'PhortuneSubscriptionPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhortuneSubscriptionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhortuneSubscriptionSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'PhortuneSubscriptionTableView' => 'AphrontView',
|
||||
'PhortuneTestPaymentProvider' => 'PhortunePaymentProvider',
|
||||
'PhortuneWePayPaymentProvider' => 'PhortunePaymentProvider',
|
||||
'PhragmentBrowseController' => 'PhragmentController',
|
||||
|
|
|
@ -45,6 +45,8 @@ final class PhabricatorPhortuneApplication extends PhabricatorApplication {
|
|||
),
|
||||
'order/(?:query/(?P<queryKey>[^/]+)/)?'
|
||||
=> 'PhortuneCartListController',
|
||||
'subscription/(?:query/(?P<queryKey>[^/]+)/)?'
|
||||
=> 'PhortuneSubscriptionListController',
|
||||
'charge/(?:query/(?P<queryKey>[^/]+)/)?'
|
||||
=> 'PhortuneChargeListController',
|
||||
),
|
||||
|
@ -77,8 +79,10 @@ final class PhabricatorPhortuneApplication extends PhabricatorApplication {
|
|||
'merchant/' => array(
|
||||
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhortuneMerchantListController',
|
||||
'edit/(?:(?P<id>\d+)/)?' => 'PhortuneMerchantEditController',
|
||||
'orders/(?P<merchantID>\d+)/(?:query/(?P<querKey>[^/]+)/)?'
|
||||
'orders/(?P<merchantID>\d+)/(?:query/(?P<queryKey>[^/]+)/)?'
|
||||
=> 'PhortuneCartListController',
|
||||
'subscription/(?P<merchantID>\d+)/(?:query/(?P<queryKey>[^/]+)/)?'
|
||||
=> 'PhortuneSubscriptionListController',
|
||||
'(?P<id>\d+)/' => 'PhortuneMerchantViewController',
|
||||
),
|
||||
),
|
||||
|
|
|
@ -70,6 +70,8 @@ final class PhortuneAccountViewController extends PhortuneController {
|
|||
$payment_methods = $this->buildPaymentMethodsSection($account);
|
||||
$purchase_history = $this->buildPurchaseHistorySection($account);
|
||||
$charge_history = $this->buildChargeHistorySection($account);
|
||||
$subscriptions = $this->buildSubscriptionsSection($account);
|
||||
|
||||
$timeline = $this->buildTransactionTimeline(
|
||||
$account,
|
||||
new PhortuneAccountTransactionQuery());
|
||||
|
@ -86,6 +88,7 @@ final class PhortuneAccountViewController extends PhortuneController {
|
|||
$payment_methods,
|
||||
$purchase_history,
|
||||
$charge_history,
|
||||
$subscriptions,
|
||||
$timeline,
|
||||
),
|
||||
array(
|
||||
|
@ -259,6 +262,39 @@ final class PhortuneAccountViewController extends PhortuneController {
|
|||
->appendChild($table);
|
||||
}
|
||||
|
||||
private function buildSubscriptionsSection(PhortuneAccount $account) {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$subscriptions = id(new PhortuneSubscriptionQuery())
|
||||
->setViewer($viewer)
|
||||
->withAccountPHIDs(array($account->getPHID()))
|
||||
->setLimit(10)
|
||||
->execute();
|
||||
|
||||
$subscriptions_uri = $this->getApplicationURI(
|
||||
$account->getID().'/subscription/');
|
||||
|
||||
$table = id(new PhortuneSubscriptionTableView())
|
||||
->setUser($viewer)
|
||||
->setSubscriptions($subscriptions);
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Recent Subscriptions'))
|
||||
->addActionLink(
|
||||
id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setIcon(
|
||||
id(new PHUIIconView())
|
||||
->setIconFont('fa-list'))
|
||||
->setHref($subscriptions_uri)
|
||||
->setText(pht('View All Subscriptions')));
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->appendChild($table);
|
||||
}
|
||||
|
||||
protected function buildApplicationCrumbs() {
|
||||
$crumbs = parent::buildApplicationCrumbs();
|
||||
|
||||
|
|
|
@ -186,6 +186,14 @@ final class PhortuneMerchantViewController
|
|||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('View Subscriptions'))
|
||||
->setIcon('fa-moon-o')
|
||||
->setHref($this->getApplicationURI("merchant/subscription/{$id}/"))
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
final class PhortuneSubscriptionListController
|
||||
extends PhortuneController {
|
||||
|
||||
private $accountID;
|
||||
private $merchantID;
|
||||
private $queryKey;
|
||||
|
||||
private $merchant;
|
||||
private $account;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->merchantID = idx($data, 'merchantID');
|
||||
$this->accountID = idx($data, 'accountID');
|
||||
$this->queryKey = idx($data, 'queryKey');
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$engine = new PhortuneSubscriptionSearchEngine();
|
||||
|
||||
if ($this->merchantID) {
|
||||
$merchant = id(new PhortuneMerchantQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($this->merchantID))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$merchant) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$this->merchant = $merchant;
|
||||
$engine->setMerchant($merchant);
|
||||
} else if ($this->accountID) {
|
||||
$account = id(new PhortuneAccountQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($this->accountID))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$account) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$this->account = $account;
|
||||
$engine->setAccount($account);
|
||||
} else {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$controller = id(new PhabricatorApplicationSearchController())
|
||||
->setQueryKey($this->queryKey)
|
||||
->setSearchEngine($engine)
|
||||
->setNavigation($this->buildSideNavView());
|
||||
|
||||
return $this->delegateToController($controller);
|
||||
}
|
||||
|
||||
public function buildSideNavView() {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$nav = new AphrontSideNavFilterView();
|
||||
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
|
||||
|
||||
id(new PhortuneSubscriptionSearchEngine())
|
||||
->setViewer($viewer)
|
||||
->addNavigationItems($nav->getMenu());
|
||||
|
||||
$nav->selectFilter(null);
|
||||
|
||||
return $nav;
|
||||
}
|
||||
|
||||
protected function buildApplicationCrumbs() {
|
||||
$crumbs = parent::buildApplicationCrumbs();
|
||||
|
||||
$merchant = $this->merchant;
|
||||
if ($merchant) {
|
||||
$id = $merchant->getID();
|
||||
$crumbs->addTextCrumb(
|
||||
$merchant->getName(),
|
||||
$this->getApplicationURI("merchant/{$id}/"));
|
||||
$crumbs->addTextCrumb(
|
||||
pht('Subscriptions'),
|
||||
$this->getApplicationURI("merchant/subscriptions/{$id}/"));
|
||||
}
|
||||
|
||||
$account = $this->account;
|
||||
if ($account) {
|
||||
$id = $account->getID();
|
||||
$crumbs->addTextCrumb(
|
||||
$account->getName(),
|
||||
$this->getApplicationURI("{$id}/"));
|
||||
$crumbs->addTextCrumb(
|
||||
pht('Subscriptions'),
|
||||
$this->getApplicationURI("{$id}/subscription/"));
|
||||
}
|
||||
|
||||
return $crumbs;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
final class PhortuneSubscriptionPHIDType extends PhabricatorPHIDType {
|
||||
|
||||
const TYPECONST = 'PSUB';
|
||||
|
||||
public function getTypeName() {
|
||||
return pht('Phortune Subscription');
|
||||
}
|
||||
|
||||
public function newObject() {
|
||||
return new PhortuneSubscription();
|
||||
}
|
||||
|
||||
protected function buildQueryForObjects(
|
||||
PhabricatorObjectQuery $query,
|
||||
array $phids) {
|
||||
|
||||
return id(new PhortuneSubscriptionQuery())
|
||||
->withPHIDs($phids);
|
||||
}
|
||||
|
||||
public function loadHandles(
|
||||
PhabricatorHandleQuery $query,
|
||||
array $handles,
|
||||
array $objects) {
|
||||
|
||||
foreach ($handles as $phid => $handle) {
|
||||
$subscription = $objects[$phid];
|
||||
|
||||
$id = $subscription->getID();
|
||||
|
||||
// TODO: Flesh this out.
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
152
src/applications/phortune/query/PhortuneSubscriptionQuery.php
Normal file
152
src/applications/phortune/query/PhortuneSubscriptionQuery.php
Normal file
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
|
||||
final class PhortuneSubscriptionQuery
|
||||
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||
|
||||
private $ids;
|
||||
private $phids;
|
||||
private $accountPHIDs;
|
||||
private $merchantPHIDs;
|
||||
private $statuses;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withPHIDs(array $phids) {
|
||||
$this->phids = $phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withAccountPHIDs(array $account_phids) {
|
||||
$this->accountPHIDs = $account_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withMerchantPHIDs(array $merchant_phids) {
|
||||
$this->merchantPHIDs = $merchant_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withStatuses(array $statuses) {
|
||||
$this->statuses = $statuses;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$table = new PhortuneSubscription();
|
||||
$conn = $table->establishConnection('r');
|
||||
|
||||
$rows = queryfx_all(
|
||||
$conn,
|
||||
'SELECT subscription.* FROM %T subscription %Q %Q %Q',
|
||||
$table->getTableName(),
|
||||
$this->buildWhereClause($conn),
|
||||
$this->buildOrderClause($conn),
|
||||
$this->buildLimitClause($conn));
|
||||
|
||||
return $table->loadAllFromArray($rows);
|
||||
}
|
||||
|
||||
protected function willFilterPage(array $subscriptions) {
|
||||
$accounts = id(new PhortuneAccountQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs(mpull($subscriptions, 'getAccountPHID'))
|
||||
->execute();
|
||||
$accounts = mpull($accounts, null, 'getPHID');
|
||||
|
||||
foreach ($subscriptions as $key => $subscription) {
|
||||
$account = idx($accounts, $subscription->getAccountPHID());
|
||||
if (!$account) {
|
||||
unset($subscriptions[$key]);
|
||||
continue;
|
||||
}
|
||||
$subscription->attachAccount($account);
|
||||
}
|
||||
|
||||
$merchants = id(new PhortuneMerchantQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs(mpull($subscriptions, 'getMerchantPHID'))
|
||||
->execute();
|
||||
$merchants = mpull($merchants, null, 'getPHID');
|
||||
|
||||
foreach ($subscriptions as $key => $subscription) {
|
||||
$merchant = idx($merchants, $subscription->getMerchantPHID());
|
||||
if (!$merchant) {
|
||||
unset($subscriptions[$key]);
|
||||
continue;
|
||||
}
|
||||
$subscription->attachMerchant($merchant);
|
||||
}
|
||||
|
||||
$implementations = array();
|
||||
|
||||
$subscription_map = mgroup($subscriptions, 'getSubscriptionClass');
|
||||
foreach ($subscription_map as $class => $class_subscriptions) {
|
||||
$sub = newv($class, array());
|
||||
$implementations += $sub->loadImplementationsForSubscriptions(
|
||||
$this->getViewer(),
|
||||
$class_subscriptions);
|
||||
}
|
||||
|
||||
foreach ($subscriptions as $key => $subscription) {
|
||||
$implementation = idx($implementations, $key);
|
||||
if (!$implementation) {
|
||||
unset($subscriptions[$key]);
|
||||
continue;
|
||||
}
|
||||
$subscription->attachImplementation($implementation);
|
||||
}
|
||||
|
||||
return $subscriptions;
|
||||
}
|
||||
|
||||
private function buildWhereClause(AphrontDatabaseConnection $conn) {
|
||||
$where = array();
|
||||
|
||||
$where[] = $this->buildPagingClause($conn);
|
||||
|
||||
if ($this->ids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'subscription.id IN (%Ld)',
|
||||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->phids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'subscription.phid IN (%Ls)',
|
||||
$this->phids);
|
||||
}
|
||||
|
||||
if ($this->accountPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'subscription.accountPHID IN (%Ls)',
|
||||
$this->accountPHIDs);
|
||||
}
|
||||
|
||||
if ($this->merchantPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'subscription.merchantPHID IN (%Ls)',
|
||||
$this->merchantPHIDs);
|
||||
}
|
||||
|
||||
if ($this->statuses !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'subscription.status IN (%Ls)',
|
||||
$this->statuses);
|
||||
}
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
}
|
||||
|
||||
public function getQueryApplicationClass() {
|
||||
return 'PhabricatorPhortuneApplication';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
|
||||
final class PhortuneSubscriptionSearchEngine
|
||||
extends PhabricatorApplicationSearchEngine {
|
||||
|
||||
private $merchant;
|
||||
private $account;
|
||||
|
||||
public function setAccount(PhortuneAccount $account) {
|
||||
$this->account = $account;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAccount() {
|
||||
return $this->account;
|
||||
}
|
||||
|
||||
public function setMerchant(PhortuneMerchant $merchant) {
|
||||
$this->merchant = $merchant;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMerchant() {
|
||||
return $this->merchant;
|
||||
}
|
||||
|
||||
public function getResultTypeDescription() {
|
||||
return pht('Phortune Subscriptions');
|
||||
}
|
||||
|
||||
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
||||
$saved = new PhabricatorSavedQuery();
|
||||
|
||||
return $saved;
|
||||
}
|
||||
|
||||
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
||||
$query = id(new PhortuneSubscriptionQuery());
|
||||
|
||||
$viewer = $this->requireViewer();
|
||||
|
||||
$merchant = $this->getMerchant();
|
||||
$account = $this->getAccount();
|
||||
if ($merchant) {
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$merchant,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
if (!$can_edit) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'You can not query subscriptions for a merchant you do not '.
|
||||
'control.'));
|
||||
}
|
||||
$query->withMerchantPHIDs(array($merchant->getPHID()));
|
||||
} else if ($account) {
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$account,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
if (!$can_edit) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'You can not query subscriptions for an account you are not '.
|
||||
'a member of.'));
|
||||
}
|
||||
$query->withAccountPHIDs(array($account->getPHID()));
|
||||
} else {
|
||||
$accounts = id(new PhortuneAccountQuery())
|
||||
->withMemberPHIDs(array($viewer->getPHID()))
|
||||
->execute();
|
||||
if ($accounts) {
|
||||
$query->withAccountPHIDs(mpull($accounts, 'getPHID'));
|
||||
} else {
|
||||
throw new Exception(pht('You have no accounts!'));
|
||||
}
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function buildSearchForm(
|
||||
AphrontFormView $form,
|
||||
PhabricatorSavedQuery $saved_query) {}
|
||||
|
||||
protected function getURI($path) {
|
||||
$merchant = $this->getMerchant();
|
||||
$account = $this->getAccount();
|
||||
if ($merchant) {
|
||||
return '/phortune/merchant/'.$merchant->getID().'/subscription/'.$path;
|
||||
} else if ($account) {
|
||||
return '/phortune/'.$account->getID().'/subscription/';
|
||||
} else {
|
||||
return '/phortune/subscription/'.$path;
|
||||
}
|
||||
}
|
||||
|
||||
protected function getBuiltinQueryNames() {
|
||||
$names = array(
|
||||
'all' => pht('All Subscriptions'),
|
||||
);
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
public function buildSavedQueryFromBuiltin($query_key) {
|
||||
|
||||
$query = $this->newSavedQuery();
|
||||
$query->setQueryKey($query_key);
|
||||
|
||||
switch ($query_key) {
|
||||
case 'all':
|
||||
return $query;
|
||||
}
|
||||
|
||||
return parent::buildSavedQueryFromBuiltin($query_key);
|
||||
}
|
||||
|
||||
protected function getRequiredHandlePHIDsForResultList(
|
||||
array $subscriptions,
|
||||
PhabricatorSavedQuery $query) {
|
||||
$phids = array();
|
||||
foreach ($subscriptions as $subscription) {
|
||||
$phids[] = $subscription->getPHID();
|
||||
$phids[] = $subscription->getMerchantPHID();
|
||||
$phids[] = $subscription->getAuthorPHID();
|
||||
}
|
||||
return $phids;
|
||||
}
|
||||
|
||||
protected function renderResultList(
|
||||
array $subscriptions,
|
||||
PhabricatorSavedQuery $query,
|
||||
array $handles) {
|
||||
assert_instances_of($subscriptions, 'PhortuneSubscription');
|
||||
|
||||
$viewer = $this->requireViewer();
|
||||
|
||||
$table = id(new PhortuneSubscriptionTableView())
|
||||
->setUser($viewer)
|
||||
->setSubscriptions($subscriptions);
|
||||
|
||||
$merchant = $this->getMerchant();
|
||||
if ($merchant) {
|
||||
$header = pht('Subscriptions for %s', $merchant->getName());
|
||||
} else {
|
||||
$header = pht('Your Subscriptions');
|
||||
}
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeaderText($header)
|
||||
->appendChild($table);
|
||||
}
|
||||
}
|
131
src/applications/phortune/storage/PhortuneSubscription.php
Normal file
131
src/applications/phortune/storage/PhortuneSubscription.php
Normal file
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* A subscription bills users regularly.
|
||||
*/
|
||||
final class PhortuneSubscription extends PhortuneDAO
|
||||
implements PhabricatorPolicyInterface {
|
||||
|
||||
const STATUS_ACTIVE = 'active';
|
||||
const STATUS_CANCELLED = 'cancelled';
|
||||
|
||||
protected $accountPHID;
|
||||
protected $merchantPHID;
|
||||
protected $triggerPHID;
|
||||
protected $authorPHID;
|
||||
protected $subscriptionClassKey;
|
||||
protected $subscriptionClass;
|
||||
protected $subscriptionRefKey;
|
||||
protected $subscriptionRef;
|
||||
protected $status;
|
||||
protected $metadata = array();
|
||||
|
||||
private $merchant = self::ATTACHABLE;
|
||||
private $account = self::ATTACHABLE;
|
||||
private $implementation = self::ATTACHABLE;
|
||||
private $trigger = self::ATTACHABLE;
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_AUX_PHID => true,
|
||||
self::CONFIG_SERIALIZATION => array(
|
||||
'metadata' => self::SERIALIZATION_JSON,
|
||||
),
|
||||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
'subscriptionClassKey' => 'bytes12',
|
||||
'subscriptionClass' => 'text128',
|
||||
'subscriptionRefKey' => 'bytes12',
|
||||
'subscriptionRef' => 'text128',
|
||||
'status' => 'text32',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_subscription' => array(
|
||||
'columns' => array('subscriptionClassKey', 'subscriptionRefKey'),
|
||||
'unique' => true,
|
||||
),
|
||||
'key_account' => array(
|
||||
'columns' => array('accountPHID'),
|
||||
),
|
||||
'key_merchant' => array(
|
||||
'columns' => array('merchantPHID'),
|
||||
),
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public function generatePHID() {
|
||||
return PhabricatorPHID::generateNewPHID(
|
||||
PhortuneSubscriptionPHIDType::TYPECONST);
|
||||
}
|
||||
|
||||
public static function initializeNewSubscription() {
|
||||
return id(new PhortuneSubscription());
|
||||
}
|
||||
|
||||
public function attachImplementation(
|
||||
PhortuneSubscriptionImplementation $impl) {
|
||||
$this->implementation = $impl;
|
||||
}
|
||||
|
||||
public function getImplementation() {
|
||||
return $this->assertAttached($this->implementation);
|
||||
}
|
||||
|
||||
public function save() {
|
||||
$this->subscriptionClassKey = PhabricatorHash::digestForIndex(
|
||||
$this->subscriptionClass);
|
||||
|
||||
$this->subscriptionRefKey = PhabricatorHash::digestForIndex(
|
||||
$this->subscriptionRef);
|
||||
|
||||
return parent::save();
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||
|
||||
|
||||
public function getCapabilities() {
|
||||
return array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
);
|
||||
}
|
||||
|
||||
public function getPolicy($capability) {
|
||||
// NOTE: Both view and edit use the account's edit policy. We punch a hole
|
||||
// through this for merchants, below.
|
||||
return $this
|
||||
->getAccount()
|
||||
->getPolicy(PhabricatorPolicyCapability::CAN_EDIT);
|
||||
}
|
||||
|
||||
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||
if ($this->getAccount()->hasAutomaticCapability($capability, $viewer)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the viewer controls the merchant this subscription bills to, they can
|
||||
// view the subscription.
|
||||
if ($capability == PhabricatorPolicyCapability::CAN_VIEW) {
|
||||
$can_admin = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$this->getMerchant(),
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
if ($can_admin) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function describeAutomaticCapability($capability) {
|
||||
return array(
|
||||
pht('Subscriptions inherit the policies of the associated account.'),
|
||||
pht(
|
||||
'The merchant you are subscribed with can review and manage the '.
|
||||
'subscription.'),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
abstract class PhortuneSubscriptionImplementation {
|
||||
|
||||
abstract public function loadImplementationsForRefs(
|
||||
PhabricatorUser $viewer,
|
||||
array $refs);
|
||||
|
||||
abstract public function getRef();
|
||||
abstract public function getName(PhortuneSubscription $subscription);
|
||||
|
||||
protected function getContentSource() {
|
||||
return PhabricatorContentSource::newForSource(
|
||||
PhabricatorContentSource::SOURCE_PHORTUNE,
|
||||
array());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
final class PhortuneSubscriptionTableView extends AphrontView {
|
||||
|
||||
private $subscriptions;
|
||||
private $handles;
|
||||
|
||||
public function setHandles(array $handles) {
|
||||
$this->handles = $handles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHandles() {
|
||||
return $this->handles;
|
||||
}
|
||||
|
||||
public function setSubscriptions(array $subscriptions) {
|
||||
$this->subscriptions = $subscriptions;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSubscriptions() {
|
||||
return $this->subscriptions;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$subscriptions = $this->getSubscriptions();
|
||||
$handles = $this->getHandles();
|
||||
$viewer = $this->getUser();
|
||||
|
||||
$rows = array();
|
||||
$rowc = array();
|
||||
foreach ($subscriptions as $subscription) {
|
||||
$subscription_link = $handles[$subscription->getPHID()]->renderLink();
|
||||
$rows[] = array(
|
||||
$subscription->getID(),
|
||||
phabricator_datetime($subscription->getDateCreated(), $viewer),
|
||||
);
|
||||
}
|
||||
|
||||
$table = id(new AphrontTableView($rows))
|
||||
->setHeaders(
|
||||
array(
|
||||
pht('ID'),
|
||||
pht('Created'),
|
||||
))
|
||||
->setColumnClasses(
|
||||
array(
|
||||
'',
|
||||
'right',
|
||||
));
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue