1
0
Fork 0
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:
epriestley 2014-09-12 06:31:11 -07:00
parent e4f399b9fa
commit 09fb5667cc
19 changed files with 623 additions and 101 deletions

View 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;

View 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;

View file

@ -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',

View file

@ -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',
),
);
}

View file

@ -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;
}
}

View file

@ -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'));
}
}

View file

@ -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?');

View file

@ -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;

View file

@ -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;
}

View 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);
}
}

View file

@ -1,13 +0,0 @@
<?php
final class FundBackingEditor
extends PhabricatorApplicationTransactionEditor {
public function getEditorApplicationClass() {
return 'PhabricatorFundApplication';
}
public function getEditorObjectsDescription() {
return pht('Fund Backing');
}
}

View file

@ -1,6 +1,6 @@
<?php
final class FundBackingPHIDType extends PhabricatorPHIDType {
final class FundBackerPHIDType extends PhabricatorPHIDType {
const TYPECONST = 'FBAK';

View 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';
}
}

View 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;
}
}

View file

@ -1,10 +1,10 @@
<?php
final class FundBackingTransactionQuery
final class FundBackerTransactionQuery
extends PhabricatorApplicationTransactionQuery {
public function getTemplateApplicationTransaction() {
return new FundBackingTransaction();
return new FundBackerTransaction();
}
}

View file

@ -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';
}
}

View file

@ -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();
}
}

View file

@ -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() {

View file

@ -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.');
}