mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-22 21:40:55 +01:00
Scaffolding for Fund
Summary: Ref T5835. This is all pretty boilerplate, and does not interact with Phortune at all yet. You can create "Initiatives", which have a title and description, and support most of the expected infrastructure (policies, transactions, mentions, edges, appsearch, remakrup, etc). Only notable decisions: - Initiatives have an explicit owner. I think it's good to have a single clearly-responsible user behind an initiative. - I think that's it? Test Plan: - Created an initiative. - Edited an initiative. - Changed application policy defaults. - Searched for initiatives. - Subscribed to an initiative. - Opened/closed an initiative. - Used `I123` and `{I123}` in remarkup. - Destroyed an initiative. Reviewers: chad, btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T5835 Differential Revision: https://secure.phabricator.com/D10481
This commit is contained in:
parent
cae59d8345
commit
e4f399b9fa
28 changed files with 1722 additions and 0 deletions
resources/sql/autopatches
src
__phutil_library_map__.php
applications/fund
application
capability
controller
FundController.phpFundInitiativeCloseController.phpFundInitiativeEditController.phpFundInitiativeListController.phpFundInitiativeViewController.php
editor
phid
query
FundBackingQuery.phpFundBackingTransactionQuery.phpFundInitiativeQuery.phpFundInitiativeSearchEngine.phpFundInitiativeTransactionQuery.php
remarkup
storage
infrastructure/storage/patch
15
resources/sql/autopatches/20140911.fund.1.initiative.sql
Normal file
15
resources/sql/autopatches/20140911.fund.1.initiative.sql
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
CREATE TABLE {$NAMESPACE}_fund.fund_initiative (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
phid VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
ownerPHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||||
|
description LONGTEXT NOT NULL,
|
||||||
|
viewPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||||
|
editPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||||
|
status VARCHAR(32) NOT NULL COLLATE utf8_bin,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
UNIQUE KEY `key_phid` (phid),
|
||||||
|
KEY `key_status` (status),
|
||||||
|
KEY `key_owner` (ownerPHID)
|
||||||
|
) ENGINE=InnoDB, COLLATE utf8_general_ci;
|
19
resources/sql/autopatches/20140911.fund.2.xaction.sql
Normal file
19
resources/sql/autopatches/20140911.fund.2.xaction.sql
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
CREATE TABLE {$NAMESPACE}_fund.fund_initiativetransaction (
|
||||||
|
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;
|
15
resources/sql/autopatches/20140911.fund.3.edge.sql
Normal file
15
resources/sql/autopatches/20140911.fund.3.edge.sql
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
CREATE TABLE {$NAMESPACE}_fund.edge (
|
||||||
|
src VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||||
|
type VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||||
|
dst VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
seq INT UNSIGNED NOT NULL,
|
||||||
|
dataID INT UNSIGNED,
|
||||||
|
PRIMARY KEY (src, type, dst),
|
||||||
|
KEY (src, type, dateCreated, seq)
|
||||||
|
) ENGINE=InnoDB, COLLATE utf8_general_ci;
|
||||||
|
|
||||||
|
CREATE TABLE {$NAMESPACE}_fund.edgedata (
|
||||||
|
id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
data LONGTEXT NOT NULL COLLATE utf8_bin
|
||||||
|
) ENGINE=InnoDB, COLLATE utf8_general_ci;
|
|
@ -654,6 +654,28 @@ phutil_register_library_map(array(
|
||||||
'FlagDeleteConduitAPIMethod' => 'applications/flag/conduit/FlagDeleteConduitAPIMethod.php',
|
'FlagDeleteConduitAPIMethod' => 'applications/flag/conduit/FlagDeleteConduitAPIMethod.php',
|
||||||
'FlagEditConduitAPIMethod' => 'applications/flag/conduit/FlagEditConduitAPIMethod.php',
|
'FlagEditConduitAPIMethod' => 'applications/flag/conduit/FlagEditConduitAPIMethod.php',
|
||||||
'FlagQueryConduitAPIMethod' => 'applications/flag/conduit/FlagQueryConduitAPIMethod.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',
|
||||||
|
'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',
|
||||||
|
'FundInitiativeCloseController' => 'applications/fund/controller/FundInitiativeCloseController.php',
|
||||||
|
'FundInitiativeEditController' => 'applications/fund/controller/FundInitiativeEditController.php',
|
||||||
|
'FundInitiativeEditor' => 'applications/fund/editor/FundInitiativeEditor.php',
|
||||||
|
'FundInitiativeListController' => 'applications/fund/controller/FundInitiativeListController.php',
|
||||||
|
'FundInitiativePHIDType' => 'applications/fund/phid/FundInitiativePHIDType.php',
|
||||||
|
'FundInitiativeQuery' => 'applications/fund/query/FundInitiativeQuery.php',
|
||||||
|
'FundInitiativeRemarkupRule' => 'applications/fund/remarkup/FundInitiativeRemarkupRule.php',
|
||||||
|
'FundInitiativeSearchEngine' => 'applications/fund/query/FundInitiativeSearchEngine.php',
|
||||||
|
'FundInitiativeTransaction' => 'applications/fund/storage/FundInitiativeTransaction.php',
|
||||||
|
'FundInitiativeTransactionQuery' => 'applications/fund/query/FundInitiativeTransactionQuery.php',
|
||||||
|
'FundInitiativeViewController' => 'applications/fund/controller/FundInitiativeViewController.php',
|
||||||
'HarbormasterBuild' => 'applications/harbormaster/storage/build/HarbormasterBuild.php',
|
'HarbormasterBuild' => 'applications/harbormaster/storage/build/HarbormasterBuild.php',
|
||||||
'HarbormasterBuildAbortedException' => 'applications/harbormaster/exception/HarbormasterBuildAbortedException.php',
|
'HarbormasterBuildAbortedException' => 'applications/harbormaster/exception/HarbormasterBuildAbortedException.php',
|
||||||
'HarbormasterBuildActionController' => 'applications/harbormaster/controller/HarbormasterBuildActionController.php',
|
'HarbormasterBuildActionController' => 'applications/harbormaster/controller/HarbormasterBuildActionController.php',
|
||||||
|
@ -1600,6 +1622,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorFlagsApplication' => 'applications/flag/application/PhabricatorFlagsApplication.php',
|
'PhabricatorFlagsApplication' => 'applications/flag/application/PhabricatorFlagsApplication.php',
|
||||||
'PhabricatorFlagsUIEventListener' => 'applications/flag/events/PhabricatorFlagsUIEventListener.php',
|
'PhabricatorFlagsUIEventListener' => 'applications/flag/events/PhabricatorFlagsUIEventListener.php',
|
||||||
'PhabricatorFormExample' => 'applications/uiexample/examples/PhabricatorFormExample.php',
|
'PhabricatorFormExample' => 'applications/uiexample/examples/PhabricatorFormExample.php',
|
||||||
|
'PhabricatorFundApplication' => 'applications/fund/application/PhabricatorFundApplication.php',
|
||||||
'PhabricatorGarbageCollector' => 'infrastructure/daemon/garbagecollector/PhabricatorGarbageCollector.php',
|
'PhabricatorGarbageCollector' => 'infrastructure/daemon/garbagecollector/PhabricatorGarbageCollector.php',
|
||||||
'PhabricatorGarbageCollectorConfigOptions' => 'applications/config/option/PhabricatorGarbageCollectorConfigOptions.php',
|
'PhabricatorGarbageCollectorConfigOptions' => 'applications/config/option/PhabricatorGarbageCollectorConfigOptions.php',
|
||||||
'PhabricatorGarbageCollectorDaemon' => 'infrastructure/daemon/garbagecollector/PhabricatorGarbageCollectorDaemon.php',
|
'PhabricatorGarbageCollectorDaemon' => 'infrastructure/daemon/garbagecollector/PhabricatorGarbageCollectorDaemon.php',
|
||||||
|
@ -3422,6 +3445,42 @@ phutil_register_library_map(array(
|
||||||
'FlagDeleteConduitAPIMethod' => 'FlagConduitAPIMethod',
|
'FlagDeleteConduitAPIMethod' => 'FlagConduitAPIMethod',
|
||||||
'FlagEditConduitAPIMethod' => 'FlagConduitAPIMethod',
|
'FlagEditConduitAPIMethod' => 'FlagConduitAPIMethod',
|
||||||
'FlagQueryConduitAPIMethod' => 'FlagConduitAPIMethod',
|
'FlagQueryConduitAPIMethod' => 'FlagConduitAPIMethod',
|
||||||
|
'FundBacking' => array(
|
||||||
|
'FundDAO',
|
||||||
|
'PhabricatorPolicyInterface',
|
||||||
|
'PhabricatorApplicationTransactionInterface',
|
||||||
|
),
|
||||||
|
'FundBackingEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||||
|
'FundBackingPHIDType' => 'PhabricatorPHIDType',
|
||||||
|
'FundBackingQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'FundBackingTransaction' => 'PhabricatorApplicationTransaction',
|
||||||
|
'FundBackingTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
|
'FundController' => 'PhabricatorController',
|
||||||
|
'FundCreateInitiativesCapability' => 'PhabricatorPolicyCapability',
|
||||||
|
'FundDAO' => 'PhabricatorLiskDAO',
|
||||||
|
'FundDefaultViewCapability' => 'PhabricatorPolicyCapability',
|
||||||
|
'FundInitiative' => array(
|
||||||
|
'FundDAO',
|
||||||
|
'PhabricatorPolicyInterface',
|
||||||
|
'PhabricatorProjectInterface',
|
||||||
|
'PhabricatorApplicationTransactionInterface',
|
||||||
|
'PhabricatorSubscribableInterface',
|
||||||
|
'PhabricatorMentionableInterface',
|
||||||
|
'PhabricatorFlaggableInterface',
|
||||||
|
'PhabricatorTokenReceiverInterface',
|
||||||
|
'PhabricatorDestructibleInterface',
|
||||||
|
),
|
||||||
|
'FundInitiativeCloseController' => 'FundController',
|
||||||
|
'FundInitiativeEditController' => 'FundController',
|
||||||
|
'FundInitiativeEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||||
|
'FundInitiativeListController' => 'FundController',
|
||||||
|
'FundInitiativePHIDType' => 'PhabricatorPHIDType',
|
||||||
|
'FundInitiativeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'FundInitiativeRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
||||||
|
'FundInitiativeSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
|
'FundInitiativeTransaction' => 'PhabricatorApplicationTransaction',
|
||||||
|
'FundInitiativeTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
|
'FundInitiativeViewController' => 'FundController',
|
||||||
'HarbormasterBuild' => array(
|
'HarbormasterBuild' => array(
|
||||||
'HarbormasterDAO',
|
'HarbormasterDAO',
|
||||||
'PhabricatorPolicyInterface',
|
'PhabricatorPolicyInterface',
|
||||||
|
@ -4465,6 +4524,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorFlagsApplication' => 'PhabricatorApplication',
|
'PhabricatorFlagsApplication' => 'PhabricatorApplication',
|
||||||
'PhabricatorFlagsUIEventListener' => 'PhabricatorEventListener',
|
'PhabricatorFlagsUIEventListener' => 'PhabricatorEventListener',
|
||||||
'PhabricatorFormExample' => 'PhabricatorUIExample',
|
'PhabricatorFormExample' => 'PhabricatorUIExample',
|
||||||
|
'PhabricatorFundApplication' => 'PhabricatorApplication',
|
||||||
'PhabricatorGarbageCollector' => 'Phobject',
|
'PhabricatorGarbageCollector' => 'Phobject',
|
||||||
'PhabricatorGarbageCollectorConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
'PhabricatorGarbageCollectorConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||||
'PhabricatorGarbageCollectorDaemon' => 'PhabricatorDaemon',
|
'PhabricatorGarbageCollectorDaemon' => 'PhabricatorDaemon',
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorFundApplication extends PhabricatorApplication {
|
||||||
|
|
||||||
|
public function getName() {
|
||||||
|
return pht('Fund');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBaseURI() {
|
||||||
|
return '/fund/';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getShortDescription() {
|
||||||
|
return pht('Donate');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIconName() {
|
||||||
|
return 'phund';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitleGlyph() {
|
||||||
|
return "\xE2\x99\xA5";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationGroup() {
|
||||||
|
return self::GROUP_UTILITIES;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isBeta() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRemarkupRules() {
|
||||||
|
return array(
|
||||||
|
new FundInitiativeRemarkupRule(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRoutes() {
|
||||||
|
return array(
|
||||||
|
'/I(?P<id>[1-9]\d*)' => 'FundInitiativeViewController',
|
||||||
|
'/fund/' => array(
|
||||||
|
'(?:query/(?P<queryKey>[^/]+)/)?' => 'FundInitiativeListController',
|
||||||
|
'create/' => 'FundInitiativeEditController',
|
||||||
|
'edit/(?:(?P<id>[^/]+)/)?' => 'FundInitiativeEditController',
|
||||||
|
'close/(?P<id>[^/]+)/' => 'FundInitiativeCloseController',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCustomCapabilities() {
|
||||||
|
return array(
|
||||||
|
FundDefaultViewCapability::CAPABILITY => array(
|
||||||
|
'caption' => pht('Default view policy for newly created initiatives.'),
|
||||||
|
),
|
||||||
|
FundCreateInitiativesCapability::CAPABILITY => array(
|
||||||
|
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundCreateInitiativesCapability
|
||||||
|
extends PhabricatorPolicyCapability {
|
||||||
|
|
||||||
|
const CAPABILITY = 'fund.create';
|
||||||
|
|
||||||
|
public function getCapabilityName() {
|
||||||
|
return pht('Can Create Initiatives');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function describeCapabilityRejection() {
|
||||||
|
return pht('You do not have permission to create Fund initiatives.');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundDefaultViewCapability extends PhabricatorPolicyCapability {
|
||||||
|
|
||||||
|
const CAPABILITY = 'fund.default.view';
|
||||||
|
|
||||||
|
public function getCapabilityName() {
|
||||||
|
return pht('Default View Policy');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldAllowPublicPolicySetting() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
3
src/applications/fund/controller/FundController.php
Normal file
3
src/applications/fund/controller/FundController.php
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class FundController extends PhabricatorController {}
|
|
@ -0,0 +1,73 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundInitiativeCloseController
|
||||||
|
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))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
|
->executeOne();
|
||||||
|
if (!$initiative) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$initiative_uri = '/'.$initiative->getMonogram();
|
||||||
|
|
||||||
|
$is_close = !$initiative->isClosed();
|
||||||
|
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
$type_status = FundInitiativeTransaction::TYPE_STATUS;
|
||||||
|
|
||||||
|
if ($is_close) {
|
||||||
|
$new_status = FundInitiative::STATUS_CLOSED;
|
||||||
|
} else {
|
||||||
|
$new_status = FundInitiative::STATUS_OPEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
$xaction = id(new FundInitiativeTransaction())
|
||||||
|
->setTransactionType($type_status)
|
||||||
|
->setNewValue($new_status);
|
||||||
|
|
||||||
|
$editor = id(new FundInitiativeEditor())
|
||||||
|
->setActor($viewer)
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setContinueOnMissingFields(true);
|
||||||
|
|
||||||
|
$editor->applyTransactions($initiative, array($xaction));
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($initiative_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($is_close) {
|
||||||
|
$title = pht('Close Initiative?');
|
||||||
|
$body = pht('Really close this initiative?');
|
||||||
|
$button_text = pht('Close Initiative');
|
||||||
|
} else {
|
||||||
|
$title = pht('Reopen Initiative?');
|
||||||
|
$body = pht('Really reopen this initiative?');
|
||||||
|
$button_text = pht('Reopen Initiative');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle($title)
|
||||||
|
->appendParagraph($body)
|
||||||
|
->addCancelButton($initiative_uri)
|
||||||
|
->addSubmitButton($button_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,191 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundInitiativeEditController
|
||||||
|
extends FundController {
|
||||||
|
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
public function willProcessRequest(array $data) {
|
||||||
|
$this->id = idx($data, 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processRequest() {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$viewer = $request->getUser();
|
||||||
|
|
||||||
|
if ($this->id) {
|
||||||
|
$initiative = id(new FundInitiativeQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($this->id))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
|
->executeOne();
|
||||||
|
if (!$initiative) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
$is_new = false;
|
||||||
|
} else {
|
||||||
|
$initiative = FundInitiative::initializeNewInitiative($viewer);
|
||||||
|
$is_new = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($is_new) {
|
||||||
|
$title = pht('Create Initiative');
|
||||||
|
$button_text = pht('Create Initiative');
|
||||||
|
$cancel_uri = $this->getApplicationURI();
|
||||||
|
} else {
|
||||||
|
$title = pht(
|
||||||
|
'Edit %s %s',
|
||||||
|
$initiative->getMonogram(),
|
||||||
|
$initiative->getName());
|
||||||
|
$button_text = pht('Save Changes');
|
||||||
|
$cancel_uri = '/'.$initiative->getMonogram();
|
||||||
|
}
|
||||||
|
|
||||||
|
$e_name = true;
|
||||||
|
$v_name = $initiative->getName();
|
||||||
|
|
||||||
|
$v_desc = $initiative->getDescription();
|
||||||
|
|
||||||
|
if ($is_new) {
|
||||||
|
$v_projects = array();
|
||||||
|
} else {
|
||||||
|
$v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||||
|
$initiative->getPHID(),
|
||||||
|
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
|
||||||
|
$v_projects = array_reverse($v_projects);
|
||||||
|
}
|
||||||
|
|
||||||
|
$validation_exception = null;
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
$v_name = $request->getStr('name');
|
||||||
|
$v_desc = $request->getStr('description');
|
||||||
|
$v_view = $request->getStr('viewPolicy');
|
||||||
|
$v_edit = $request->getStr('editPolicy');
|
||||||
|
$v_projects = $request->getArr('projects');
|
||||||
|
|
||||||
|
$type_name = FundInitiativeTransaction::TYPE_NAME;
|
||||||
|
$type_desc = FundInitiativeTransaction::TYPE_DESCRIPTION;
|
||||||
|
$type_view = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||||
|
$type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
||||||
|
|
||||||
|
$xactions = array();
|
||||||
|
|
||||||
|
$xactions[] = id(new FundInitiativeTransaction())
|
||||||
|
->setTransactionType($type_name)
|
||||||
|
->setNewValue($v_name);
|
||||||
|
|
||||||
|
$xactions[] = id(new FundInitiativeTransaction())
|
||||||
|
->setTransactionType($type_desc)
|
||||||
|
->setNewValue($v_desc);
|
||||||
|
|
||||||
|
$xactions[] = id(new FundInitiativeTransaction())
|
||||||
|
->setTransactionType($type_view)
|
||||||
|
->setNewValue($v_view);
|
||||||
|
|
||||||
|
$xactions[] = id(new FundInitiativeTransaction())
|
||||||
|
->setTransactionType($type_edit)
|
||||||
|
->setNewValue($v_edit);
|
||||||
|
|
||||||
|
$proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
|
||||||
|
$xactions[] = id(new FundInitiativeTransaction())
|
||||||
|
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
|
||||||
|
->setMetadataValue('edge:type', $proj_edge_type)
|
||||||
|
->setNewValue(array('=' => array_fuse($v_projects)));
|
||||||
|
|
||||||
|
$editor = id(new FundInitiativeEditor())
|
||||||
|
->setActor($viewer)
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setContinueOnNoEffect(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$editor->applyTransactions($initiative, $xactions);
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())
|
||||||
|
->setURI('/'.$initiative->getMonogram());
|
||||||
|
} catch (PhabricatorApplicationTransactionValidationException $ex) {
|
||||||
|
$validation_exception = $ex;
|
||||||
|
|
||||||
|
$e_name = $ex->getShortMessage($type_name);
|
||||||
|
|
||||||
|
$initiative->setViewPolicy($v_view);
|
||||||
|
$initiative->setEditPolicy($v_edit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$policies = id(new PhabricatorPolicyQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setObject($initiative)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
if ($v_projects) {
|
||||||
|
$project_handles = $this->loadViewerHandles($v_projects);
|
||||||
|
} else {
|
||||||
|
$project_handles = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$form = id(new AphrontFormView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setName('name')
|
||||||
|
->setLabel(pht('Name'))
|
||||||
|
->setValue($v_name)
|
||||||
|
->setError($e_name))
|
||||||
|
->appendChild(
|
||||||
|
id(new PhabricatorRemarkupControl())
|
||||||
|
->setName('description')
|
||||||
|
->setLabel(pht('Description'))
|
||||||
|
->setValue($v_desc))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTokenizerControl())
|
||||||
|
->setLabel(pht('Projects'))
|
||||||
|
->setName('projects')
|
||||||
|
->setValue($project_handles)
|
||||||
|
->setDatasource(new PhabricatorProjectDatasource()))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormPolicyControl())
|
||||||
|
->setName('viewPolicy')
|
||||||
|
->setPolicyObject($initiative)
|
||||||
|
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
|
||||||
|
->setPolicies($policies))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormPolicyControl())
|
||||||
|
->setName('editPolicy')
|
||||||
|
->setPolicyObject($initiative)
|
||||||
|
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
|
||||||
|
->setPolicies($policies))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormSubmitControl())
|
||||||
|
->setValue($button_text)
|
||||||
|
->addCancelButton($cancel_uri));
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
|
if ($is_new) {
|
||||||
|
$crumbs->addTextCrumb(pht('Create Initiative'));
|
||||||
|
} else {
|
||||||
|
$crumbs->addTextCrumb(
|
||||||
|
$initiative->getMonogram(),
|
||||||
|
'/'.$initiative->getMonogram());
|
||||||
|
$crumbs->addTextCrumb(pht('Edit'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$box = id(new PHUIObjectBoxView())
|
||||||
|
->setValidationException($validation_exception)
|
||||||
|
->setHeaderText($title)
|
||||||
|
->appendChild($form);
|
||||||
|
|
||||||
|
return $this->buildApplicationPage(
|
||||||
|
array(
|
||||||
|
$crumbs,
|
||||||
|
$box,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'title' => $title,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundInitiativeListController
|
||||||
|
extends FundController {
|
||||||
|
|
||||||
|
private $queryKey;
|
||||||
|
|
||||||
|
public function willProcessRequest(array $data) {
|
||||||
|
$this->queryKey = idx($data, 'queryKey');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processRequest() {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$controller = id(new PhabricatorApplicationSearchController($request))
|
||||||
|
->setQueryKey($this->queryKey)
|
||||||
|
->setSearchEngine(new FundInitiativeSearchEngine())
|
||||||
|
->setNavigation($this->buildSideNavView());
|
||||||
|
|
||||||
|
return $this->delegateToController($controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildSideNavView() {
|
||||||
|
$user = $this->getRequest()->getUser();
|
||||||
|
|
||||||
|
$nav = new AphrontSideNavFilterView();
|
||||||
|
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
|
||||||
|
|
||||||
|
id(new FundInitiativeSearchEngine())
|
||||||
|
->setViewer($user)
|
||||||
|
->addNavigationItems($nav->getMenu());
|
||||||
|
$nav->selectFilter(null);
|
||||||
|
|
||||||
|
return $nav;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildApplicationCrumbs() {
|
||||||
|
$crumbs = parent::buildApplicationCrumbs();
|
||||||
|
|
||||||
|
$can_create = $this->hasApplicationCapability(
|
||||||
|
FundCreateInitiativesCapability::CAPABILITY);
|
||||||
|
|
||||||
|
$crumbs->addAction(
|
||||||
|
id(new PHUIListItemView())
|
||||||
|
->setName(pht('Create Initiative'))
|
||||||
|
->setHref($this->getApplicationURI('create/'))
|
||||||
|
->setIcon('fa-plus-square')
|
||||||
|
->setDisabled(!$can_create)
|
||||||
|
->setWorkflow(!$can_create));
|
||||||
|
|
||||||
|
return $crumbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundInitiativeViewController
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
|
$crumbs->addTextCrumb($initiative->getMonogram());
|
||||||
|
|
||||||
|
$title = pht(
|
||||||
|
'%s %s',
|
||||||
|
$initiative->getMonogram(),
|
||||||
|
$initiative->getName());
|
||||||
|
|
||||||
|
if ($initiative->isClosed()) {
|
||||||
|
$status_icon = 'fa-times';
|
||||||
|
$status_color = 'bluegrey';
|
||||||
|
} else {
|
||||||
|
$status_icon = 'fa-check';
|
||||||
|
$status_color = 'bluegrey';
|
||||||
|
}
|
||||||
|
$status_name = idx(
|
||||||
|
FundInitiative::getStatusNameMap(),
|
||||||
|
$initiative->getStatus());
|
||||||
|
|
||||||
|
$header = id(new PHUIHeaderView())
|
||||||
|
->setObjectName($initiative->getMonogram())
|
||||||
|
->setHeader($initiative->getName())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setPolicyObject($initiative)
|
||||||
|
->setStatus($status_icon, $status_color, $status_name);
|
||||||
|
|
||||||
|
$properties = $this->buildPropertyListView($initiative);
|
||||||
|
$actions = $this->buildActionListView($initiative);
|
||||||
|
$properties->setActionList($actions);
|
||||||
|
|
||||||
|
$box = id(new PHUIObjectBoxView())
|
||||||
|
->setHeader($header)
|
||||||
|
->appendChild($properties);
|
||||||
|
|
||||||
|
$xactions = id(new FundInitiativeTransactionQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withObjectPHIDs(array($initiative->getPHID()))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$timeline = id(new PhabricatorApplicationTransactionView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setObjectPHID($initiative->getPHID())
|
||||||
|
->setTransactions($xactions);
|
||||||
|
|
||||||
|
return $this->buildApplicationPage(
|
||||||
|
array(
|
||||||
|
$crumbs,
|
||||||
|
$box,
|
||||||
|
$timeline,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'title' => $title,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildPropertyListView(FundInitiative $initiative) {
|
||||||
|
$viewer = $this->getRequest()->getUser();
|
||||||
|
|
||||||
|
$view = id(new PHUIPropertyListView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setObject($initiative);
|
||||||
|
|
||||||
|
$owner_phid = $initiative->getOwnerPHID();
|
||||||
|
$this->loadHandles(array($owner_phid));
|
||||||
|
|
||||||
|
$view->addProperty(
|
||||||
|
pht('Owner'),
|
||||||
|
$this->getHandle($owner_phid)->renderLink());
|
||||||
|
|
||||||
|
$view->invokeWillRenderEvent();
|
||||||
|
|
||||||
|
$description = $initiative->getDescription();
|
||||||
|
if (strlen($description)) {
|
||||||
|
$description = PhabricatorMarkupEngine::renderOneObject(
|
||||||
|
id(new PhabricatorMarkupOneOff())->setContent($description),
|
||||||
|
'default',
|
||||||
|
$viewer);
|
||||||
|
|
||||||
|
$view->addSectionHeader(pht('Description'));
|
||||||
|
$view->addTextContent($description);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildActionListView(FundInitiative $initiative) {
|
||||||
|
$viewer = $this->getRequest()->getUser();
|
||||||
|
$id = $initiative->getID();
|
||||||
|
|
||||||
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
|
$viewer,
|
||||||
|
$initiative,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$view = id(new PhabricatorActionListView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setObject($initiative);
|
||||||
|
|
||||||
|
$view->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('Edit Initiative'))
|
||||||
|
->setIcon('fa-pencil')
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(!$can_edit)
|
||||||
|
->setHref($this->getApplicationURI("/edit/{$id}/")));
|
||||||
|
|
||||||
|
if ($initiative->isClosed()) {
|
||||||
|
$close_name = pht('Reopen Initiative');
|
||||||
|
$close_icon = 'fa-check';
|
||||||
|
} else {
|
||||||
|
$close_name = pht('Close Initiative');
|
||||||
|
$close_icon = 'fa-times';
|
||||||
|
}
|
||||||
|
|
||||||
|
$view->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName($close_name)
|
||||||
|
->setIcon($close_icon)
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(true)
|
||||||
|
->setHref($this->getApplicationURI("/close/{$id}/")));
|
||||||
|
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
13
src/applications/fund/editor/FundBackingEditor.php
Normal file
13
src/applications/fund/editor/FundBackingEditor.php
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundBackingEditor
|
||||||
|
extends PhabricatorApplicationTransactionEditor {
|
||||||
|
|
||||||
|
public function getEditorApplicationClass() {
|
||||||
|
return 'PhabricatorFundApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEditorObjectsDescription() {
|
||||||
|
return pht('Fund Backing');
|
||||||
|
}
|
||||||
|
}
|
123
src/applications/fund/editor/FundInitiativeEditor.php
Normal file
123
src/applications/fund/editor/FundInitiativeEditor.php
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundInitiativeEditor
|
||||||
|
extends PhabricatorApplicationTransactionEditor {
|
||||||
|
|
||||||
|
public function getEditorApplicationClass() {
|
||||||
|
return 'PhabricatorFundApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEditorObjectsDescription() {
|
||||||
|
return pht('Fund Initiatives');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTransactionTypes() {
|
||||||
|
$types = parent::getTransactionTypes();
|
||||||
|
|
||||||
|
$types[] = FundInitiativeTransaction::TYPE_NAME;
|
||||||
|
$types[] = FundInitiativeTransaction::TYPE_DESCRIPTION;
|
||||||
|
$types[] = FundInitiativeTransaction::TYPE_STATUS;
|
||||||
|
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||||
|
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
||||||
|
|
||||||
|
return $types;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCustomTransactionOldValue(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
switch ($xaction->getTransactionType()) {
|
||||||
|
case FundInitiativeTransaction::TYPE_NAME:
|
||||||
|
return $object->getName();
|
||||||
|
case FundInitiativeTransaction::TYPE_DESCRIPTION:
|
||||||
|
return $object->getDescription();
|
||||||
|
case FundInitiativeTransaction::TYPE_STATUS:
|
||||||
|
return $object->getStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::getCustomTransactionOldValue($object, $xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCustomTransactionNewValue(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
switch ($xaction->getTransactionType()) {
|
||||||
|
case FundInitiativeTransaction::TYPE_NAME:
|
||||||
|
case FundInitiativeTransaction::TYPE_DESCRIPTION:
|
||||||
|
case FundInitiativeTransaction::TYPE_STATUS:
|
||||||
|
return $xaction->getNewValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::getCustomTransactionNewValue($object, $xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function applyCustomInternalTransaction(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
switch ($xaction->getTransactionType()) {
|
||||||
|
case FundInitiativeTransaction::TYPE_NAME:
|
||||||
|
$object->setName($xaction->getNewValue());
|
||||||
|
return;
|
||||||
|
case FundInitiativeTransaction::TYPE_DESCRIPTION:
|
||||||
|
$object->setDescription($xaction->getNewValue());
|
||||||
|
return;
|
||||||
|
case FundInitiativeTransaction::TYPE_STATUS:
|
||||||
|
$object->setStatus($xaction->getNewValue());
|
||||||
|
return;
|
||||||
|
case PhabricatorTransactions::TYPE_SUBSCRIBERS:
|
||||||
|
case PhabricatorTransactions::TYPE_EDGE:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::applyCustomInternalTransaction($object, $xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function applyCustomExternalTransaction(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
|
|
||||||
|
switch ($xaction->getTransactionType()) {
|
||||||
|
case FundInitiativeTransaction::TYPE_NAME:
|
||||||
|
case FundInitiativeTransaction::TYPE_DESCRIPTION:
|
||||||
|
case FundInitiativeTransaction::TYPE_STATUS:
|
||||||
|
case PhabricatorTransactions::TYPE_SUBSCRIBERS:
|
||||||
|
case PhabricatorTransactions::TYPE_EDGE:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::applyCustomExternalTransaction($object, $xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function validateTransaction(
|
||||||
|
PhabricatorLiskDAO $object,
|
||||||
|
$type,
|
||||||
|
array $xactions) {
|
||||||
|
|
||||||
|
$errors = parent::validateTransaction($object, $type, $xactions);
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case FundInitiativeTransaction::TYPE_NAME:
|
||||||
|
$missing = $this->validateIsEmptyTextField(
|
||||||
|
$object->getName(),
|
||||||
|
$xactions);
|
||||||
|
|
||||||
|
if ($missing) {
|
||||||
|
$error = new PhabricatorApplicationTransactionValidationError(
|
||||||
|
$type,
|
||||||
|
pht('Required'),
|
||||||
|
pht('Initiative name is required.'),
|
||||||
|
nonempty(last($xactions), null));
|
||||||
|
|
||||||
|
$error->setIsMissingFieldError(true);
|
||||||
|
$errors[] = $error;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
41
src/applications/fund/phid/FundBackingPHIDType.php
Normal file
41
src/applications/fund/phid/FundBackingPHIDType.php
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundBackingPHIDType extends PhabricatorPHIDType {
|
||||||
|
|
||||||
|
const TYPECONST = 'FBAK';
|
||||||
|
|
||||||
|
public function getTypeName() {
|
||||||
|
return pht('Variable');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newObject() {
|
||||||
|
return new FundInitiative();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildQueryForObjects(
|
||||||
|
PhabricatorObjectQuery $query,
|
||||||
|
array $phids) {
|
||||||
|
|
||||||
|
return id(new FundInitiativeQuery())
|
||||||
|
->withPHIDs($phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHandles(
|
||||||
|
PhabricatorHandleQuery $query,
|
||||||
|
array $handles,
|
||||||
|
array $objects) {
|
||||||
|
|
||||||
|
foreach ($handles as $phid => $handle) {
|
||||||
|
$initiative = $objects[$phid];
|
||||||
|
|
||||||
|
$id = $initiative->getID();
|
||||||
|
$monogram = $initiative->getMonogram();
|
||||||
|
$name = $initiative->getName();
|
||||||
|
|
||||||
|
$handle->setName($name);
|
||||||
|
$handle->setFullName("{$monogram} {$name}");
|
||||||
|
$handle->setURI("/fund/view/{$id}/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
74
src/applications/fund/phid/FundInitiativePHIDType.php
Normal file
74
src/applications/fund/phid/FundInitiativePHIDType.php
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundInitiativePHIDType extends PhabricatorPHIDType {
|
||||||
|
|
||||||
|
const TYPECONST = 'FITV';
|
||||||
|
|
||||||
|
public function getTypeName() {
|
||||||
|
return pht('Initiative');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newObject() {
|
||||||
|
return new FundInitiative();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildQueryForObjects(
|
||||||
|
PhabricatorObjectQuery $query,
|
||||||
|
array $phids) {
|
||||||
|
|
||||||
|
return id(new FundInitiativeQuery())
|
||||||
|
->withPHIDs($phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHandles(
|
||||||
|
PhabricatorHandleQuery $query,
|
||||||
|
array $handles,
|
||||||
|
array $objects) {
|
||||||
|
|
||||||
|
foreach ($handles as $phid => $handle) {
|
||||||
|
$initiative = $objects[$phid];
|
||||||
|
|
||||||
|
$id = $initiative->getID();
|
||||||
|
$monogram = $initiative->getMonogram();
|
||||||
|
$name = $initiative->getName();
|
||||||
|
|
||||||
|
if ($initiative->isClosed()) {
|
||||||
|
$handle->setStatus(PhabricatorObjectHandleStatus::STATUS_CLOSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
$handle->setName($name);
|
||||||
|
$handle->setFullName("{$monogram} {$name}");
|
||||||
|
$handle->setURI("/I{$id}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canLoadNamedObject($name) {
|
||||||
|
return preg_match('/^I\d*[1-9]\d*$/i', $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadNamedObjects(
|
||||||
|
PhabricatorObjectQuery $query,
|
||||||
|
array $names) {
|
||||||
|
|
||||||
|
$id_map = array();
|
||||||
|
foreach ($names as $name) {
|
||||||
|
$id = (int)substr($name, 1);
|
||||||
|
$id_map[$id][] = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
$objects = id(new FundInitiativeQuery())
|
||||||
|
->setViewer($query->getViewer())
|
||||||
|
->withIDs(array_keys($id_map))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
foreach ($objects as $id => $object) {
|
||||||
|
foreach (idx($id_map, $id, array()) as $name) {
|
||||||
|
$results[$name] = $object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
60
src/applications/fund/query/FundBackingQuery.php
Normal file
60
src/applications/fund/query/FundBackingQuery.php
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
<?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';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
10
src/applications/fund/query/FundBackingTransactionQuery.php
Normal file
10
src/applications/fund/query/FundBackingTransactionQuery.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundBackingTransactionQuery
|
||||||
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
|
public function getTemplateApplicationTransaction() {
|
||||||
|
return new FundBackingTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
116
src/applications/fund/query/FundInitiativeQuery.php
Normal file
116
src/applications/fund/query/FundInitiativeQuery.php
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundInitiativeQuery
|
||||||
|
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
|
|
||||||
|
private $ids;
|
||||||
|
private $phids;
|
||||||
|
private $ownerPHIDs;
|
||||||
|
private $statuses;
|
||||||
|
|
||||||
|
private $needProjectPHIDs;
|
||||||
|
|
||||||
|
public function withIDs(array $ids) {
|
||||||
|
$this->ids = $ids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withPHIDs(array $phids) {
|
||||||
|
$this->phids = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withOwnerPHIDs(array $phids) {
|
||||||
|
$this->ownerPHIDs = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withStatuses(array $statuses) {
|
||||||
|
$this->statuses = $statuses;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function needProjectPHIDs($need) {
|
||||||
|
$this->needProjectPHIDs = $need;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadPage() {
|
||||||
|
$table = new FundInitiative();
|
||||||
|
$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 didFilterPage(array $initiatives) {
|
||||||
|
|
||||||
|
if ($this->needProjectPHIDs) {
|
||||||
|
$edge_query = id(new PhabricatorEdgeQuery())
|
||||||
|
->withSourcePHIDs(mpull($initiatives, 'getPHID'))
|
||||||
|
->withEdgeTypes(
|
||||||
|
array(
|
||||||
|
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST,
|
||||||
|
));
|
||||||
|
$edge_query->execute();
|
||||||
|
|
||||||
|
foreach ($initiatives as $initiative) {
|
||||||
|
$phids = $edge_query->getDestinationPHIDs(
|
||||||
|
array(
|
||||||
|
$initiative->getPHID(),
|
||||||
|
));
|
||||||
|
$initiative->attachProjectPHIDs($phids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $initiatives;
|
||||||
|
}
|
||||||
|
|
||||||
|
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->ownerPHIDs !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'ownerPHID IN (%Ls)',
|
||||||
|
$this->ownerPHIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->statuses !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'status IN (%Ls)',
|
||||||
|
$this->statuses);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->formatWhereClause($where);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryApplicationClass() {
|
||||||
|
return 'PhabricatorFundApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
180
src/applications/fund/query/FundInitiativeSearchEngine.php
Normal file
180
src/applications/fund/query/FundInitiativeSearchEngine.php
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundInitiativeSearchEngine
|
||||||
|
extends PhabricatorApplicationSearchEngine {
|
||||||
|
|
||||||
|
public function getResultTypeDescription() {
|
||||||
|
return pht('Fund Initiatives');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationClassName() {
|
||||||
|
return 'PhabricatorFundApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
||||||
|
$saved = new PhabricatorSavedQuery();
|
||||||
|
|
||||||
|
$saved->setParameter(
|
||||||
|
'ownerPHIDs',
|
||||||
|
$this->readUsersFromRequest($request, 'owners'));
|
||||||
|
|
||||||
|
$saved->setParameter(
|
||||||
|
'statuses',
|
||||||
|
$this->readListFromRequest($request, 'statuses'));
|
||||||
|
|
||||||
|
return $saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
||||||
|
$query = id(new FundInitiativeQuery())
|
||||||
|
->needProjectPHIDs(true);
|
||||||
|
|
||||||
|
$owner_phids = $saved->getParameter('ownerPHIDs');
|
||||||
|
if ($owner_phids) {
|
||||||
|
$query->withOwnerPHIDs($owner_phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
$statuses = $saved->getParameter('statuses');
|
||||||
|
if ($statuses) {
|
||||||
|
$query->withStatuses($statuses);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildSearchForm(
|
||||||
|
AphrontFormView $form,
|
||||||
|
PhabricatorSavedQuery $saved) {
|
||||||
|
|
||||||
|
$statuses = $saved->getParameter('statuses', array());
|
||||||
|
$statuses = array_fuse($statuses);
|
||||||
|
|
||||||
|
$owner_phids = $saved->getParameter('ownerPHIDs', array());
|
||||||
|
|
||||||
|
$all_phids = array_mergev(
|
||||||
|
array(
|
||||||
|
$owner_phids,
|
||||||
|
));
|
||||||
|
|
||||||
|
$handles = id(new PhabricatorHandleQuery())
|
||||||
|
->setViewer($this->requireViewer())
|
||||||
|
->withPHIDs($all_phids)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$status_map = FundInitiative::getStatusNameMap();
|
||||||
|
$status_control = id(new AphrontFormCheckboxControl())
|
||||||
|
->setLabel(pht('Statuses'));
|
||||||
|
foreach ($status_map as $status => $name) {
|
||||||
|
$status_control->addCheckbox(
|
||||||
|
'statuses[]',
|
||||||
|
$status,
|
||||||
|
$name,
|
||||||
|
isset($statuses[$status]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$form
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTokenizerControl())
|
||||||
|
->setLabel(pht('Owners'))
|
||||||
|
->setName('owners')
|
||||||
|
->setDatasource(new PhabricatorPeopleDatasource())
|
||||||
|
->setValue(array_select_keys($handles, $owner_phids)))
|
||||||
|
->appendChild($status_control);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getURI($path) {
|
||||||
|
return '/fund/'.$path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBuiltinQueryNames() {
|
||||||
|
$names = array();
|
||||||
|
|
||||||
|
$names['open'] = pht('Open Initiatives');
|
||||||
|
if ($this->requireViewer()->isLoggedIn()) {
|
||||||
|
$names['owned'] = pht('Owned Initiatives');
|
||||||
|
}
|
||||||
|
$names['all'] = pht('All Initiatives');
|
||||||
|
|
||||||
|
return $names;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildSavedQueryFromBuiltin($query_key) {
|
||||||
|
$query = $this->newSavedQuery();
|
||||||
|
$query->setQueryKey($query_key);
|
||||||
|
|
||||||
|
switch ($query_key) {
|
||||||
|
case 'all':
|
||||||
|
return $query;
|
||||||
|
case 'owned':
|
||||||
|
return $query->setParameter(
|
||||||
|
'ownerPHIDs',
|
||||||
|
array(
|
||||||
|
$this->requireViewer()->getPHID(),
|
||||||
|
));
|
||||||
|
case 'open':
|
||||||
|
return $query->setParameter(
|
||||||
|
'statuses',
|
||||||
|
array(
|
||||||
|
FundInitiative::STATUS_OPEN,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::buildSavedQueryFromBuiltin($query_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getRequiredHandlePHIDsForResultList(
|
||||||
|
array $initiatives,
|
||||||
|
PhabricatorSavedQuery $query) {
|
||||||
|
|
||||||
|
$phids = array();
|
||||||
|
foreach ($initiatives as $initiative) {
|
||||||
|
$phids[] = $initiative->getOwnerPHID();
|
||||||
|
foreach ($initiative->getProjectPHIDs() as $project_phid) {
|
||||||
|
$phids[] = $project_phid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $phids;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderResultList(
|
||||||
|
array $initiatives,
|
||||||
|
PhabricatorSavedQuery $query,
|
||||||
|
array $handles) {
|
||||||
|
assert_instances_of($initiatives, 'FundInitiative');
|
||||||
|
|
||||||
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
|
$list = id(new PHUIObjectItemListView());
|
||||||
|
foreach ($initiatives as $initiative) {
|
||||||
|
$owner_handle = $handles[$initiative->getOwnerPHID()];
|
||||||
|
|
||||||
|
$item = id(new PHUIObjectItemView())
|
||||||
|
->setObjectName($initiative->getMonogram())
|
||||||
|
->setHeader($initiative->getName())
|
||||||
|
->setHref('/'.$initiative->getMonogram())
|
||||||
|
->addByline(pht('Owner: %s', $owner_handle->renderLink()));
|
||||||
|
|
||||||
|
if ($initiative->isClosed()) {
|
||||||
|
$item->setDisabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$project_handles = array_select_keys(
|
||||||
|
$handles,
|
||||||
|
$initiative->getProjectPHIDs());
|
||||||
|
if ($project_handles) {
|
||||||
|
$item->addAttribute(
|
||||||
|
id(new PHUIHandleTagListView())
|
||||||
|
->setLimit(4)
|
||||||
|
->setSlim(true)
|
||||||
|
->setHandles($project_handles));
|
||||||
|
}
|
||||||
|
|
||||||
|
$list->addItem($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundInitiativeTransactionQuery
|
||||||
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
|
public function getTemplateApplicationTransaction() {
|
||||||
|
return new FundInitiativeTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundInitiativeRemarkupRule extends PhabricatorObjectRemarkupRule {
|
||||||
|
|
||||||
|
protected function getObjectNamePrefix() {
|
||||||
|
return 'I';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadObjects(array $ids) {
|
||||||
|
$viewer = $this->getEngine()->getConfig('viewer');
|
||||||
|
|
||||||
|
return id(new FundInitiativeQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs($ids)
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
85
src/applications/fund/storage/FundBacking.php
Normal file
85
src/applications/fund/storage/FundBacking.php
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundBacking extends FundDAO
|
||||||
|
implements
|
||||||
|
PhabricatorPolicyInterface,
|
||||||
|
PhabricatorApplicationTransactionInterface {
|
||||||
|
|
||||||
|
protected $initiativePHID;
|
||||||
|
protected $backerPHID;
|
||||||
|
protected $purchasePHID;
|
||||||
|
protected $amountInCents;
|
||||||
|
protected $status;
|
||||||
|
protected $properties = array();
|
||||||
|
|
||||||
|
private $initiative = self::ATTACHABLE;
|
||||||
|
|
||||||
|
public function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_AUX_PHID => true,
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generatePHID() {
|
||||||
|
return PhabricatorPHID::generateNewPHID(FundBackingPHIDType::TYPECONST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProperty($key, $default = null) {
|
||||||
|
return idx($this->properties, $key, $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setProperty($key, $value) {
|
||||||
|
$this->properties[$key] = $value;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getCapabilities() {
|
||||||
|
return array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPolicy($capability) {
|
||||||
|
switch ($capability) {
|
||||||
|
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.
|
||||||
|
|
||||||
|
$initiative = $this->getInitiative();
|
||||||
|
if ($initiative) {
|
||||||
|
return $initiative->getPolicy($capability);
|
||||||
|
}
|
||||||
|
return PhabricatorPolicies::POLICY_NOONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||||
|
return ($viewer->getPHID() == $this->getBackerPHID());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function describeAutomaticCapability($capability) {
|
||||||
|
return pht('A backer can always see what they have backed.');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getApplicationTransactionEditor() {
|
||||||
|
return new FundBackingEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionObject() {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionTemplate() {
|
||||||
|
return new FundBackingTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
18
src/applications/fund/storage/FundBackingTransaction.php
Normal file
18
src/applications/fund/storage/FundBackingTransaction.php
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundBackingTransaction
|
||||||
|
extends PhabricatorApplicationTransaction {
|
||||||
|
|
||||||
|
public function getApplicationName() {
|
||||||
|
return 'fund';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionType() {
|
||||||
|
return FundBackingPHIDType::TYPECONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionCommentObject() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
9
src/applications/fund/storage/FundDAO.php
Normal file
9
src/applications/fund/storage/FundDAO.php
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class FundDAO extends PhabricatorLiskDAO {
|
||||||
|
|
||||||
|
public function getApplicationName() {
|
||||||
|
return 'fund';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
157
src/applications/fund/storage/FundInitiative.php
Normal file
157
src/applications/fund/storage/FundInitiative.php
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundInitiative extends FundDAO
|
||||||
|
implements
|
||||||
|
PhabricatorPolicyInterface,
|
||||||
|
PhabricatorProjectInterface,
|
||||||
|
PhabricatorApplicationTransactionInterface,
|
||||||
|
PhabricatorSubscribableInterface,
|
||||||
|
PhabricatorMentionableInterface,
|
||||||
|
PhabricatorFlaggableInterface,
|
||||||
|
PhabricatorTokenReceiverInterface,
|
||||||
|
PhabricatorDestructibleInterface {
|
||||||
|
|
||||||
|
protected $name;
|
||||||
|
protected $ownerPHID;
|
||||||
|
protected $description;
|
||||||
|
protected $viewPolicy;
|
||||||
|
protected $editPolicy;
|
||||||
|
protected $status;
|
||||||
|
|
||||||
|
private $projectPHIDs = self::ATTACHABLE;
|
||||||
|
|
||||||
|
const STATUS_OPEN = 'open';
|
||||||
|
const STATUS_CLOSED = 'closed';
|
||||||
|
|
||||||
|
public static function getStatusNameMap() {
|
||||||
|
return array(
|
||||||
|
self::STATUS_OPEN => pht('Open'),
|
||||||
|
self::STATUS_CLOSED => pht('Closed'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function initializeNewInitiative(PhabricatorUser $actor) {
|
||||||
|
$app = id(new PhabricatorApplicationQuery())
|
||||||
|
->setViewer($actor)
|
||||||
|
->withClasses(array('PhabricatorFundApplication'))
|
||||||
|
->executeOne();
|
||||||
|
|
||||||
|
$view_policy = $app->getPolicy(FundDefaultViewCapability::CAPABILITY);
|
||||||
|
|
||||||
|
return id(new FundInitiative())
|
||||||
|
->setOwnerPHID($actor->getPHID())
|
||||||
|
->setViewPolicy($view_policy)
|
||||||
|
->setEditPolicy($actor->getPHID())
|
||||||
|
->setStatus(self::STATUS_OPEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_AUX_PHID => true,
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generatePHID() {
|
||||||
|
return PhabricatorPHID::generateNewPHID(FundInitiativePHIDType::TYPECONST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMonogram() {
|
||||||
|
return 'I'.$this->getID();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProjectPHIDs() {
|
||||||
|
return $this->assertAttached($this->projectPHIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachProjectPHIDs(array $phids) {
|
||||||
|
$this->projectPHIDs = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isClosed() {
|
||||||
|
return ($this->getStatus() == self::STATUS_CLOSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getCapabilities() {
|
||||||
|
return array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPolicy($capability) {
|
||||||
|
switch ($capability) {
|
||||||
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||||
|
return $this->getViewPolicy();
|
||||||
|
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||||
|
return $this->getEditPolicy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function describeAutomaticCapability($capability) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getApplicationTransactionEditor() {
|
||||||
|
return new FundInitiativeEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionObject() {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionTemplate() {
|
||||||
|
return new FundInitiativeTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorSubscribableInterface )----------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function isAutomaticallySubscribed($phid) {
|
||||||
|
return ($phid == $this->getOwnerPHID());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldShowSubscribersProperty() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldAllowSubscription($phid) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorTokenRecevierInterface )---------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getUsersToNotifyOfTokenGiven() {
|
||||||
|
return array(
|
||||||
|
$this->getOwnerPHID(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorDestructibleInterface )----------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function destroyObjectPermanently(
|
||||||
|
PhabricatorDestructionEngine $engine) {
|
||||||
|
|
||||||
|
$this->openTransaction();
|
||||||
|
$this->delete();
|
||||||
|
$this->saveTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
136
src/applications/fund/storage/FundInitiativeTransaction.php
Normal file
136
src/applications/fund/storage/FundInitiativeTransaction.php
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class FundInitiativeTransaction
|
||||||
|
extends PhabricatorApplicationTransaction {
|
||||||
|
|
||||||
|
const TYPE_NAME = 'fund:name';
|
||||||
|
const TYPE_DESCRIPTION = 'fund:description';
|
||||||
|
const TYPE_STATUS = 'fund:status';
|
||||||
|
|
||||||
|
public function getApplicationName() {
|
||||||
|
return 'fund';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionType() {
|
||||||
|
return FundInitiativePHIDType::TYPECONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionCommentObject() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
$author_phid = $this->getAuthorPHID();
|
||||||
|
$object_phid = $this->getObjectPHID();
|
||||||
|
|
||||||
|
$old = $this->getOldValue();
|
||||||
|
$new = $this->getNewValue();
|
||||||
|
|
||||||
|
$type = $this->getTransactionType();
|
||||||
|
switch ($type) {
|
||||||
|
case FundInitiativeTransaction::TYPE_NAME:
|
||||||
|
if ($old === null) {
|
||||||
|
return pht(
|
||||||
|
'%s created this initiative.',
|
||||||
|
$this->renderHandleLink($author_phid));
|
||||||
|
} else {
|
||||||
|
return pht(
|
||||||
|
'%s renamed this initiative from "%s" to "%s".',
|
||||||
|
$this->renderHandleLink($author_phid),
|
||||||
|
$old,
|
||||||
|
$new);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FundInitiativeTransaction::TYPE_DESCRIPTION:
|
||||||
|
return pht(
|
||||||
|
'%s edited the description of this initiative.',
|
||||||
|
$this->renderHandleLink($author_phid));
|
||||||
|
case FundInitiativeTransaction::TYPE_STATUS:
|
||||||
|
switch ($new) {
|
||||||
|
case FundInitiative::STATUS_OPEN:
|
||||||
|
return pht(
|
||||||
|
'%s reopened this initiative.',
|
||||||
|
$this->renderHandleLink($author_phid));
|
||||||
|
case FundInitiative::STATUS_CLOSED:
|
||||||
|
return pht(
|
||||||
|
'%s closed this initiative.',
|
||||||
|
$this->renderHandleLink($author_phid));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::getTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitleForFeed(PhabricatorFeedStory $story) {
|
||||||
|
$author_phid = $this->getAuthorPHID();
|
||||||
|
$object_phid = $this->getObjectPHID();
|
||||||
|
|
||||||
|
$old = $this->getOldValue();
|
||||||
|
$new = $this->getNewValue();
|
||||||
|
|
||||||
|
$type = $this->getTransactionType();
|
||||||
|
switch ($type) {
|
||||||
|
case FundInitiativeTransaction::TYPE_NAME:
|
||||||
|
if ($old === null) {
|
||||||
|
return pht(
|
||||||
|
'%s created %s.',
|
||||||
|
$this->renderHandleLink($author_phid),
|
||||||
|
$this->renderHandleLink($object_phid));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return pht(
|
||||||
|
'%s renamed %s.',
|
||||||
|
$this->renderHandleLink($author_phid),
|
||||||
|
$this->renderHandleLink($object_phid));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FundInitiativeTransaction::TYPE_DESCRIPTION:
|
||||||
|
return pht(
|
||||||
|
'%s updated the description for %s.',
|
||||||
|
$this->renderHandleLink($author_phid),
|
||||||
|
$this->renderHandleLink($object_phid));
|
||||||
|
case FundInitiativeTransaction::TYPE_STATUS:
|
||||||
|
switch ($new) {
|
||||||
|
case FundInitiative::STATUS_OPEN:
|
||||||
|
return pht(
|
||||||
|
'%s reopened %s.',
|
||||||
|
$this->renderHandleLink($author_phid),
|
||||||
|
$this->renderHandleLink($object_phid));
|
||||||
|
case FundInitiative::STATUS_CLOSED:
|
||||||
|
return pht(
|
||||||
|
'%s closed %s.',
|
||||||
|
$this->renderHandleLink($author_phid),
|
||||||
|
$this->renderHandleLink($object_phid));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::getTitleForFeed($story);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldHide() {
|
||||||
|
$old = $this->getOldValue();
|
||||||
|
switch ($this->getTransactionType()) {
|
||||||
|
case FundInitiativeTransaction::TYPE_DESCRIPTION:
|
||||||
|
return ($old === null);
|
||||||
|
}
|
||||||
|
return parent::shouldHide();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasChangeDetails() {
|
||||||
|
switch ($this->getTransactionType()) {
|
||||||
|
case FundInitiativeTransaction::TYPE_DESCRIPTION:
|
||||||
|
return ($this->getOldValue() !== null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::hasChangeDetails();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderChangeDetails(PhabricatorUser $viewer) {
|
||||||
|
return $this->renderTextCorpusChangeDetails(
|
||||||
|
$viewer,
|
||||||
|
$this->getOldValue(),
|
||||||
|
$this->getNewValue());
|
||||||
|
}
|
||||||
|
}
|
|
@ -119,6 +119,7 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
||||||
'db.phragment' => array(),
|
'db.phragment' => array(),
|
||||||
'db.dashboard' => array(),
|
'db.dashboard' => array(),
|
||||||
'db.system' => array(),
|
'db.system' => array(),
|
||||||
|
'db.fund' => array(),
|
||||||
'0000.legacy.sql' => array(
|
'0000.legacy.sql' => array(
|
||||||
'legacy' => 0,
|
'legacy' => 0,
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in a new issue