Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14830699
D10486.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
30 KB
Referenced Files
None
Subscribers
None
D10486.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Thu, Jan 30, 10:17 PM (3 h, 40 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7073415
Default Alt Text
D10486.diff (30 KB)
Attached To
Mode
D10486: Allow users to back initiatives in Fund
Attached
Detach File
Event Timeline
Log In to Comment