Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13983833
D11482.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
26 KB
Referenced Files
None
Subscribers
None
D11482.diff
View Options
diff --git a/resources/sql/autopatches/20150124.subs.1.sql b/resources/sql/autopatches/20150124.subs.1.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20150124.subs.1.sql
@@ -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};
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2804,6 +2804,13 @@
'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 @@
'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',
diff --git a/src/applications/phortune/application/PhabricatorPhortuneApplication.php b/src/applications/phortune/application/PhabricatorPhortuneApplication.php
--- a/src/applications/phortune/application/PhabricatorPhortuneApplication.php
+++ b/src/applications/phortune/application/PhabricatorPhortuneApplication.php
@@ -45,6 +45,8 @@
),
'order/(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhortuneCartListController',
+ 'subscription/(?:query/(?P<queryKey>[^/]+)/)?'
+ => 'PhortuneSubscriptionListController',
'charge/(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhortuneChargeListController',
),
@@ -77,8 +79,10 @@
'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',
),
),
diff --git a/src/applications/phortune/controller/PhortuneAccountViewController.php b/src/applications/phortune/controller/PhortuneAccountViewController.php
--- a/src/applications/phortune/controller/PhortuneAccountViewController.php
+++ b/src/applications/phortune/controller/PhortuneAccountViewController.php
@@ -70,6 +70,8 @@
$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 @@
$payment_methods,
$purchase_history,
$charge_history,
+ $subscriptions,
$timeline,
),
array(
@@ -259,6 +262,39 @@
->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();
diff --git a/src/applications/phortune/controller/PhortuneMerchantViewController.php b/src/applications/phortune/controller/PhortuneMerchantViewController.php
--- a/src/applications/phortune/controller/PhortuneMerchantViewController.php
+++ b/src/applications/phortune/controller/PhortuneMerchantViewController.php
@@ -186,6 +186,14 @@
->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;
}
diff --git a/src/applications/phortune/controller/PhortuneSubscriptionListController.php b/src/applications/phortune/controller/PhortuneSubscriptionListController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/controller/PhortuneSubscriptionListController.php
@@ -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;
+ }
+
+}
diff --git a/src/applications/phortune/phid/PhortuneSubscriptionPHIDType.php b/src/applications/phortune/phid/PhortuneSubscriptionPHIDType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/phid/PhortuneSubscriptionPHIDType.php
@@ -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.
+
+ }
+ }
+
+}
diff --git a/src/applications/phortune/query/PhortuneSubscriptionQuery.php b/src/applications/phortune/query/PhortuneSubscriptionQuery.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/query/PhortuneSubscriptionQuery.php
@@ -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';
+ }
+
+}
diff --git a/src/applications/phortune/query/PhortuneSubscriptionSearchEngine.php b/src/applications/phortune/query/PhortuneSubscriptionSearchEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/query/PhortuneSubscriptionSearchEngine.php
@@ -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);
+ }
+}
diff --git a/src/applications/phortune/storage/PhortuneSubscription.php b/src/applications/phortune/storage/PhortuneSubscription.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/storage/PhortuneSubscription.php
@@ -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.'),
+ );
+ }
+}
diff --git a/src/applications/phortune/subscription/PhortuneSubscriptionImplementation.php b/src/applications/phortune/subscription/PhortuneSubscriptionImplementation.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/subscription/PhortuneSubscriptionImplementation.php
@@ -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());
+ }
+
+}
diff --git a/src/applications/phortune/view/PhortuneSubscriptionTableView.php b/src/applications/phortune/view/PhortuneSubscriptionTableView.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/view/PhortuneSubscriptionTableView.php
@@ -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;
+ }
+
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Oct 21, 9:01 AM (4 w, 11 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6737426
Default Alt Text
D11482.diff (26 KB)
Attached To
Mode
D11482: Add boilerplate scaffolding for Phortune subscriptions
Attached
Detach File
Event Timeline
Log In to Comment