Page MenuHomePhabricator

D16178.diff
No OneTemporary

D16178.diff

diff --git a/resources/sql/autopatches/20160625.tokens.1.sql b/resources/sql/autopatches/20160625.tokens.1.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20160625.tokens.1.sql
@@ -0,0 +1,71 @@
+CREATE TABLE {$NAMESPACE}_tokens.tokens_token (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ phid VARBINARY(64) NOT NULL,
+ name VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT},
+ flavor VARCHAR(128) NOT NULL COLLATE {$COLLATE_TEXT},
+ status VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
+ dateCreated INT UNSIGNED NOT NULL,
+ dateModified INT UNSIGNED NOT NULL,
+ editPolicy VARBINARY(64) NOT NULL,
+ creatorPHID VARBINARY(64) NOT NULL,
+ tokenImagePHID VARBINARY(64) NOT NULL,
+ mailKey BINARY(20) NOT NULL,
+ UNIQUE KEY `key_phid` (phid),
+ KEY `key_creator` (creatorPHID, dateModified)
+) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
+
+CREATE TABLE {$NAMESPACE}_tokens.tokens_transaction (
+ id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ phid VARBINARY(64) NOT NULL,
+ authorPHID VARBINARY(64) NOT NULL,
+ objectPHID VARBINARY(64) NOT NULL,
+ viewPolicy VARBINARY(64) NOT NULL,
+ editPolicy VARBINARY(64) NOT NULL,
+ commentPHID VARBINARY(64),
+ commentVersion INT UNSIGNED NOT NULL,
+ transactionType VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
+ oldValue LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
+ newValue LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
+ contentSource LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
+ metadata LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
+ dateCreated INT UNSIGNED NOT NULL,
+ dateModified INT UNSIGNED NOT NULL,
+ UNIQUE KEY `key_phid` (phid),
+ KEY `key_object` (objectPHID)
+) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
+
+CREATE TABLE {$NAMESPACE}_tokens.edge (
+ src VARBINARY(64) NOT NULL,
+ type INT UNSIGNED NOT NULL,
+ dst VARBINARY(64) NOT NULL,
+ dateCreated INT UNSIGNED NOT NULL,
+ seq INT UNSIGNED NOT NULL,
+ dataID INT UNSIGNED,
+ PRIMARY KEY (src, type, dst),
+ KEY `src` (src, type, dateCreated, seq),
+ UNIQUE KEY `key_dst` (dst, type, src)
+) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
+
+CREATE TABLE {$NAMESPACE}_tokens.edgedata (
+ id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ data LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}
+) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
+
+CREATE TABLE {$NAMESPACE}_tokens.tokens_transaction_comment (
+ id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ phid VARBINARY(64) NOT NULL,
+ transactionPHID VARBINARY(64),
+ authorPHID VARBINARY(64) NOT NULL,
+ viewPolicy VARBINARY(64) NOT NULL,
+ editPolicy VARBINARY(64) NOT NULL,
+ commentVersion INT UNSIGNED NOT NULL,
+ content LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
+ contentSource LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
+ isDeleted BOOL NOT NULL,
+ dateCreated INT UNSIGNED NOT NULL,
+ dateModified INT UNSIGNED NOT NULL,
+
+ UNIQUE KEY `key_phid` (phid),
+ UNIQUE KEY `key_version` (transactionPHID, commentVersion)
+
+) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1982,6 +1982,7 @@
'PhabricatorBotWhatsNewHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotWhatsNewHandler.php',
'PhabricatorBritishEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorBritishEnglishTranslation.php',
'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php',
+ 'PhabricatorBuiltinTokenQuery' => 'applications/tokens/query/PhabricatorBuiltinTokenQuery.php',
'PhabricatorBulkContentSource' => 'infrastructure/daemon/contentsource/PhabricatorBulkContentSource.php',
'PhabricatorBusyUIExample' => 'applications/uiexample/examples/PhabricatorBusyUIExample.php',
'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php',
@@ -2856,6 +2857,7 @@
'PhabricatorObjectHasFileEdgeType' => 'applications/transactions/edges/PhabricatorObjectHasFileEdgeType.php',
'PhabricatorObjectHasJiraIssueEdgeType' => 'applications/doorkeeper/edge/PhabricatorObjectHasJiraIssueEdgeType.php',
'PhabricatorObjectHasSubscriberEdgeType' => 'applications/transactions/edges/PhabricatorObjectHasSubscriberEdgeType.php',
+ 'PhabricatorObjectHasTokenEdgeType' => 'applications/tokens/edge/PhabricatorObjectHasTokenEdgeType.php',
'PhabricatorObjectHasUnsubscriberEdgeType' => 'applications/transactions/edges/PhabricatorObjectHasUnsubscriberEdgeType.php',
'PhabricatorObjectHasWatcherEdgeType' => 'applications/transactions/edges/PhabricatorObjectHasWatcherEdgeType.php',
'PhabricatorObjectListQuery' => 'applications/phid/query/PhabricatorObjectListQuery.php',
@@ -3599,27 +3601,45 @@
'PhabricatorTimezoneSetupCheck' => 'applications/config/check/PhabricatorTimezoneSetupCheck.php',
'PhabricatorTitleGlyphsSetting' => 'applications/settings/setting/PhabricatorTitleGlyphsSetting.php',
'PhabricatorToken' => 'applications/tokens/storage/PhabricatorToken.php',
+ 'PhabricatorTokenArchiveController' => 'applications/tokens/controller/PhabricatorTokenArchiveController.php',
'PhabricatorTokenController' => 'applications/tokens/controller/PhabricatorTokenController.php',
'PhabricatorTokenCount' => 'applications/tokens/storage/PhabricatorTokenCount.php',
'PhabricatorTokenCountQuery' => 'applications/tokens/query/PhabricatorTokenCountQuery.php',
'PhabricatorTokenDAO' => 'applications/tokens/storage/PhabricatorTokenDAO.php',
'PhabricatorTokenDestructionEngineExtension' => 'applications/tokens/engineextension/PhabricatorTokenDestructionEngineExtension.php',
+ 'PhabricatorTokenEditController' => 'applications/tokens/controller/PhabricatorTokenEditController.php',
+ 'PhabricatorTokenEditEngine' => 'applications/tokens/editor/PhabricatorTokenEditEngine.php',
+ 'PhabricatorTokenEditor' => 'applications/tokens/editor/PhabricatorTokenEditor.php',
'PhabricatorTokenGiveController' => 'applications/tokens/controller/PhabricatorTokenGiveController.php',
'PhabricatorTokenGiven' => 'applications/tokens/storage/PhabricatorTokenGiven.php',
'PhabricatorTokenGivenController' => 'applications/tokens/controller/PhabricatorTokenGivenController.php',
'PhabricatorTokenGivenEditor' => 'applications/tokens/editor/PhabricatorTokenGivenEditor.php',
'PhabricatorTokenGivenFeedStory' => 'applications/tokens/feed/PhabricatorTokenGivenFeedStory.php',
'PhabricatorTokenGivenQuery' => 'applications/tokens/query/PhabricatorTokenGivenQuery.php',
+ 'PhabricatorTokenHasObjectEdgeType' => 'applications/tokens/edge/PhabricatorTokenHasObjectEdgeType.php',
'PhabricatorTokenLeaderController' => 'applications/tokens/controller/PhabricatorTokenLeaderController.php',
+ 'PhabricatorTokenListController' => 'applications/tokens/controller/PhabricatorTokenListController.php',
'PhabricatorTokenQuery' => 'applications/tokens/query/PhabricatorTokenQuery.php',
'PhabricatorTokenReceiverInterface' => 'applications/tokens/interface/PhabricatorTokenReceiverInterface.php',
'PhabricatorTokenReceiverQuery' => 'applications/tokens/query/PhabricatorTokenReceiverQuery.php',
- 'PhabricatorTokenTokenPHIDType' => 'applications/tokens/phid/PhabricatorTokenTokenPHIDType.php',
+ 'PhabricatorTokenSearchEngine' => 'applications/tokens/query/PhabricatorTokenSearchEngine.php',
'PhabricatorTokenUIEventListener' => 'applications/tokens/event/PhabricatorTokenUIEventListener.php',
+ 'PhabricatorTokenViewController' => 'applications/tokens/controller/PhabricatorTokenViewController.php',
'PhabricatorTokenizerEditField' => 'applications/transactions/editfield/PhabricatorTokenizerEditField.php',
'PhabricatorTokensApplication' => 'applications/tokens/application/PhabricatorTokensApplication.php',
+ 'PhabricatorTokensCreateCapability' => 'applications/tokens/capability/PhabricatorTokensCreateCapability.php',
'PhabricatorTokensCurtainExtension' => 'applications/tokens/engineextension/PhabricatorTokensCurtainExtension.php',
+ 'PhabricatorTokensDAO' => 'applications/tokens/storage/PhabricatorTokensDAO.php',
+ 'PhabricatorTokensDefaultEditCapability' => 'applications/tokens/capability/PhabricatorTokensDefaultEditCapability.php',
+ 'PhabricatorTokensMailReceiver' => 'applications/tokens/mail/PhabricatorTokensMailReceiver.php',
+ 'PhabricatorTokensReplyHandler' => 'applications/tokens/mail/PhabricatorTokensReplyHandler.php',
+ 'PhabricatorTokensSchemaSpec' => 'applications/tokens/storage/PhabricatorTokensSchemaSpec.php',
'PhabricatorTokensSettingsPanel' => 'applications/settings/panel/PhabricatorTokensSettingsPanel.php',
+ 'PhabricatorTokensToken' => 'applications/tokens/storage/PhabricatorTokensToken.php',
+ 'PhabricatorTokensTokenPHIDType' => 'applications/tokens/phid/PhabricatorTokensTokenPHIDType.php',
+ 'PhabricatorTokensTransaction' => 'applications/tokens/storage/PhabricatorTokensTransaction.php',
+ 'PhabricatorTokensTransactionComment' => 'applications/tokens/storage/PhabricatorTokensTransactionComment.php',
+ 'PhabricatorTokensTransactionQuery' => 'applications/tokens/query/PhabricatorTokensTransactionQuery.php',
'PhabricatorTooltipUIExample' => 'applications/uiexample/examples/PhabricatorTooltipUIExample.php',
'PhabricatorTransactionChange' => 'applications/transactions/data/PhabricatorTransactionChange.php',
'PhabricatorTransactionRemarkupChange' => 'applications/transactions/data/PhabricatorTransactionRemarkupChange.php',
@@ -6549,6 +6569,7 @@
'PhabricatorBotWhatsNewHandler' => 'PhabricatorBotHandler',
'PhabricatorBritishEnglishTranslation' => 'PhutilTranslation',
'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList',
+ 'PhabricatorBuiltinTokenQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorBulkContentSource' => 'PhabricatorContentSource',
'PhabricatorBusyUIExample' => 'PhabricatorUIExample',
'PhabricatorCacheDAO' => 'PhabricatorLiskDAO',
@@ -7550,6 +7571,7 @@
'PhabricatorObjectHasFileEdgeType' => 'PhabricatorEdgeType',
'PhabricatorObjectHasJiraIssueEdgeType' => 'PhabricatorEdgeType',
'PhabricatorObjectHasSubscriberEdgeType' => 'PhabricatorEdgeType',
+ 'PhabricatorObjectHasTokenEdgeType' => 'PhabricatorEdgeType',
'PhabricatorObjectHasUnsubscriberEdgeType' => 'PhabricatorEdgeType',
'PhabricatorObjectHasWatcherEdgeType' => 'PhabricatorEdgeType',
'PhabricatorObjectListQuery' => 'Phobject',
@@ -8440,11 +8462,15 @@
'PhabricatorTokenDAO',
'PhabricatorPolicyInterface',
),
+ 'PhabricatorTokenArchiveController' => 'PhabricatorTokenController',
'PhabricatorTokenController' => 'PhabricatorController',
'PhabricatorTokenCount' => 'PhabricatorTokenDAO',
'PhabricatorTokenCountQuery' => 'PhabricatorOffsetPagedQuery',
'PhabricatorTokenDAO' => 'PhabricatorLiskDAO',
'PhabricatorTokenDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension',
+ 'PhabricatorTokenEditController' => 'PhabricatorTokenController',
+ 'PhabricatorTokenEditEngine' => 'PhabricatorEditEngine',
+ 'PhabricatorTokenEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorTokenGiveController' => 'PhabricatorTokenController',
'PhabricatorTokenGiven' => array(
'PhabricatorTokenDAO',
@@ -8454,15 +8480,37 @@
'PhabricatorTokenGivenEditor' => 'PhabricatorEditor',
'PhabricatorTokenGivenFeedStory' => 'PhabricatorFeedStory',
'PhabricatorTokenGivenQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'PhabricatorTokenHasObjectEdgeType' => 'PhabricatorEdgeType',
'PhabricatorTokenLeaderController' => 'PhabricatorTokenController',
+ 'PhabricatorTokenListController' => 'PhabricatorTokenController',
'PhabricatorTokenQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorTokenReceiverQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
- 'PhabricatorTokenTokenPHIDType' => 'PhabricatorPHIDType',
+ 'PhabricatorTokenSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorTokenUIEventListener' => 'PhabricatorEventListener',
+ 'PhabricatorTokenViewController' => 'PhabricatorTokenController',
'PhabricatorTokenizerEditField' => 'PhabricatorPHIDListEditField',
'PhabricatorTokensApplication' => 'PhabricatorApplication',
+ 'PhabricatorTokensCreateCapability' => 'PhabricatorPolicyCapability',
'PhabricatorTokensCurtainExtension' => 'PHUICurtainExtension',
+ 'PhabricatorTokensDAO' => 'PhabricatorLiskDAO',
+ 'PhabricatorTokensDefaultEditCapability' => 'PhabricatorPolicyCapability',
+ 'PhabricatorTokensMailReceiver' => 'PhabricatorObjectMailReceiver',
+ 'PhabricatorTokensReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
+ 'PhabricatorTokensSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhabricatorTokensSettingsPanel' => 'PhabricatorSettingsPanel',
+ 'PhabricatorTokensToken' => array(
+ 'PhabricatorTokensDAO',
+ 'PhabricatorPolicyInterface',
+ 'PhabricatorDestructibleInterface',
+ 'PhabricatorSubscribableInterface',
+ 'PhabricatorFlaggableInterface',
+ 'PhabricatorApplicationTransactionInterface',
+ 'PhabricatorConduitResultInterface',
+ ),
+ 'PhabricatorTokensTokenPHIDType' => 'PhabricatorPHIDType',
+ 'PhabricatorTokensTransaction' => 'PhabricatorApplicationTransaction',
+ 'PhabricatorTokensTransactionComment' => 'PhabricatorApplicationTransactionComment',
+ 'PhabricatorTokensTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorTooltipUIExample' => 'PhabricatorUIExample',
'PhabricatorTransactionChange' => 'Phobject',
'PhabricatorTransactionRemarkupChange' => 'PhabricatorTransactionChange',
diff --git a/src/applications/tokens/application/PhabricatorTokensApplication.php b/src/applications/tokens/application/PhabricatorTokensApplication.php
--- a/src/applications/tokens/application/PhabricatorTokensApplication.php
+++ b/src/applications/tokens/application/PhabricatorTokensApplication.php
@@ -7,7 +7,7 @@
}
public function getBaseURI() {
- return '/token/';
+ return '/tokens/';
}
public function getIcon() {
@@ -28,11 +28,35 @@
public function getRoutes() {
return array(
- '/token/' => array(
- '' => 'PhabricatorTokenGivenController',
- 'given/' => 'PhabricatorTokenGivenController',
- 'give/(?<phid>[^/]+)/' => 'PhabricatorTokenGiveController',
- 'leaders/' => 'PhabricatorTokenLeaderController',
+ '/tokens/' => array(
+ '(?:query/(?P<queryKey>[^/]+)/)?'
+ => 'PhabricatorTokenListController',
+ 'archive/(?:(?P<id>\d+)/)?' =>
+ 'PhabricatorTokenArchiveController',
+ 'given/' =>
+ 'PhabricatorTokenGivenController',
+ 'give/(?<phid>[^/]+)/' =>
+ 'PhabricatorTokenGiveController',
+ 'leaders/' =>
+ 'PhabricatorTokenLeaderController',
+ 'view/(?:(?P<id>\d+)/)?'
+ => 'PhabricatorTokenViewController',
+ $this->getEditRoutePattern('edit/')
+ => 'PhabricatorTokenEditController',
+ ),
+ );
+ }
+
+ protected function getCustomCapabilities() {
+ return array(
+ PhabricatorTokensCreateCapability::CAPABILITY => array(
+ 'default' => PhabricatorPolicies::POLICY_ADMIN,
+ 'caption' => pht('Default create policy for tokens.'),
+ ),
+ PhabricatorTokensDefaultEditCapability::CAPABILITY => array(
+ 'default' => PhabricatorPolicies::POLICY_ADMIN,
+ 'caption' => pht('Default edit policy for tokens.'),
+ 'template' => PhabricatorTokensTokenPHIDType::TYPECONST,
),
);
}
diff --git a/src/applications/tokens/capability/PhabricatorTokensCreateCapability.php b/src/applications/tokens/capability/PhabricatorTokensCreateCapability.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/capability/PhabricatorTokensCreateCapability.php
@@ -0,0 +1,16 @@
+<?php
+
+final class PhabricatorTokensCreateCapability
+ extends PhabricatorPolicyCapability {
+
+ const CAPABILITY = 'tokens.default.create';
+
+ public function getCapabilityName() {
+ return pht('Can Create Tokens');
+ }
+
+ public function describeCapabilityRejection() {
+ return pht('You do not have permission to create tokens.');
+ }
+
+}
diff --git a/src/applications/tokens/capability/PhabricatorTokensDefaultEditCapability.php b/src/applications/tokens/capability/PhabricatorTokensDefaultEditCapability.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/capability/PhabricatorTokensDefaultEditCapability.php
@@ -0,0 +1,12 @@
+<?php
+
+final class PhabricatorTokensDefaultEditCapability
+ extends PhabricatorPolicyCapability {
+
+ const CAPABILITY = 'tokens.default.edit';
+
+ public function getCapabilityName() {
+ return pht('Default Edit Tokens');
+ }
+
+}
diff --git a/src/applications/tokens/controller/PhabricatorTokenArchiveController.php b/src/applications/tokens/controller/PhabricatorTokenArchiveController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/controller/PhabricatorTokenArchiveController.php
@@ -0,0 +1,67 @@
+<?php
+
+final class PhabricatorTokenArchiveController
+ extends PhabricatorTokenController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $request->getViewer();
+ $id = $request->getURIData('id');
+
+ $token = id(new PhabricatorTokenQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$token) {
+ return new Aphront404Response();
+ }
+
+ $view_uri = $this->getApplicationURI('view/'.$token->getID().'/');
+
+ if ($request->isFormPost()) {
+ if ($token->isArchived()) {
+ $new_status = PhabricatorTokensToken::STATUS_ACTIVE;
+ } else {
+ $new_status = PhabricatorTokensToken::STATUS_ARCHIVED;
+ }
+
+ $xactions = array();
+
+ $xactions[] = id(new PhabricatorTokensTransaction())
+ ->setTransactionType(PhabricatorTokensTransaction::TYPE_STATUS)
+ ->setNewValue($new_status);
+
+ id(new PhabricatorTokenEditor())
+ ->setActor($viewer)
+ ->setContentSourceFromRequest($request)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true)
+ ->applyTransactions($token, $xactions);
+
+ return id(new AphrontRedirectResponse())->setURI($view_uri);
+ }
+
+ if ($token->isArchived()) {
+ $title = pht('Activate Token');
+ $body = pht('This token will immediately be available for '.
+ 'general tomfoolery.');
+ $button = pht('Activate Token');
+ } else {
+ $title = pht('Archive Token');
+ $body = pht(
+ 'Really? You want to just "get rid" of this token? Kinda harsh.');
+ $button = pht('Archive Token');
+ }
+
+ return $this->newDialog()
+ ->setTitle($title)
+ ->appendChild($body)
+ ->addCancelButton($view_uri)
+ ->addSubmitButton($button);
+ }
+
+}
diff --git a/src/applications/tokens/controller/PhabricatorTokenController.php b/src/applications/tokens/controller/PhabricatorTokenController.php
--- a/src/applications/tokens/controller/PhabricatorTokenController.php
+++ b/src/applications/tokens/controller/PhabricatorTokenController.php
@@ -1,25 +1,4 @@
<?php
-abstract class PhabricatorTokenController extends PhabricatorController {
+abstract class PhabricatorTokenController extends PhabricatorController {}
- protected function buildSideNav() {
- $nav = new AphrontSideNavFilterView();
- $nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
-
- $nav->addLabel(pht('Tokens'));
- $nav->addFilter('given/', pht('Tokens Given'));
- $nav->addFilter('leaders/', pht('Leader Board'));
-
- return $nav;
- }
-
- public function buildApplicationMenu() {
- return $this->buildSideNav()->getMenu();
- }
-
- protected function buildApplicationCrumbs() {
- $crumbs = parent::buildApplicationCrumbs();
- return $crumbs;
- }
-
-}
diff --git a/src/applications/tokens/controller/PhabricatorTokenEditController.php b/src/applications/tokens/controller/PhabricatorTokenEditController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/controller/PhabricatorTokenEditController.php
@@ -0,0 +1,11 @@
+<?php
+
+final class PhabricatorTokenEditController extends PhabricatorTokenController {
+
+ public function handleRequest(AphrontRequest $request) {
+ return id(new PhabricatorTokenEditEngine())
+ ->setController($this)
+ ->buildResponse();
+ }
+
+}
diff --git a/src/applications/tokens/controller/PhabricatorTokenGiveController.php b/src/applications/tokens/controller/PhabricatorTokenGiveController.php
--- a/src/applications/tokens/controller/PhabricatorTokenGiveController.php
+++ b/src/applications/tokens/controller/PhabricatorTokenGiveController.php
@@ -60,7 +60,7 @@
private function buildGiveTokenDialog() {
$viewer = $this->getViewer();
- $tokens = id(new PhabricatorTokenQuery())
+ $tokens = id(new PhabricatorBuiltinTokenQuery())
->setViewer($viewer)
->execute();
diff --git a/src/applications/tokens/controller/PhabricatorTokenGivenController.php b/src/applications/tokens/controller/PhabricatorTokenGivenController.php
--- a/src/applications/tokens/controller/PhabricatorTokenGivenController.php
+++ b/src/applications/tokens/controller/PhabricatorTokenGivenController.php
@@ -30,7 +30,7 @@
$tokens = array();
if ($tokens_given) {
$token_phids = mpull($tokens_given, 'getTokenPHID');
- $tokens = id(new PhabricatorTokenQuery())
+ $tokens = id(new PhabricatorBuiltinTokenQuery())
->setViewer($viewer)
->withPHIDs($token_phids)
->execute();
@@ -62,18 +62,16 @@
->setHeaderText($title)
->setObjectList($list);
- $nav = $this->buildSideNav();
- $nav->setCrumbs(
- $this->buildApplicationCrumbs()
- ->addTextCrumb($title));
- $nav->selectFilter('given/');
-
- $nav->appendChild($box);
- $nav->appendChild($pager);
+ $crumbs = $this->buildApplicationCrumbs();
+ $crumbs->addTextCrumb($title);
return $this->newPage()
->setTitle($title)
- ->appendChild($nav);
+ ->setCrumbs($crumbs)
+ ->appendChild(array(
+ $box,
+ $pager,
+ ));
}
diff --git a/src/applications/tokens/controller/PhabricatorTokenLeaderController.php b/src/applications/tokens/controller/PhabricatorTokenLeaderController.php
--- a/src/applications/tokens/controller/PhabricatorTokenLeaderController.php
+++ b/src/applications/tokens/controller/PhabricatorTokenLeaderController.php
@@ -46,18 +46,16 @@
->setHeaderText($title)
->setObjectList($list);
- $nav = $this->buildSideNav();
- $nav->setCrumbs(
- $this->buildApplicationCrumbs()
- ->addTextCrumb($title));
- $nav->selectFilter('leaders/');
-
- $nav->appendChild($box);
- $nav->appendChild($pager);
+ $crumbs = $this->buildApplicationCrumbs();
+ $crumbs->addTextCrumb($title);
return $this->newPage()
->setTitle($title)
- ->appendChild($nav);
+ ->setCrumbs($crumbs)
+ ->appendChild(array(
+ $box,
+ $pager,
+ ));
}
diff --git a/src/applications/tokens/controller/PhabricatorTokenListController.php b/src/applications/tokens/controller/PhabricatorTokenListController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/controller/PhabricatorTokenListController.php
@@ -0,0 +1,26 @@
+<?php
+
+final class PhabricatorTokenListController
+ extends PhabricatorTokenController {
+
+ public function shouldAllowPublic() {
+ return true;
+ }
+
+ public function handleRequest(AphrontRequest $request) {
+ return id(new PhabricatorTokenSearchEngine())
+ ->setController($this)
+ ->buildResponse();
+ }
+
+ protected function buildApplicationCrumbs() {
+ $crumbs = parent::buildApplicationCrumbs();
+
+ id(new PhabricatorTokenEditEngine())
+ ->setViewer($this->getViewer())
+ ->addActionToCrumbs($crumbs);
+
+ return $crumbs;
+ }
+
+}
diff --git a/src/applications/tokens/controller/PhabricatorTokenViewController.php b/src/applications/tokens/controller/PhabricatorTokenViewController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/controller/PhabricatorTokenViewController.php
@@ -0,0 +1,135 @@
+<?php
+
+final class PhabricatorTokenViewController
+ extends PhabricatorTokenController {
+
+ public function shouldAllowPublic() {
+ return true;
+ }
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $request->getViewer();
+ $id = $request->getURIData('id');
+
+ $token = id(new PhabricatorTokenQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->executeOne();
+ if (!$token) {
+ return new Aphront404Response();
+ }
+
+ $crumbs = $this->buildApplicationCrumbs();
+ $crumbs->addTextCrumb($token->getName());
+ $crumbs->setBorder(true);
+ $title = $token->getName();
+
+ if ($token->isArchived()) {
+ $status_icon = 'fa-ban';
+ $status_color = 'dark';
+ } else {
+ $status_icon = 'fa-check';
+ $status_color = 'bluegrey';
+ }
+ $status_name = idx(
+ PhabricatorTokensToken::getStatusNameMap(),
+ $token->getStatus());
+
+ $header = id(new PHUIHeaderView())
+ ->setHeader($token->getName())
+ ->setUser($viewer)
+ ->setPolicyObject($token)
+ ->setStatus($status_icon, $status_color, $status_name)
+ ->setHeaderIcon('fa-thumbs-up');
+
+ $curtain = $this->buildCurtain($token);
+ $details = $this->buildDetailsView($token);
+
+ $timeline = $this->buildTransactionTimeline(
+ $token,
+ new PhabricatorTokensTransactionQuery());
+
+ $comment_view = id(new PhabricatorTokenEditEngine())
+ ->setViewer($viewer)
+ ->buildEditEngineCommentView($token);
+
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setCurtain($curtain)
+ ->setMainColumn(array(
+ $timeline,
+ $comment_view,
+ ))
+ ->addPropertySection(pht('Description'), $details);
+
+ return $this->newPage()
+ ->setTitle($title)
+ ->setCrumbs($crumbs)
+ ->setPageObjectPHIDs(array($token->getPHID()))
+ ->appendChild($view);
+ }
+
+ private function buildDetailsView(
+ PhabricatorTokensToken $token) {
+ $viewer = $this->getViewer();
+
+ $view = id(new PHUIPropertyListView())
+ ->setUser($viewer);
+
+ // TODO: Show th Token
+ $image = phutil_tag('em', array(), pht('Token goes here'));
+ $view->addProperty(pht('Looks Like'), $image);
+
+ $flavor = $token->getFlavor();
+ if (!$flavor) {
+ $flavor = phutil_tag('em', array(), pht('Flavorless token'));
+ }
+ $view->addProperty(pht('Flavor'), $flavor);
+
+
+ return $view;
+ }
+
+ private function buildCurtain(PhabricatorTokensToken $token) {
+ $viewer = $this->getViewer();
+
+ $can_edit = PhabricatorPolicyFilter::hasCapability(
+ $viewer,
+ $token,
+ PhabricatorPolicyCapability::CAN_EDIT);
+
+ $id = $token->getID();
+ $edit_uri = $this->getApplicationURI("/edit/{$id}/");
+ $archive_uri = $this->getApplicationURI("/archive/{$id}/");
+
+ $curtain = $this->newCurtainView($token);
+
+ $curtain->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Edit Token'))
+ ->setIcon('fa-pencil')
+ ->setDisabled(!$can_edit)
+ ->setHref($edit_uri));
+
+ if ($token->isArchived()) {
+ $curtain->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Activate Token'))
+ ->setIcon('fa-check')
+ ->setDisabled(!$can_edit)
+ ->setWorkflow($can_edit)
+ ->setHref($archive_uri));
+ } else {
+ $curtain->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Archive Token'))
+ ->setIcon('fa-ban')
+ ->setDisabled(!$can_edit)
+ ->setWorkflow($can_edit)
+ ->setHref($archive_uri));
+ }
+
+ return $curtain;
+ }
+
+}
diff --git a/src/applications/tokens/edge/PhabricatorObjectHasTokenEdgeType.php b/src/applications/tokens/edge/PhabricatorObjectHasTokenEdgeType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/edge/PhabricatorObjectHasTokenEdgeType.php
@@ -0,0 +1,103 @@
+<?php
+
+final class PhabricatorObjectHasTokenEdgeType
+ extends PhabricatorEdgeType {
+
+ const EDGECONST = 63;
+
+ public function getInverseEdgeConstant() {
+ return PhabricatorTokenHasObjectEdgeType::EDGECONST;
+ }
+
+ public function shouldWriteInverseTransactions() {
+ return true;
+ }
+
+ public function getTransactionAddString(
+ $actor,
+ $add_count,
+ $add_edges) {
+
+ return pht(
+ '%s added %s token(s): %s.',
+ $actor,
+ $add_count,
+ $add_edges);
+ }
+
+ public function getTransactionRemoveString(
+ $actor,
+ $rem_count,
+ $rem_edges) {
+
+ return pht(
+ '%s revoked %s token(s): %s.',
+ $actor,
+ $rem_count,
+ $rem_edges);
+ }
+
+ public function getTransactionEditString(
+ $actor,
+ $total_count,
+ $add_count,
+ $add_edges,
+ $rem_count,
+ $rem_edges) {
+
+ return pht(
+ '%s edited token(s), added %s: %s; revoked %s: %s.',
+ $actor,
+ $add_count,
+ $add_edges,
+ $rem_count,
+ $rem_edges);
+ }
+
+ public function getFeedAddString(
+ $actor,
+ $object,
+ $add_count,
+ $add_edges) {
+
+ return pht(
+ '%s added %s token(s) for %s: %s.',
+ $actor,
+ $add_count,
+ $object,
+ $add_edges);
+ }
+
+ public function getFeedRemoveString(
+ $actor,
+ $object,
+ $rem_count,
+ $rem_edges) {
+
+ return pht(
+ '%s revoked %s token(s) for %s: %s.',
+ $actor,
+ $rem_count,
+ $object,
+ $rem_edges);
+ }
+
+ public function getFeedEditString(
+ $actor,
+ $object,
+ $total_count,
+ $add_count,
+ $add_edges,
+ $rem_count,
+ $rem_edges) {
+
+ return pht(
+ '%s edited token(s) for %s, added %s: %s; revoked %s: %s.',
+ $actor,
+ $object,
+ $add_count,
+ $add_edges,
+ $rem_count,
+ $rem_edges);
+ }
+}
diff --git a/src/applications/tokens/edge/PhabricatorTokenHasObjectEdgeType.php b/src/applications/tokens/edge/PhabricatorTokenHasObjectEdgeType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/edge/PhabricatorTokenHasObjectEdgeType.php
@@ -0,0 +1,103 @@
+<?php
+
+final class PhabricatorTokenHasObjectEdgeType
+ extends PhabricatorEdgeType {
+
+ const EDGECONST = 62;
+
+ public function getInverseEdgeConstant() {
+ return PhabricatorObjectHasTokenEdgeType::EDGECONST;
+ }
+
+ public function shouldWriteInverseTransactions() {
+ return true;
+ }
+
+ public function getTransactionAddString(
+ $actor,
+ $add_count,
+ $add_edges) {
+
+ return pht(
+ '%s awarded %s objects(s): %s.',
+ $actor,
+ $add_count,
+ $add_edges);
+ }
+
+ public function getTransactionRemoveString(
+ $actor,
+ $rem_count,
+ $rem_edges) {
+
+ return pht(
+ '%s revoked %s objects(s): %s.',
+ $actor,
+ $rem_count,
+ $rem_edges);
+ }
+
+ public function getTransactionEditString(
+ $actor,
+ $total_count,
+ $add_count,
+ $add_edges,
+ $rem_count,
+ $rem_edges) {
+
+ return pht(
+ '%s edited object(s), awarded %s: %s; revoked %s: %s.',
+ $actor,
+ $add_count,
+ $add_edges,
+ $rem_count,
+ $rem_edges);
+ }
+
+ public function getFeedAddString(
+ $actor,
+ $object,
+ $add_count,
+ $add_edges) {
+
+ return pht(
+ '%s awarded %s object(s) for %s: %s.',
+ $actor,
+ $add_count,
+ $object,
+ $add_edges);
+ }
+
+ public function getFeedRemoveString(
+ $actor,
+ $object,
+ $rem_count,
+ $rem_edges) {
+
+ return pht(
+ '%s revoked %s object(s) for %s: %s.',
+ $actor,
+ $rem_count,
+ $object,
+ $rem_edges);
+ }
+
+ public function getFeedEditString(
+ $actor,
+ $object,
+ $total_count,
+ $add_count,
+ $add_edges,
+ $rem_count,
+ $rem_edges) {
+
+ return pht(
+ '%s edited object(s) for %s, awarded %s: %s; revoked %s: %s.',
+ $actor,
+ $object,
+ $add_count,
+ $add_edges,
+ $rem_count,
+ $rem_edges);
+ }
+}
diff --git a/src/applications/tokens/editor/PhabricatorTokenEditEngine.php b/src/applications/tokens/editor/PhabricatorTokenEditEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/editor/PhabricatorTokenEditEngine.php
@@ -0,0 +1,90 @@
+<?php
+
+final class PhabricatorTokenEditEngine
+ extends PhabricatorEditEngine {
+
+ const ENGINECONST = 'phabricator.tokens.token';
+
+ public function getEngineName() {
+ return pht('Tokens');
+ }
+
+ public function getEngineApplicationClass() {
+ return 'PhabricatorTokensApplication';
+ }
+
+ public function getSummaryHeader() {
+ return pht('Configure Tokens Forms');
+ }
+
+ public function getSummaryText() {
+ return pht('Configure how tokens are created and edited.');
+ }
+
+ protected function newEditableObject() {
+ return PhabricatorTokensToken::initializeNewToken($this->getViewer());
+ }
+
+ protected function newObjectQuery() {
+ return id(new PhabricatorTokenQuery());
+ }
+
+ protected function getObjectCreateTitleText($object) {
+ return pht('Create New Token');
+ }
+
+ protected function getObjectEditTitleText($object) {
+ return pht('Edit %s', $object->getName());
+ }
+
+ protected function getObjectEditShortText($object) {
+ return $object->getName();
+ }
+
+ protected function getObjectCreateShortText() {
+ return pht('Create Token');
+ }
+
+ protected function getObjectName() {
+ return pht('Token');
+ }
+
+ protected function getObjectCreateCancelURI($object) {
+ return $this->getApplication()->getApplicationURI('/');
+ }
+
+ protected function getEditorURI() {
+ return $this->getApplication()->getApplicationURI('/edit/');
+ }
+
+ protected function getObjectViewURI($object) {
+ return $object->getViewURI();
+ }
+
+ protected function getCreateNewObjectPolicy() {
+ return $this->getApplication()->getPolicy(
+ PhabricatorTokensCreateCapability::CAPABILITY);
+ }
+
+ protected function buildCustomEditFields($object) {
+ return array(
+ id(new PhabricatorTextEditField())
+ ->setKey('name')
+ ->setLabel(pht('Name'))
+ ->setDescription(pht('Token name.'))
+ ->setConduitDescription(pht('Retitle the token.'))
+ ->setConduitTypeDescription(pht('New token name.'))
+ ->setTransactionType(PhabricatorTokensTransaction::TYPE_NAME)
+ ->setValue($object->getName()),
+ id(new PhabricatorTextEditField())
+ ->setKey('flavor')
+ ->setLabel(pht('Flavor'))
+ ->setDescription(pht('Token flavor text.'))
+ ->setConduitDescription(pht('Change the token flavor.'))
+ ->setConduitTypeDescription(pht('New token flavor.'))
+ ->setTransactionType(PhabricatorTokensTransaction::TYPE_FLAVOR)
+ ->setValue($object->getFlavor()),
+ );
+ }
+
+}
diff --git a/src/applications/tokens/editor/PhabricatorTokenEditor.php b/src/applications/tokens/editor/PhabricatorTokenEditor.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/editor/PhabricatorTokenEditor.php
@@ -0,0 +1,191 @@
+<?php
+
+final class PhabricatorTokenEditor
+ extends PhabricatorApplicationTransactionEditor {
+
+ public function getEditorApplicationClass() {
+ return 'PhabricatorTokensApplication';
+ }
+
+ public function getEditorObjectsDescription() {
+ return pht('Phabricator Tokens');
+ }
+
+ public function getTransactionTypes() {
+ $types = parent::getTransactionTypes();
+
+ $types[] = PhabricatorTokensTransaction::TYPE_NAME;
+ $types[] = PhabricatorTokensTransaction::TYPE_FLAVOR;
+ $types[] = PhabricatorTokensTransaction::TYPE_STATUS;
+ $types[] = PhabricatorTokensTransaction::TYPE_IMAGE;
+
+ $types[] = PhabricatorTransactions::TYPE_COMMENT;
+ $types[] = PhabricatorTransactions::TYPE_EDGE;
+ $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
+
+ return $types;
+ }
+
+ protected function getCustomTransactionOldValue(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case PhabricatorTokensTransaction::TYPE_NAME:
+ return $object->getName();
+ case PhabricatorTokensTransaction::TYPE_FLAVOR:
+ return $object->getFlavor();
+ case PhabricatorTokensTransaction::TYPE_STATUS:
+ return $object->getStatus();
+ case PhabricatorTokensTransaction::TYPE_IMAGE:
+ return $object->getImage();
+ }
+ }
+
+ protected function getCustomTransactionNewValue(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case PhabricatorTokensTransaction::TYPE_NAME:
+ case PhabricatorTokensTransaction::TYPE_FLAVOR:
+ case PhabricatorTokensTransaction::TYPE_STATUS:
+ case PhabricatorTokensTransaction::TYPE_IMAGE:
+ return $xaction->getNewValue();
+ }
+ }
+
+ protected function applyCustomInternalTransaction(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case PhabricatorTokensTransaction::TYPE_NAME:
+ return $object->setName($xaction->getNewValue());
+ case PhabricatorTokensTransaction::TYPE_FLAVOR:
+ return $object->setFlavor($xaction->getNewValue());
+ case PhabricatorTokensTransaction::TYPE_STATUS:
+ return $object->setStatus($xaction->getNewValue());
+ case PhabricatorTokensTransaction::TYPE_IMAGE:
+ return $object->setImage($xaction->getNewValue());
+ }
+
+ return parent::applyCustomInternalTransaction($object, $xaction);
+ }
+
+ protected function applyCustomExternalTransaction(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+
+ switch ($xaction->getTransactionType()) {
+ case PhabricatorTokensTransaction::TYPE_NAME:
+ case PhabricatorTokensTransaction::TYPE_FLAVOR:
+ case PhabricatorTokensTransaction::TYPE_STATUS:
+ case PhabricatorTokensTransaction::TYPE_IMAGE:
+ return;
+ }
+
+ return parent::applyCustomExternalTransaction($object, $xaction);
+ }
+
+ protected function validateTransaction(
+ PhabricatorLiskDAO $object,
+ $type,
+ array $xactions) {
+
+ $errors = parent::validateTransaction($object, $type, $xactions);
+
+ switch ($type) {
+ case PhabricatorTokensTransaction::TYPE_NAME:
+ $missing = $this->validateIsEmptyTextField(
+ $object->getName(),
+ $xactions);
+
+ if ($missing) {
+ $error = new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('Required'),
+ pht('Name is required.'),
+ nonempty(last($xactions), null));
+
+ $error->setIsMissingFieldError(true);
+ $errors[] = $error;
+ }
+ break;
+ }
+ return $errors;
+ }
+
+ protected function shouldSendMail(
+ PhabricatorLiskDAO $object,
+ array $xactions) {
+ return true;
+ }
+
+ protected function shouldPublishFeedStory(
+ PhabricatorLiskDAO $object,
+ array $xactions) {
+ return true;
+ }
+
+ protected function getMailTo(PhabricatorLiskDAO $object) {
+ $phids = array();
+ $phids[] = $this->requireActor()->getPHID();
+ $phids[] = $object->getCreatorPHID();
+
+ return $phids;
+ }
+
+ protected function buildMailTemplate(PhabricatorLiskDAO $object) {
+ $phid = $object->getPHID();
+ $name = $object->getName();
+
+ return id(new PhabricatorMetaMTAMail())
+ ->setSubject($name)
+ ->addHeader('Thread-Topic', $phid);
+ }
+
+ protected function buildReplyHandler(PhabricatorLiskDAO $object) {
+ return id(new PhabricatorTokensReplyHandler())
+ ->setMailReceiver($object);
+ }
+
+ protected function buildMailBody(
+ PhabricatorLiskDAO $object,
+ array $xactions) {
+
+ $body = parent::buildMailBody($object, $xactions);
+
+ $body->addLinkSection(
+ pht('TOKEN DETAIL'),
+ PhabricatorEnv::getProductionURI($object->getViewURI()));
+
+ return $body;
+ }
+
+ public function getMailTagsMap() {
+ return array(
+ PhabricatorTokensTransaction::MAILTAG_DETAILS =>
+ pht("A token's details change."),
+ PhabricatorTokensTransaction::MAILTAG_SUBSCRIBERS =>
+ pht("A token's subscribers change."),
+ PhabricatorTokensTransaction::MAILTAG_OTHER =>
+ pht('Other token activity not listed above occurs.'),
+ );
+ }
+
+ protected function getMailSubjectPrefix() {
+ return '[Tokens]';
+ }
+
+ protected function supportsSearch() {
+ return false;
+ }
+
+ protected function shouldApplyHeraldRules(
+ PhabricatorLiskDAO $object,
+ array $xactions) {
+ return false;
+ }
+
+}
diff --git a/src/applications/tokens/editor/PhabricatorTokenGivenEditor.php b/src/applications/tokens/editor/PhabricatorTokenGivenEditor.php
--- a/src/applications/tokens/editor/PhabricatorTokenGivenEditor.php
+++ b/src/applications/tokens/editor/PhabricatorTokenGivenEditor.php
@@ -110,7 +110,7 @@
}
private function validateToken($token_phid) {
- $token = id(new PhabricatorTokenQuery())
+ $token = id(new PhabricatorBuiltinTokenQuery())
->setViewer($this->requireActor())
->withPHIDs(array($token_phid))
->executeOne();
diff --git a/src/applications/tokens/event/PhabricatorTokenUIEventListener.php b/src/applications/tokens/event/PhabricatorTokenUIEventListener.php
--- a/src/applications/tokens/event/PhabricatorTokenUIEventListener.php
+++ b/src/applications/tokens/event/PhabricatorTokenUIEventListener.php
@@ -46,13 +46,13 @@
if (!$current) {
$token_action = id(new PhabricatorActionView())
->setWorkflow(true)
- ->setHref('/token/give/'.$object->getPHID().'/')
+ ->setHref('/tokens/give/'.$object->getPHID().'/')
->setName(pht('Award Token'))
->setIcon('fa-trophy');
} else {
$token_action = id(new PhabricatorActionView())
->setWorkflow(true)
- ->setHref('/token/give/'.$object->getPHID().'/')
+ ->setHref('/tokens/give/'.$object->getPHID().'/')
->setName(pht('Rescind Token'))
->setIcon('fa-trophy');
}
diff --git a/src/applications/tokens/mail/PhabricatorTokensMailReceiver.php b/src/applications/tokens/mail/PhabricatorTokensMailReceiver.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/mail/PhabricatorTokensMailReceiver.php
@@ -0,0 +1,28 @@
+<?php
+
+final class PhabricatorTokensMailReceiver
+ extends PhabricatorObjectMailReceiver {
+
+ public function isEnabled() {
+ return PhabricatorApplication::isClassInstalled(
+ 'PhabricatorTokensApplication');
+ }
+
+ protected function getObjectPattern() {
+ return 'TOKN[1-9]\d*';
+ }
+
+ protected function loadObject($pattern, PhabricatorUser $viewer) {
+ $id = (int)substr($pattern, 4);
+
+ return id(new PhabricatorTokenQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->executeOne();
+ }
+
+ protected function getTransactionReplyHandler() {
+ return new PhabricatorTokensReplyHandler();
+ }
+
+}
diff --git a/src/applications/tokens/mail/PhabricatorTokensReplyHandler.php b/src/applications/tokens/mail/PhabricatorTokensReplyHandler.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/mail/PhabricatorTokensReplyHandler.php
@@ -0,0 +1,16 @@
+<?php
+
+final class PhabricatorTokensReplyHandler
+ extends PhabricatorApplicationTransactionReplyHandler {
+
+ public function validateMailReceiver($mail_receiver) {
+ if (!($mail_receiver instanceof PhabricatorTokensToken)) {
+ throw new Exception(pht('Mail receiver is not a %s!', 'Tokens'));
+ }
+ }
+
+ public function getObjectPrefix() {
+ return 'TOKN';
+ }
+
+}
diff --git a/src/applications/tokens/phid/PhabricatorTokenTokenPHIDType.php b/src/applications/tokens/phid/PhabricatorTokensTokenPHIDType.php
rename from src/applications/tokens/phid/PhabricatorTokenTokenPHIDType.php
rename to src/applications/tokens/phid/PhabricatorTokensTokenPHIDType.php
--- a/src/applications/tokens/phid/PhabricatorTokenTokenPHIDType.php
+++ b/src/applications/tokens/phid/PhabricatorTokensTokenPHIDType.php
@@ -1,6 +1,6 @@
<?php
-final class PhabricatorTokenTokenPHIDType extends PhabricatorPHIDType {
+final class PhabricatorTokensTokenPHIDType extends PhabricatorPHIDType {
const TYPECONST = 'TOKN';
@@ -9,7 +9,7 @@
}
public function newObject() {
- return new PhabricatorToken();
+ return new PhabricatorTokensToken();
}
public function getPHIDTypeApplicationClass() {
diff --git a/src/applications/tokens/query/PhabricatorTokenQuery.php b/src/applications/tokens/query/PhabricatorBuiltinTokenQuery.php
copy from src/applications/tokens/query/PhabricatorTokenQuery.php
copy to src/applications/tokens/query/PhabricatorBuiltinTokenQuery.php
--- a/src/applications/tokens/query/PhabricatorTokenQuery.php
+++ b/src/applications/tokens/query/PhabricatorBuiltinTokenQuery.php
@@ -1,6 +1,6 @@
<?php
-final class PhabricatorTokenQuery
+final class PhabricatorBuiltinTokenQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $phids;
@@ -12,7 +12,6 @@
protected function loadPage() {
$tokens = $this->getBuiltinTokens();
-
if ($this->phids) {
$map = array_fill_keys($this->phids, true);
foreach ($tokens as $key => $token) {
@@ -21,7 +20,6 @@
}
}
}
-
return $tokens;
}
@@ -44,24 +42,19 @@
array('misc-3', pht('Baby Tequila')),
array('misc-4', pht('The World Burns')),
);
-
- $type = PhabricatorTokenTokenPHIDType::TYPECONST;
-
+ $type = PhabricatorTokensTokenPHIDType::TYPECONST;
$tokens = array();
foreach ($specs as $id => $spec) {
list($image, $name) = $spec;
-
$token = id(new PhabricatorToken())
->setID($id)
->setName($name)
->setPHID('PHID-'.$type.'-'.$image);
$tokens[] = $token;
}
-
return $tokens;
}
-
public function getQueryApplicationClass() {
return 'PhabricatorTokensApplication';
}
diff --git a/src/applications/tokens/query/PhabricatorTokenGivenQuery.php b/src/applications/tokens/query/PhabricatorTokenGivenQuery.php
--- a/src/applications/tokens/query/PhabricatorTokenGivenQuery.php
+++ b/src/applications/tokens/query/PhabricatorTokenGivenQuery.php
@@ -88,7 +88,7 @@
$token_phids = mpull($results, 'getTokenPHID');
- $tokens = id(new PhabricatorTokenQuery())
+ $tokens = id(new PhabricatorBuiltinTokenQuery())
->setViewer($viewer)
->withPHIDs($token_phids)
->execute();
diff --git a/src/applications/tokens/query/PhabricatorTokenQuery.php b/src/applications/tokens/query/PhabricatorTokenQuery.php
--- a/src/applications/tokens/query/PhabricatorTokenQuery.php
+++ b/src/applications/tokens/query/PhabricatorTokenQuery.php
@@ -3,26 +3,64 @@
final class PhabricatorTokenQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
+ private $ids;
private $phids;
+ private $statuses;
+
+ private $needImages;
+
+ public function withIDs(array $ids) {
+ $this->ids = $ids;
+ return $this;
+ }
public function withPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
+ public function withStatuses(array $statuses) {
+ $this->statuses = $statuses;
+ return $this;
+ }
+
protected function loadPage() {
- $tokens = $this->getBuiltinTokens();
-
- if ($this->phids) {
- $map = array_fill_keys($this->phids, true);
- foreach ($tokens as $key => $token) {
- if (empty($map[$token->getPHID()])) {
- unset($tokens[$key]);
- }
- }
+ return $this->loadStandardPage($this->newResultObject());
+ }
+
+ public function newResultObject() {
+ return new PhabricatorTokensToken();
+ }
+
+ protected function getPrimaryTableAlias() {
+ return 'tokens_token';
+ }
+
+ protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
+ $where = parent::buildWhereClauseParts($conn);
+
+ if ($this->ids !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'id IN (%Ld)',
+ $this->ids);
}
- return $tokens;
+ if ($this->phids !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'phid IN (%Ls)',
+ $this->phids);
+ }
+
+ if ($this->statuses !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'status IN (%Ls)',
+ $this->statuses);
+ }
+
+ return $where;
}
private function getBuiltinTokens() {
@@ -45,7 +83,7 @@
array('misc-4', pht('The World Burns')),
);
- $type = PhabricatorTokenTokenPHIDType::TYPECONST;
+ $type = PhabricatorTokensTokenPHIDType::TYPECONST;
$tokens = array();
foreach ($specs as $id => $spec) {
diff --git a/src/applications/tokens/query/PhabricatorTokenSearchEngine.php b/src/applications/tokens/query/PhabricatorTokenSearchEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/query/PhabricatorTokenSearchEngine.php
@@ -0,0 +1,131 @@
+<?php
+
+final class PhabricatorTokenSearchEngine
+ extends PhabricatorApplicationSearchEngine {
+
+ public function getResultTypeDescription() {
+ return pht('Token');
+ }
+
+ public function getApplicationClassName() {
+ return 'PhabricatorTokensApplication';
+ }
+
+ public function newQuery() {
+ return new PhabricatorTokenQuery();
+ }
+
+ protected function buildCustomSearchFields() {
+ return array(
+ id(new PhabricatorSearchCheckboxesField())
+ ->setKey('statuses')
+ ->setLabel(pht('Status'))
+ ->setOptions(
+ id(new PhabricatorTokensToken())
+ ->getStatusNameMap()),
+ );
+ }
+
+ protected function buildQueryFromParameters(array $map) {
+ $query = $this->newQuery();
+
+ if ($map['statuses']) {
+ $query->withStatuses($map['statuses']);
+ }
+
+ return $query;
+ }
+
+ protected function getURI($path) {
+ return '/tokens/'.$path;
+ }
+
+ protected function getBuiltinQueryNames() {
+ $names = array();
+
+ $names['open'] = pht('Active Tokens');
+ $names['all'] = pht('All Tokens');
+
+ return $names;
+ }
+
+ public function buildSavedQueryFromBuiltin($query_key) {
+ $query = $this->newSavedQuery();
+ $query->setQueryKey($query_key);
+
+ switch ($query_key) {
+ case 'all':
+ return $query;
+ case 'open':
+ return $query->setParameter(
+ 'statuses',
+ array(
+ PhabricatorTokensToken::STATUS_ACTIVE,
+ ));
+ }
+
+ return parent::buildSavedQueryFromBuiltin($query_key);
+ }
+
+ protected function getRequiredHandlePHIDsForResultList(
+ array $tokens,
+ PhabricatorSavedQuery $query) {
+
+ $phids = array();
+
+ return $phids;
+ }
+
+ protected function renderResultList(
+ array $tokens,
+ PhabricatorSavedQuery $query,
+ array $handles) {
+ assert_instances_of($tokens, 'PhabricatorTokensToken');
+
+ $viewer = $this->requireViewer();
+
+ $list = id(new PHUIObjectItemListView());
+ foreach ($tokens as $token) {
+
+ $item = id(new PHUIObjectItemView())
+ ->setHeader($token->getName())
+ ->setHref('/tokens/view/'.$token->getID().'/')
+ ->addAttribute($token->getFlavor());
+
+ if ($token->isArchived()) {
+ $item->setDisabled(true);
+ $item->addIcon('fa-ban', pht('Archived'));
+ }
+
+ $list->addItem($item);
+ }
+
+ $result = new PhabricatorApplicationSearchResultView();
+ $result->setObjectList($list);
+ $result->setNoDataString(pht('No tokens found.'));
+
+ return $result;
+
+ }
+
+ protected function getNewUserBody() {
+ $create_button = id(new PHUIButtonView())
+ ->setTag('a')
+ ->setText(pht('Create a Token'))
+ ->setHref('/tokens/edit/')
+ ->setColor(PHUIButtonView::GREEN);
+
+ $icon = $this->getApplication()->getIcon();
+ $app_name = $this->getApplication()->getName();
+ $view = id(new PHUIBigInfoView())
+ ->setIcon($icon)
+ ->setTitle(pht('Welcome to %s', $app_name))
+ ->setDescription(
+ pht('Tokens let you award and distinguish objects and comments '.
+ 'throughout your instance.'))
+ ->addAction($create_button);
+
+ return $view;
+ }
+
+}
diff --git a/src/applications/tokens/query/PhabricatorTokensTransactionQuery.php b/src/applications/tokens/query/PhabricatorTokensTransactionQuery.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/query/PhabricatorTokensTransactionQuery.php
@@ -0,0 +1,10 @@
+<?php
+
+final class PhabricatorTokensTransactionQuery
+ extends PhabricatorApplicationTransactionQuery {
+
+ public function getTemplateApplicationTransaction() {
+ return new PhabricatorTokensTransaction();
+ }
+
+}
diff --git a/src/applications/tokens/storage/PhabricatorTokensDAO.php b/src/applications/tokens/storage/PhabricatorTokensDAO.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/storage/PhabricatorTokensDAO.php
@@ -0,0 +1,9 @@
+<?php
+
+abstract class PhabricatorTokensDAO extends PhabricatorLiskDAO {
+
+ public function getApplicationName() {
+ return 'tokens';
+ }
+
+}
diff --git a/src/applications/tokens/storage/PhabricatorTokensSchemaSpec.php b/src/applications/tokens/storage/PhabricatorTokensSchemaSpec.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/storage/PhabricatorTokensSchemaSpec.php
@@ -0,0 +1,10 @@
+<?php
+
+final class PhabricatorTokensSchemaSpec
+ extends PhabricatorConfigSchemaSpec {
+
+ public function buildSchemata() {
+ $this->buildEdgeSchemata(new PhabricatorTokensToken());
+ }
+
+}
diff --git a/src/applications/tokens/storage/PhabricatorTokensToken.php b/src/applications/tokens/storage/PhabricatorTokensToken.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/storage/PhabricatorTokensToken.php
@@ -0,0 +1,211 @@
+<?php
+
+final class PhabricatorTokensToken extends PhabricatorTokensDAO
+ implements
+ PhabricatorPolicyInterface,
+ PhabricatorDestructibleInterface,
+ PhabricatorSubscribableInterface,
+ PhabricatorFlaggableInterface,
+ PhabricatorApplicationTransactionInterface,
+ PhabricatorConduitResultInterface {
+
+ protected $name;
+ protected $flavor;
+ protected $status;
+ protected $creatorPHID;
+ protected $editPolicy;
+ protected $mailKey;
+ protected $tokenImagePHID;
+
+ const STATUS_ACTIVE = 'active';
+ const STATUS_ARCHIVED = 'archived';
+
+ protected function getConfiguration() {
+ return array(
+ self::CONFIG_AUX_PHID => true,
+ self::CONFIG_SERIALIZATION => array(
+ 'configData' => self::SERIALIZATION_JSON,
+ ),
+ self::CONFIG_COLUMN_SCHEMA => array(
+ 'name' => 'text64',
+ 'flavor' => 'text128',
+ 'status' => 'text32',
+ 'tokenImagePHID' => 'phid',
+ 'mailKey' => 'bytes20',
+ ),
+ self::CONFIG_KEY_SCHEMA => array(
+ 'key_creator' => array(
+ 'columns' => array('creatorPHID', 'dateModified'),
+ ),
+ ),
+ ) + parent::getConfiguration();
+ }
+
+ public function generatePHID() {
+ return PhabricatorPHID::generateNewPHID(
+ PhabricatorTokensTokenPHIDType::TYPECONST);
+ }
+
+ public static function initializeNewToken(PhabricatorUser $actor) {
+ $app = id(new PhabricatorApplicationQuery())
+ ->setViewer($actor)
+ ->withClasses(array('PhabricatorTokensApplication'))
+ ->executeOne();
+
+ $edit_policy =
+ $app->getPolicy(PhabricatorTokensDefaultEditCapability::CAPABILITY);
+
+ $token = id(new self())
+ ->setCreatorPHID($actor->getPHID())
+ ->setStatus(self::STATUS_ACTIVE)
+ ->setEditPolicy($edit_policy)
+ ->setTokenImagePHID('');
+ return $token;
+ }
+
+ public function isArchived() {
+ return ($this->getStatus() == self::STATUS_ARCHIVED);
+ }
+
+ public static function getStatusNameMap() {
+ return array(
+ self::STATUS_ACTIVE => pht('Active'),
+ self::STATUS_ARCHIVED => pht('Archived'),
+ );
+ }
+
+ public function getTokenImageURI() {
+ return $this->getTokenImageFile()->getBestURI();
+ }
+
+ public function attachTokenImageFile(PhabricatorFile $file) {
+ $this->tokenImageFile = $file;
+ return $this;
+ }
+
+ public function getTokenImageFile() {
+ return $this->assertAttached($this->tokenImageFile);
+ }
+
+ public function getViewURI() {
+ return '/tokens/view/'.$this->getID().'/';
+ }
+
+ public function save() {
+ if (!$this->getMailKey()) {
+ $this->setMailKey(Filesystem::readRandomCharacters(20));
+ }
+ return parent::save();
+ }
+
+
+/* -( PhabricatorPolicyInterface Implementation )-------------------------- */
+
+
+ public function getCapabilities() {
+ return array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ );
+ }
+
+ public function getPolicy($capability) {
+ switch ($capability) {
+ case PhabricatorPolicyCapability::CAN_VIEW:
+ return PhabricatorPolicies::getMostOpenPolicy();
+ case PhabricatorPolicyCapability::CAN_EDIT:
+ return $this->getEditPolicy();
+ }
+ }
+
+ public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
+ return false;
+ }
+
+ public function describeAutomaticCapability($capability) {
+ return null;
+ }
+
+
+/* -( PhabricatorDestructibleInterface )----------------------------------- */
+
+ public function destroyObjectPermanently(
+ PhabricatorDestructionEngine $engine) {
+
+ $this->openTransaction();
+
+ $tokens = id(new self())
+ ->loadAllWhere('tokenPHID = %s', $this->getPHID());
+ foreach ($tokens as $token) {
+ $token->delete();
+ }
+ $this->delete();
+
+ $this->saveTransaction();
+ }
+
+
+/* -( PhabricatorApplicationTransactionInterface )------------------------- */
+
+
+ public function getApplicationTransactionEditor() {
+ return new PhabricatorTokenEditor();
+ }
+
+ public function getApplicationTransactionObject() {
+ return $this;
+ }
+
+ public function getApplicationTransactionTemplate() {
+ return new PhabricatorTokensTransaction();
+ }
+
+ public function willRenderTimeline(
+ PhabricatorApplicationTransactionView $timeline,
+ AphrontRequest $request) {
+ return $timeline;
+ }
+
+
+/* -( PhabricatorSubscribableInterface Implementation )-------------------- */
+
+
+ public function isAutomaticallySubscribed($phid) {
+ return ($this->creatorPHID == $phid);
+ }
+
+
+/* -( PhabricatorConduitResultInterface )---------------------------------- */
+
+
+ public function getFieldSpecificationsForConduit() {
+ return array(
+ id(new PhabricatorConduitSearchFieldSpecification())
+ ->setKey('name')
+ ->setType('string')
+ ->setDescription(pht('The name of the token.')),
+ id(new PhabricatorConduitSearchFieldSpecification())
+ ->setKey('flavor')
+ ->setType('string')
+ ->setDescription(pht('Token flavor.')),
+ id(new PhabricatorConduitSearchFieldSpecification())
+ ->setKey('status')
+ ->setType('string')
+ ->setDescription(pht('Archived or active status.')),
+ );
+ }
+
+ public function getFieldValuesForConduit() {
+ return array(
+ 'name' => $this->getName(),
+ 'flavor' => $this->getFlavor(),
+ 'status' => $this->getStatus(),
+ );
+ }
+
+ public function getConduitSearchAttachments() {
+ return array();
+ }
+
+
+}
diff --git a/src/applications/tokens/storage/PhabricatorTokensTransaction.php b/src/applications/tokens/storage/PhabricatorTokensTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/storage/PhabricatorTokensTransaction.php
@@ -0,0 +1,154 @@
+<?php
+
+final class PhabricatorTokensTransaction
+ extends PhabricatorApplicationTransaction {
+
+ const TYPE_NAME = 'tokens.token.name';
+ const TYPE_FLAVOR = 'tokens.token.flavor';
+ const TYPE_IMAGE = 'tokens.token.image';
+ const TYPE_STATUS = 'tokens.token.status';
+
+ const MAILTAG_DETAILS = 'tokens.token.details';
+ const MAILTAG_COMMENT = 'tokens.token.comment';
+ const MAILTAG_OTHER = 'tokens.token.other';
+
+ public function getApplicationName() {
+ return 'tokens';
+ }
+
+ public function getApplicationTransactionType() {
+ return PhabricatorTokensTokenPHIDType::TYPECONST;
+ }
+
+ public function getApplicationTransactionCommentObject() {
+ return new PhabricatorTokensTransactionComment();
+ }
+
+
+ public function getTitle() {
+ $author_phid = $this->getAuthorPHID();
+ $object_phid = $this->getObjectPHID();
+
+ $old = $this->getOldValue();
+ $new = $this->getNewValue();
+
+ $type = $this->getTransactionType();
+ switch ($type) {
+ case self::TYPE_NAME:
+ if ($old === null) {
+ return pht(
+ '%s created this token.',
+ $this->renderHandleLink($author_phid));
+ } else {
+ return pht(
+ '%s renamed this token from "%s" to "%s".',
+ $this->renderHandleLink($author_phid),
+ $old,
+ $new);
+ }
+ break;
+ case self::TYPE_FLAVOR:
+ if ($old === null) {
+ return pht(
+ '%s set the flavor text for this token.',
+ $this->renderHandleLink($author_phid));
+ } else {
+ return pht(
+ '%s updated the flavor text for this token.',
+ $this->renderHandleLink($author_phid));
+ }
+ break;
+ case self::TYPE_STATUS:
+ switch ($new) {
+ case PhabricatorTokensToken::STATUS_ACTIVE:
+ return pht(
+ '%s activated this token.',
+ $this->renderHandleLink($author_phid));
+ case PhabricatorTokensToken::STATUS_ARCHIVED:
+ return pht(
+ '%s archived this token.',
+ $this->renderHandleLink($author_phid));
+ }
+ break;
+ case self::TYPE_IMAGE:
+ return pht(
+ '%s updated the image for this token.',
+ $this->renderHandleLink($author_phid));
+ break;
+ }
+
+ return parent::getTitle();
+ }
+
+ public function getTitleForFeed() {
+ $author_phid = $this->getAuthorPHID();
+ $object_phid = $this->getObjectPHID();
+
+ $old = $this->getOldValue();
+ $new = $this->getNewValue();
+
+ $type = $this->getTransactionType();
+ switch ($type) {
+ case self::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 self::TYPE_FLAVOR:
+ return pht(
+ '%s updated the flavor text for %s.',
+ $this->renderHandleLink($author_phid),
+ $this->renderHandleLink($object_phid));
+ case self::TYPE_IMAGE:
+ return pht(
+ '%s updated the image for %s.',
+ $this->renderHandleLink($author_phid),
+ $this->renderHandleLink($object_phid));
+ case self::TYPE_STATUS:
+ switch ($new) {
+ case PhabricatorTokensToken::STATUS_ACTIVE:
+ return pht(
+ '%s activated %s.',
+ $this->renderHandleLink($author_phid),
+ $this->renderHandleLink($object_phid));
+ case PhabricatorTokensToken::STATUS_ARCHIVED:
+ return pht(
+ '%s archived %s.',
+ $this->renderHandleLink($author_phid),
+ $this->renderHandleLink($object_phid));
+ }
+ break;
+ }
+
+ return parent::getTitleForFeed();
+ }
+
+ public function getMailTags() {
+ $tags = parent::getMailTags();
+
+ switch ($this->getTransactionType()) {
+ case PhabricatorTransactions::TYPE_COMMENT:
+ $tags[] = self::MAILTAG_COMMENT;
+ break;
+ case self::TYPE_NAME:
+ case self::TYPE_FLAVOR:
+ case self::TYPE_IMAGE:
+ $tags[] = self::MAILTAG_DETAILS;
+ break;
+ default:
+ $tags[] = self::MAILTAG_OTHER;
+ break;
+ }
+ return $tags;
+ }
+
+}
diff --git a/src/applications/tokens/storage/PhabricatorTokensTransactionComment.php b/src/applications/tokens/storage/PhabricatorTokensTransactionComment.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/storage/PhabricatorTokensTransactionComment.php
@@ -0,0 +1,10 @@
+<?php
+
+final class PhabricatorTokensTransactionComment
+ extends PhabricatorApplicationTransactionComment {
+
+ public function getApplicationTransactionObject() {
+ return new PhabricatorTokensTransaction();
+ }
+
+}
diff --git a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
--- a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
+++ b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
@@ -111,6 +111,7 @@
'db.spaces' => array(),
'db.phurl' => array(),
'db.badges' => array(),
+ 'db.tokens' => array(),
'0000.legacy.sql' => array(
'legacy' => 0,
),

File Metadata

Mime Type
text/plain
Expires
Wed, May 22, 7:42 AM (3 w, 3 d ago)
Storage Engine
amazon-s3
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
phabricator/secure/lb/6j/djsaukpt6agyjbl7
Default Alt Text
D16178.diff (64 KB)

Event Timeline