Page MenuHomePhabricator

D10486.id25206.diff
No OneTemporary

D10486.id25206.diff

diff --git a/resources/sql/autopatches/20140911.fund.4.backer.sql b/resources/sql/autopatches/20140911.fund.4.backer.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20140911.fund.4.backer.sql
@@ -0,0 +1,14 @@
+CREATE TABLE {$NAMESPACE}_fund.fund_backer (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ phid VARCHAR(64) NOT NULL COLLATE utf8_bin,
+ initiativePHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
+ backerPHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
+ status VARCHAR(32) NOT NULL COLLATE utf8_bin,
+ amountInCents INT UNSIGNED NOT NULL,
+ properties LONGTEXT NOT NULL COLLATE utf8_bin,
+ dateCreated INT UNSIGNED NOT NULL,
+ dateModified INT UNSIGNED NOT NULL,
+ UNIQUE KEY `key_phid` (phid),
+ KEY `key_initiative` (initiativePHID),
+ KEY `key_backer` (backerPHID)
+) ENGINE=InnoDB, COLLATE utf8_general_ci;
diff --git a/resources/sql/autopatches/20140911.fund.5.backxaction.sql b/resources/sql/autopatches/20140911.fund.5.backxaction.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20140911.fund.5.backxaction.sql
@@ -0,0 +1,19 @@
+CREATE TABLE {$NAMESPACE}_fund.fund_backertransaction (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ phid VARCHAR(64) COLLATE utf8_bin NOT NULL,
+ authorPHID VARCHAR(64) COLLATE utf8_bin NOT NULL,
+ objectPHID VARCHAR(64) COLLATE utf8_bin NOT NULL,
+ viewPolicy VARCHAR(64) COLLATE utf8_bin NOT NULL,
+ editPolicy VARCHAR(64) COLLATE utf8_bin NOT NULL,
+ commentPHID VARCHAR(64) COLLATE utf8_bin DEFAULT NULL,
+ commentVersion INT UNSIGNED NOT NULL,
+ transactionType VARCHAR(32) COLLATE utf8_bin NOT NULL,
+ oldValue LONGTEXT COLLATE utf8_bin NOT NULL,
+ newValue LONGTEXT COLLATE utf8_bin NOT NULL,
+ contentSource LONGTEXT COLLATE utf8_bin NOT NULL,
+ metadata LONGTEXT COLLATE utf8_bin NOT NULL,
+ dateCreated INT UNSIGNED NOT NULL,
+ dateModified INT UNSIGNED NOT NULL,
+ UNIQUE KEY `key_phid` (`phid`),
+ KEY `key_object` (`objectPHID`)
+) ENGINE=InnoDB, COLLATE utf8_general_ci;
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
@@ -654,17 +654,20 @@
'FlagDeleteConduitAPIMethod' => 'applications/flag/conduit/FlagDeleteConduitAPIMethod.php',
'FlagEditConduitAPIMethod' => 'applications/flag/conduit/FlagEditConduitAPIMethod.php',
'FlagQueryConduitAPIMethod' => 'applications/flag/conduit/FlagQueryConduitAPIMethod.php',
- 'FundBacking' => 'applications/fund/storage/FundBacking.php',
- 'FundBackingEditor' => 'applications/fund/editor/FundBackingEditor.php',
- 'FundBackingPHIDType' => 'applications/fund/phid/FundBackingPHIDType.php',
- 'FundBackingQuery' => 'applications/fund/query/FundBackingQuery.php',
- 'FundBackingTransaction' => 'applications/fund/storage/FundBackingTransaction.php',
- 'FundBackingTransactionQuery' => 'applications/fund/query/FundBackingTransactionQuery.php',
+ 'FundBacker' => 'applications/fund/storage/FundBacker.php',
+ 'FundBackerEditor' => 'applications/fund/editor/FundBackerEditor.php',
+ 'FundBackerListController' => 'applications/fund/controller/FundBackerListController.php',
+ 'FundBackerPHIDType' => 'applications/fund/phid/FundBackerPHIDType.php',
+ 'FundBackerQuery' => 'applications/fund/query/FundBackerQuery.php',
+ 'FundBackerSearchEngine' => 'applications/fund/query/FundBackerSearchEngine.php',
+ 'FundBackerTransaction' => 'applications/fund/storage/FundBackerTransaction.php',
+ 'FundBackerTransactionQuery' => 'applications/fund/query/FundBackerTransactionQuery.php',
'FundController' => 'applications/fund/controller/FundController.php',
'FundCreateInitiativesCapability' => 'applications/fund/capability/FundCreateInitiativesCapability.php',
'FundDAO' => 'applications/fund/storage/FundDAO.php',
'FundDefaultViewCapability' => 'applications/fund/capability/FundDefaultViewCapability.php',
'FundInitiative' => 'applications/fund/storage/FundInitiative.php',
+ 'FundInitiativeBackController' => 'applications/fund/controller/FundInitiativeBackController.php',
'FundInitiativeCloseController' => 'applications/fund/controller/FundInitiativeCloseController.php',
'FundInitiativeEditController' => 'applications/fund/controller/FundInitiativeEditController.php',
'FundInitiativeEditor' => 'applications/fund/editor/FundInitiativeEditor.php',
@@ -3445,16 +3448,18 @@
'FlagDeleteConduitAPIMethod' => 'FlagConduitAPIMethod',
'FlagEditConduitAPIMethod' => 'FlagConduitAPIMethod',
'FlagQueryConduitAPIMethod' => 'FlagConduitAPIMethod',
- 'FundBacking' => array(
+ 'FundBacker' => array(
'FundDAO',
'PhabricatorPolicyInterface',
'PhabricatorApplicationTransactionInterface',
),
- 'FundBackingEditor' => 'PhabricatorApplicationTransactionEditor',
- 'FundBackingPHIDType' => 'PhabricatorPHIDType',
- 'FundBackingQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
- 'FundBackingTransaction' => 'PhabricatorApplicationTransaction',
- 'FundBackingTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
+ 'FundBackerEditor' => 'PhabricatorApplicationTransactionEditor',
+ 'FundBackerListController' => 'FundController',
+ 'FundBackerPHIDType' => 'PhabricatorPHIDType',
+ 'FundBackerQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'FundBackerSearchEngine' => 'PhabricatorApplicationSearchEngine',
+ 'FundBackerTransaction' => 'PhabricatorApplicationTransaction',
+ 'FundBackerTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'FundController' => 'PhabricatorController',
'FundCreateInitiativesCapability' => 'PhabricatorPolicyCapability',
'FundDAO' => 'PhabricatorLiskDAO',
@@ -3470,6 +3475,7 @@
'PhabricatorTokenReceiverInterface',
'PhabricatorDestructibleInterface',
),
+ 'FundInitiativeBackController' => 'FundController',
'FundInitiativeCloseController' => 'FundController',
'FundInitiativeEditController' => 'FundController',
'FundInitiativeEditor' => 'PhabricatorApplicationTransactionEditor',
diff --git a/src/applications/fund/application/PhabricatorFundApplication.php b/src/applications/fund/application/PhabricatorFundApplication.php
--- a/src/applications/fund/application/PhabricatorFundApplication.php
+++ b/src/applications/fund/application/PhabricatorFundApplication.php
@@ -42,8 +42,11 @@
'/fund/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'FundInitiativeListController',
'create/' => 'FundInitiativeEditController',
- 'edit/(?:(?P<id>[^/]+)/)?' => 'FundInitiativeEditController',
- 'close/(?P<id>[^/]+)/' => 'FundInitiativeCloseController',
+ 'edit/(?:(?P<id>\d+)/)?' => 'FundInitiativeEditController',
+ 'close/(?P<id>\d+)/' => 'FundInitiativeCloseController',
+ 'back/(?P<id>\d+)/' => 'FundInitiativeBackController',
+ 'backers/(?:(?P<id>\d+)/)?(?:query/(?P<queryKey>[^/]+)/)?'
+ => 'FundBackerListController',
),
);
}
diff --git a/src/applications/fund/controller/FundBackerListController.php b/src/applications/fund/controller/FundBackerListController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/fund/controller/FundBackerListController.php
@@ -0,0 +1,78 @@
+<?php
+
+final class FundBackerListController
+ extends FundController {
+
+ private $id;
+ private $queryKey;
+ private $initiative;
+
+ public function willProcessRequest(array $data) {
+ $this->id = idx($data, 'id');
+ $this->queryKey = idx($data, 'queryKey');
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+
+ if ($this->id) {
+ $this->initiative = id(new FundInitiativeQuery())
+ ->setViewer($request->getUser())
+ ->withIDs(array($this->id))
+ ->executeOne();
+ if (!$this->initiative) {
+ return new Aphront404Response();
+ }
+ }
+
+ $controller = id(new PhabricatorApplicationSearchController($request))
+ ->setQueryKey($this->queryKey)
+ ->setSearchEngine($this->getEngine())
+ ->setNavigation($this->buildSideNavView());
+
+ return $this->delegateToController($controller);
+ }
+
+ public function buildSideNavView() {
+ $user = $this->getRequest()->getUser();
+
+ $nav = new AphrontSideNavFilterView();
+ $nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
+
+ $this->getEngine()->addNavigationItems($nav->getMenu());
+
+ $nav->selectFilter(null);
+
+ return $nav;
+ }
+
+ protected function buildApplicationCrumbs() {
+ $crumbs = parent::buildApplicationCrumbs();
+ $crumbs->addTextCrumb(
+ pht('Backers'),
+ $this->getApplicationURI('backers/'));
+
+ if ($this->initiative) {
+ $crumbs->addTextCrumb(
+ $this->initiative->getMonogram(),
+ '/'.$this->initiative->getMonogram());
+ }
+
+ return $crumbs;
+ }
+
+ private function getEngine() {
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+
+ $engine = id(new FundBackerSearchEngine())
+ ->setViewer($viewer);
+
+ if ($this->initiative) {
+ $engine->setInitiative($this->initiative);
+ }
+
+ return $engine;
+ }
+
+}
diff --git a/src/applications/fund/controller/FundInitiativeBackController.php b/src/applications/fund/controller/FundInitiativeBackController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/fund/controller/FundInitiativeBackController.php
@@ -0,0 +1,100 @@
+<?php
+
+final class FundInitiativeBackController
+ extends FundController {
+
+ private $id;
+
+ public function willProcessRequest(array $data) {
+ $this->id = $data['id'];
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+
+ $initiative = id(new FundInitiativeQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($this->id))
+ ->executeOne();
+ if (!$initiative) {
+ return new Aphront404Response();
+ }
+
+ $initiative_uri = '/'.$initiative->getMonogram();
+
+ if ($initiative->isClosed()) {
+ return $this->newDialog()
+ ->setTitle(pht('Initiative Closed'))
+ ->appendParagraph(
+ pht('You can not back a closed initiative.'))
+ ->addCancelButton($initiative_uri);
+ }
+
+ $v_amount = null;
+ $e_amount = true;
+ $errors = array();
+ if ($request->isFormPost()) {
+ $v_amount = $request->getStr('amount');
+
+ if (!strlen($v_amount)) {
+ $errors[] = pht(
+ 'You must specify how much money you want to contribute to the '.
+ 'initiative.');
+ $e_amount = pht('Required');
+ } else {
+ try {
+ $currency = PhortuneCurrency::newFromUserInput(
+ $viewer,
+ $v_amount);
+ } catch (Exception $ex) {
+ $errors[] = $ex->getMessage();
+ $e_amount = pht('Invalid');
+ }
+ }
+
+ if (!$errors) {
+ $backer = FundBacker::initializeNewBacker($viewer)
+ ->setInitiativePHID($initiative->getPHID())
+ ->attachInitiative($initiative)
+ ->setAmountInCents($currency->getValue())
+ ->save();
+
+ // TODO: Here, we'd create a purchase and cart.
+
+ $xactions = array();
+
+ $xactions[] = id(new FundBackerTransaction())
+ ->setTransactionType(FundBackerTransaction::TYPE_STATUS)
+ ->setNewValue(FundBacker::STATUS_IN_CART);
+
+ $editor = id(new FundBackerEditor())
+ ->setActor($viewer)
+ ->setContentSourceFromRequest($request);
+
+ $editor->applyTransactions($backer, $xactions);
+
+ // TODO: Here, we'd ship the user into Phortune.
+
+ return id(new AphrontRedirectResponse())->setURI($initiative_uri);
+ }
+ }
+
+ $form = id(new AphrontFormView())
+ ->setUser($viewer)
+ ->appendChild(
+ id(new AphrontFormTextControl())
+ ->setName('amount')
+ ->setLabel(pht('Amount'))
+ ->setValue($v_amount)
+ ->setError($e_amount));
+
+ return $this->newDialog()
+ ->setTitle(pht('Back Initiative'))
+ ->setErrors($errors)
+ ->appendChild($form->buildLayoutView())
+ ->addCancelButton($initiative_uri)
+ ->addSubmitButton(pht('Continue'));
+ }
+
+}
diff --git a/src/applications/fund/controller/FundInitiativeCloseController.php b/src/applications/fund/controller/FundInitiativeCloseController.php
--- a/src/applications/fund/controller/FundInitiativeCloseController.php
+++ b/src/applications/fund/controller/FundInitiativeCloseController.php
@@ -55,7 +55,9 @@
if ($is_close) {
$title = pht('Close Initiative?');
- $body = pht('Really close this initiative?');
+ $body = pht(
+ 'Really close this initiative? Users will no longer be able to '.
+ 'back it.');
$button_text = pht('Close Initiative');
} else {
$title = pht('Reopen Initiative?');
diff --git a/src/applications/fund/controller/FundInitiativeListController.php b/src/applications/fund/controller/FundInitiativeListController.php
--- a/src/applications/fund/controller/FundInitiativeListController.php
+++ b/src/applications/fund/controller/FundInitiativeListController.php
@@ -28,6 +28,10 @@
id(new FundInitiativeSearchEngine())
->setViewer($user)
->addNavigationItems($nav->getMenu());
+
+ $nav->addLabel(pht('Backers'));
+ $nav->addFilter('backers/', pht('Find Backers'));
+
$nav->selectFilter(null);
return $nav;
diff --git a/src/applications/fund/controller/FundInitiativeViewController.php b/src/applications/fund/controller/FundInitiativeViewController.php
--- a/src/applications/fund/controller/FundInitiativeViewController.php
+++ b/src/applications/fund/controller/FundInitiativeViewController.php
@@ -143,6 +143,20 @@
->setWorkflow(true)
->setHref($this->getApplicationURI("/close/{$id}/")));
+ $view->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Back Initiative'))
+ ->setIcon('fa-money')
+ ->setDisabled($initiative->isClosed())
+ ->setWorkflow(true)
+ ->setHref($this->getApplicationURI("/back/{$id}/")));
+
+ $view->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('View Backers'))
+ ->setIcon('fa-bank')
+ ->setHref($this->getApplicationURI("/backers/{$id}/")));
+
return $view;
}
diff --git a/src/applications/fund/editor/FundBackerEditor.php b/src/applications/fund/editor/FundBackerEditor.php
new file mode 100644
--- /dev/null
+++ b/src/applications/fund/editor/FundBackerEditor.php
@@ -0,0 +1,69 @@
+<?php
+
+final class FundBackerEditor
+ extends PhabricatorApplicationTransactionEditor {
+
+ public function getEditorApplicationClass() {
+ return 'PhabricatorFundApplication';
+ }
+
+ public function getEditorObjectsDescription() {
+ return pht('Fund Backing');
+ }
+
+ public function getTransactionTypes() {
+ $types = parent::getTransactionTypes();
+ $types[] = FundBackerTransaction::TYPE_STATUS;
+
+ return $types;
+ }
+
+ protected function getCustomTransactionOldValue(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+ switch ($xaction->getTransactionType()) {
+ case FundBackerTransaction::TYPE_STATUS:
+ return $object->getStatus();
+ }
+
+ return parent::getCustomTransactionOldValue($object, $xaction);
+ }
+
+ protected function getCustomTransactionNewValue(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case FundBackerTransaction::TYPE_STATUS:
+ return $xaction->getNewValue();
+ }
+
+ return parent::getCustomTransactionNewValue($object, $xaction);
+ }
+
+ protected function applyCustomInternalTransaction(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case FundBackerTransaction::TYPE_STATUS:
+ $object->setStatus($xaction->getNewValue());
+ return;
+ }
+
+ return parent::applyCustomInternalTransaction($object, $xaction);
+ }
+
+ protected function applyCustomExternalTransaction(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case FundBackerTransaction::TYPE_STATUS:
+ return;
+ }
+
+ return parent::applyCustomExternalTransaction($object, $xaction);
+ }
+
+}
diff --git a/src/applications/fund/editor/FundBackingEditor.php b/src/applications/fund/editor/FundBackingEditor.php
deleted file mode 100644
--- a/src/applications/fund/editor/FundBackingEditor.php
+++ /dev/null
@@ -1,13 +0,0 @@
-<?php
-
-final class FundBackingEditor
- extends PhabricatorApplicationTransactionEditor {
-
- public function getEditorApplicationClass() {
- return 'PhabricatorFundApplication';
- }
-
- public function getEditorObjectsDescription() {
- return pht('Fund Backing');
- }
-}
diff --git a/src/applications/fund/phid/FundBackingPHIDType.php b/src/applications/fund/phid/FundBackerPHIDType.php
rename from src/applications/fund/phid/FundBackingPHIDType.php
rename to src/applications/fund/phid/FundBackerPHIDType.php
--- a/src/applications/fund/phid/FundBackingPHIDType.php
+++ b/src/applications/fund/phid/FundBackerPHIDType.php
@@ -1,6 +1,6 @@
<?php
-final class FundBackingPHIDType extends PhabricatorPHIDType {
+final class FundBackerPHIDType extends PhabricatorPHIDType {
const TYPECONST = 'FBAK';
diff --git a/src/applications/fund/query/FundBackerQuery.php b/src/applications/fund/query/FundBackerQuery.php
new file mode 100644
--- /dev/null
+++ b/src/applications/fund/query/FundBackerQuery.php
@@ -0,0 +1,105 @@
+<?php
+
+final class FundBackerQuery
+ extends PhabricatorCursorPagedPolicyAwareQuery {
+
+ private $ids;
+ private $phids;
+
+ private $initiativePHIDs;
+ private $backerPHIDs;
+
+ public function withIDs(array $ids) {
+ $this->ids = $ids;
+ return $this;
+ }
+
+ public function withPHIDs(array $phids) {
+ $this->phids = $phids;
+ return $this;
+ }
+
+ public function withInitiativePHIDs(array $phids) {
+ $this->initiativePHIDs = $phids;
+ return $this;
+ }
+
+ public function withBackerPHIDs(array $phids) {
+ $this->backerPHIDs = $phids;
+ return $this;
+ }
+
+ protected function loadPage() {
+ $table = new FundBacker();
+ $conn_r = $table->establishConnection('r');
+
+ $rows = queryfx_all(
+ $conn_r,
+ 'SELECT * FROM %T %Q %Q %Q',
+ $table->getTableName(),
+ $this->buildWhereClause($conn_r),
+ $this->buildOrderClause($conn_r),
+ $this->buildLimitClause($conn_r));
+
+ return $table->loadAllFromArray($rows);
+ }
+
+ protected function willFilterPage(array $backers) {
+ $initiative_phids = mpull($backers, 'getInitiativePHID');
+ $initiatives = id(new PhabricatorObjectQuery())
+ ->setParentQuery($this)
+ ->setViewer($this->getViewer())
+ ->withPHIDs($initiative_phids)
+ ->execute();
+ $initiatives = mpull($initiatives, null, 'getPHID');
+
+ foreach ($backers as $backer) {
+ $initiative_phid = $backer->getInitiativePHID();
+ $initiative = idx($initiatives, $initiative_phid);
+ $backer->attachInitiative($initiative);
+ }
+
+ return $backers;
+ }
+
+ private function buildWhereClause(AphrontDatabaseConnection $conn_r) {
+ $where = array();
+
+ $where[] = $this->buildPagingClause($conn_r);
+
+ if ($this->ids !== null) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'id IN (%Ld)',
+ $this->ids);
+ }
+
+ if ($this->phids !== null) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'phid IN (%Ls)',
+ $this->phids);
+ }
+
+ if ($this->initiativePHIDs !== null) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'initiativePHID IN (%Ls)',
+ $this->initiativePHIDs);
+ }
+
+ if ($this->backerPHIDs !== null) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'backerPHID IN (%Ls)',
+ $this->backerPHIDs);
+ }
+
+ return $this->formatWhereClause($where);
+ }
+
+ public function getQueryApplicationClass() {
+ return 'PhabricatorFundApplication';
+ }
+
+}
diff --git a/src/applications/fund/query/FundBackerSearchEngine.php b/src/applications/fund/query/FundBackerSearchEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/fund/query/FundBackerSearchEngine.php
@@ -0,0 +1,153 @@
+<?php
+
+final class FundBackerSearchEngine
+ extends PhabricatorApplicationSearchEngine {
+
+ private $initiative;
+
+ public function setInitiative(FundInitiative $initiative) {
+ $this->initiative = $initiative;
+ return $this;
+ }
+
+ public function getInitiative() {
+ return $this->initiative;
+ }
+
+ public function getResultTypeDescription() {
+ return pht('Fund Backers');
+ }
+
+ public function getApplicationClassName() {
+ return 'PhabricatorFundApplication';
+ }
+
+ public function buildSavedQueryFromRequest(AphrontRequest $request) {
+ $saved = new PhabricatorSavedQuery();
+
+ $saved->setParameter(
+ 'backerPHIDs',
+ $this->readUsersFromRequest($request, 'backers'));
+
+ return $saved;
+ }
+
+ public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
+ $query = id(new FundBackerQuery());
+
+ if ($this->getInitiative()) {
+ $query->withInitiativePHIDs(
+ array(
+ $this->getInitiative()->getPHID(),
+ ));
+ }
+
+ $backer_phids = $saved->getParameter('backerPHIDs');
+ if ($backer_phids) {
+ $query->withBackerPHIDs($backer_phids);
+ }
+
+ return $query;
+ }
+
+ public function buildSearchForm(
+ AphrontFormView $form,
+ PhabricatorSavedQuery $saved) {
+
+
+ $backer_phids = $saved->getParameter('backerPHIDs', array());
+
+ $all_phids = array_mergev(
+ array(
+ $backer_phids,
+ ));
+
+ $handles = id(new PhabricatorHandleQuery())
+ ->setViewer($this->requireViewer())
+ ->withPHIDs($all_phids)
+ ->execute();
+
+ $form
+ ->appendChild(
+ id(new AphrontFormTokenizerControl())
+ ->setLabel(pht('Backers'))
+ ->setName('backers')
+ ->setDatasource(new PhabricatorPeopleDatasource())
+ ->setValue(array_select_keys($handles, $backer_phids)));
+ }
+
+ protected function getURI($path) {
+ if ($this->getInitiative()) {
+ return '/fund/backers/'.$this->getInitiative()->getID().'/'.$path;
+ } else {
+ return '/fund/backers/'.$path;
+ }
+ }
+
+ public function getBuiltinQueryNames() {
+ $names = array();
+ $names['all'] = pht('All Backers');
+
+ 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 $backers,
+ PhabricatorSavedQuery $query) {
+
+ $phids = array();
+ foreach ($backers as $backer) {
+ $phids[] = $backer->getBackerPHID();
+ $phids[] = $backer->getInitiativePHID();
+ }
+
+ return $phids;
+ }
+
+ protected function renderResultList(
+ array $backers,
+ PhabricatorSavedQuery $query,
+ array $handles) {
+ assert_instances_of($backers, 'FundBacker');
+
+ $viewer = $this->requireViewer();
+
+ $list = id(new PHUIObjectItemListView());
+ foreach ($backers as $backer) {
+ $backer_handle = $handles[$backer->getBackerPHID()];
+
+ $currency = PhortuneCurrency::newFromUSDCents(
+ $backer->getAmountInCents());
+
+ $header = pht(
+ '%s for %s',
+ $currency->formatForDisplay(),
+ $handles[$backer->getInitiativePHID()]->renderLink());
+
+ $item = id(new PHUIObjectItemView())
+ ->setHeader($header)
+ ->addIcon(
+ 'none',
+ phabricator_datetime($backer->getDateCreated(), $viewer))
+ ->addByline(pht('Backer: %s', $backer_handle->renderLink()));
+
+ $list->addItem($item);
+ }
+
+
+ return $list;
+ }
+
+}
diff --git a/src/applications/fund/query/FundBackingTransactionQuery.php b/src/applications/fund/query/FundBackerTransactionQuery.php
rename from src/applications/fund/query/FundBackingTransactionQuery.php
rename to src/applications/fund/query/FundBackerTransactionQuery.php
--- a/src/applications/fund/query/FundBackingTransactionQuery.php
+++ b/src/applications/fund/query/FundBackerTransactionQuery.php
@@ -1,10 +1,10 @@
<?php
-final class FundBackingTransactionQuery
+final class FundBackerTransactionQuery
extends PhabricatorApplicationTransactionQuery {
public function getTemplateApplicationTransaction() {
- return new FundBackingTransaction();
+ return new FundBackerTransaction();
}
}
diff --git a/src/applications/fund/query/FundBackingQuery.php b/src/applications/fund/query/FundBackingQuery.php
deleted file mode 100644
--- a/src/applications/fund/query/FundBackingQuery.php
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-
-final class FundBackingQuery
- extends PhabricatorCursorPagedPolicyAwareQuery {
-
- private $ids;
- private $phids;
-
- public function withIDs(array $ids) {
- $this->ids = $ids;
- return $this;
- }
-
- public function withPHIDs(array $phids) {
- $this->phids = $phids;
- return $this;
- }
-
- protected function loadPage() {
- $table = new FundBacking();
- $conn_r = $table->establishConnection('r');
-
- $rows = queryfx_all(
- $conn_r,
- 'SELECT * FROM %T %Q %Q %Q',
- $table->getTableName(),
- $this->buildWhereClause($conn_r),
- $this->buildOrderClause($conn_r),
- $this->buildLimitClause($conn_r));
-
- return $table->loadAllFromArray($rows);
- }
-
- private function buildWhereClause(AphrontDatabaseConnection $conn_r) {
- $where = array();
-
- $where[] = $this->buildPagingClause($conn_r);
-
- if ($this->ids !== null) {
- $where[] = qsprintf(
- $conn_r,
- 'id IN (%Ld)',
- $this->ids);
- }
-
- if ($this->phids !== null) {
- $where[] = qsprintf(
- $conn_r,
- 'phid IN (%Ls)',
- $this->phids);
- }
-
- return $this->formatWhereClause($where);
- }
-
- public function getQueryApplicationClass() {
- return 'PhabricatorFundApplication';
- }
-
-}
diff --git a/src/applications/fund/storage/FundBacking.php b/src/applications/fund/storage/FundBacker.php
rename from src/applications/fund/storage/FundBacking.php
rename to src/applications/fund/storage/FundBacker.php
--- a/src/applications/fund/storage/FundBacking.php
+++ b/src/applications/fund/storage/FundBacker.php
@@ -1,27 +1,43 @@
<?php
-final class FundBacking extends FundDAO
+final class FundBacker extends FundDAO
implements
PhabricatorPolicyInterface,
PhabricatorApplicationTransactionInterface {
protected $initiativePHID;
protected $backerPHID;
- protected $purchasePHID;
protected $amountInCents;
protected $status;
protected $properties = array();
private $initiative = self::ATTACHABLE;
+ const STATUS_NEW = 'new';
+ const STATUS_IN_CART = 'in-cart';
+
+ public static function initializeNewBacker(PhabricatorUser $actor) {
+ return id(new FundBacker())
+ ->setBackerPHID($actor->getPHID())
+ ->setStatus(self::STATUS_NEW);
+ }
+
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
+ self::CONFIG_SERIALIZATION => array(
+ 'properties' => self::SERIALIZATION_JSON,
+ ),
) + parent::getConfiguration();
}
public function generatePHID() {
- return PhabricatorPHID::generateNewPHID(FundBackingPHIDType::TYPECONST);
+ return PhabricatorPHID::generateNewPHID(FundBackerPHIDType::TYPECONST);
+ }
+
+ protected function didReadData() {
+ // The payment processing code is strict about types.
+ $this->amountInCents = (int)$this->amountInCents;
}
public function getProperty($key, $default = null) {
@@ -33,6 +49,15 @@
return $this;
}
+ public function getInitiative() {
+ return $this->assertAttached($this->initiative);
+ }
+
+ public function attachInitiative(FundInitiative $initiative = null) {
+ $this->initiative = $initiative;
+ return $this;
+ }
+
/* -( PhabricatorPolicyInterface )----------------------------------------- */
@@ -48,7 +73,7 @@
case PhabricatorPolicyCapability::CAN_VIEW:
// If we have the initiative, use the initiative's policy.
// Otherwise, return NOONE. This allows the backer to continue seeing
- // a backing even if they're no longer allowed to see the initiative.
+ // a backer even if they're no longer allowed to see the initiative.
$initiative = $this->getInitiative();
if ($initiative) {
@@ -71,7 +96,7 @@
public function getApplicationTransactionEditor() {
- return new FundBackingEditor();
+ return new FundBackerEditor();
}
public function getApplicationTransactionObject() {
@@ -79,7 +104,7 @@
}
public function getApplicationTransactionTemplate() {
- return new FundBackingTransaction();
+ return new FundBackerTransaction();
}
}
diff --git a/src/applications/fund/storage/FundBackingTransaction.php b/src/applications/fund/storage/FundBackerTransaction.php
rename from src/applications/fund/storage/FundBackingTransaction.php
rename to src/applications/fund/storage/FundBackerTransaction.php
--- a/src/applications/fund/storage/FundBackingTransaction.php
+++ b/src/applications/fund/storage/FundBackerTransaction.php
@@ -1,14 +1,16 @@
<?php
-final class FundBackingTransaction
+final class FundBackerTransaction
extends PhabricatorApplicationTransaction {
+ const TYPE_STATUS = 'fund:backer:status';
+
public function getApplicationName() {
return 'fund';
}
public function getApplicationTransactionType() {
- return FundBackingPHIDType::TYPECONST;
+ return FundBackerPHIDType::TYPECONST;
}
public function getApplicationTransactionCommentObject() {
diff --git a/src/applications/fund/storage/FundInitiative.php b/src/applications/fund/storage/FundInitiative.php
--- a/src/applications/fund/storage/FundInitiative.php
+++ b/src/applications/fund/storage/FundInitiative.php
@@ -93,11 +93,12 @@
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
- return false;
+ return ($viewer->getPHID() == $this->getOwnerPHID());
}
public function describeAutomaticCapability($capability) {
- return null;
+ return pht(
+ 'The owner of an initiative can always view and edit it.');
}

File Metadata

Mime Type
text/plain
Expires
May 20 2024, 3:28 PM (5 w, 1 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6302387
Default Alt Text
D10486.id25206.diff (30 KB)

Event Timeline