mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-27 07:50:57 +01:00
Allow users to back initiatives in Fund
Summary: Ref T5835. This is still completely made up (no payment integration), but you can "back" an initiative, type a number in the box, and generate a database row. You can then seach for backers and things you've backed and such. Notable changes: - Renamed "FundBacking" to "FundBacker". The former name was sort of because you can back things multiple times, but stuff like `$backings` was just too weird. - I think that's it? Test Plan: - Backed an initiative. - Viewed that I became a backer. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T5835 Differential Revision: https://secure.phabricator.com/D10486
This commit is contained in:
parent
e4f399b9fa
commit
09fb5667cc
19 changed files with 623 additions and 101 deletions
14
resources/sql/autopatches/20140911.fund.4.backer.sql
Normal file
14
resources/sql/autopatches/20140911.fund.4.backer.sql
Normal file
|
@ -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;
|
19
resources/sql/autopatches/20140911.fund.5.backxaction.sql
Normal file
19
resources/sql/autopatches/20140911.fund.5.backxaction.sql
Normal file
|
@ -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;
|
|
@ -654,17 +654,20 @@ phutil_register_library_map(array(
|
|||
'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 @@ phutil_register_library_map(array(
|
|||
'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 @@ phutil_register_library_map(array(
|
|||
'PhabricatorTokenReceiverInterface',
|
||||
'PhabricatorDestructibleInterface',
|
||||
),
|
||||
'FundInitiativeBackController' => 'FundController',
|
||||
'FundInitiativeCloseController' => 'FundController',
|
||||
'FundInitiativeEditController' => 'FundController',
|
||||
'FundInitiativeEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
|
|
|
@ -42,8 +42,11 @@ final class PhabricatorFundApplication extends PhabricatorApplication {
|
|||
'/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',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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'));
|
||||
}
|
||||
|
||||
}
|
|
@ -55,7 +55,9 @@ final class FundInitiativeCloseController
|
|||
|
||||
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?');
|
||||
|
|
|
@ -28,6 +28,10 @@ final class FundInitiativeListController
|
|||
id(new FundInitiativeSearchEngine())
|
||||
->setViewer($user)
|
||||
->addNavigationItems($nav->getMenu());
|
||||
|
||||
$nav->addLabel(pht('Backers'));
|
||||
$nav->addFilter('backers/', pht('Find Backers'));
|
||||
|
||||
$nav->selectFilter(null);
|
||||
|
||||
return $nav;
|
||||
|
|
|
@ -143,6 +143,20 @@ final class FundInitiativeViewController
|
|||
->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;
|
||||
}
|
||||
|
||||
|
|
69
src/applications/fund/editor/FundBackerEditor.php
Normal file
69
src/applications/fund/editor/FundBackerEditor.php
Normal file
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class FundBackingEditor
|
||||
extends PhabricatorApplicationTransactionEditor {
|
||||
|
||||
public function getEditorApplicationClass() {
|
||||
return 'PhabricatorFundApplication';
|
||||
}
|
||||
|
||||
public function getEditorObjectsDescription() {
|
||||
return pht('Fund Backing');
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
final class FundBackingPHIDType extends PhabricatorPHIDType {
|
||||
final class FundBackerPHIDType extends PhabricatorPHIDType {
|
||||
|
||||
const TYPECONST = 'FBAK';
|
||||
|
105
src/applications/fund/query/FundBackerQuery.php
Normal file
105
src/applications/fund/query/FundBackerQuery.php
Normal file
|
@ -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';
|
||||
}
|
||||
|
||||
}
|
153
src/applications/fund/query/FundBackerSearchEngine.php
Normal file
153
src/applications/fund/query/FundBackerSearchEngine.php
Normal file
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
<?php
|
||||
|
||||
final class FundBackingTransactionQuery
|
||||
final class FundBackerTransactionQuery
|
||||
extends PhabricatorApplicationTransactionQuery {
|
||||
|
||||
public function getTemplateApplicationTransaction() {
|
||||
return new FundBackingTransaction();
|
||||
return new FundBackerTransaction();
|
||||
}
|
||||
|
||||
}
|
|
@ -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';
|
||||
}
|
||||
|
||||
}
|
|
@ -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 @@ final class FundBacking extends FundDAO
|
|||
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 @@ final class FundBacking extends FundDAO
|
|||
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 @@ final class FundBacking extends FundDAO
|
|||
|
||||
|
||||
public function getApplicationTransactionEditor() {
|
||||
return new FundBackingEditor();
|
||||
return new FundBackerEditor();
|
||||
}
|
||||
|
||||
public function getApplicationTransactionObject() {
|
||||
|
@ -79,7 +104,7 @@ final class FundBacking extends FundDAO
|
|||
}
|
||||
|
||||
public function getApplicationTransactionTemplate() {
|
||||
return new FundBackingTransaction();
|
||||
return new FundBackerTransaction();
|
||||
}
|
||||
|
||||
}
|
|
@ -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() {
|
|
@ -93,11 +93,12 @@ final class FundInitiative extends FundDAO
|
|||
}
|
||||
|
||||
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.');
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue