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/(?[^/]+)/' => 'PhabricatorTokenGiveController', - 'leaders/' => 'PhabricatorTokenLeaderController', + '/tokens/' => array( + '(?:query/(?P[^/]+)/)?' + => 'PhabricatorTokenListController', + 'archive/(?:(?P\d+)/)?' => + 'PhabricatorTokenArchiveController', + 'given/' => + 'PhabricatorTokenGivenController', + 'give/(?[^/]+)/' => + 'PhabricatorTokenGiveController', + 'leaders/' => + 'PhabricatorTokenLeaderController', + 'view/(?:(?P\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 @@ +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 @@ 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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ + 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 @@ +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 @@ + array(), 'db.phurl' => array(), 'db.badges' => array(), + 'db.tokens' => array(), '0000.legacy.sql' => array( 'legacy' => 0, ),