From 5cbdda413cf7277815b054af3cc63e381a742fdf Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 21 Apr 2014 15:33:59 -0700 Subject: [PATCH] Paradigms, paradigms, paradigms Summary: Fixes T4693. Test Plan: {F146407} Reviewers: chad, btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T4693 Differential Revision: https://secure.phabricator.com/D8829 --- .../conduit/ConduitAPI_token_give_Method.php | 5 +- .../PhabricatorTokenGiveController.php | 13 +-- .../editor/PhabricatorTokenGivenEditor.php | 98 +++++++++++++++---- .../constants/PhabricatorTransactions.php | 1 + ...habricatorApplicationTransactionEditor.php | 7 ++ ...ricatorApplicationTransactionInterface.php | 20 ++++ .../PhabricatorApplicationTransaction.php | 48 ++++++++- .../PhabricatorApplicationTransactionView.php | 5 + webroot/rsrc/css/phui/phui-timeline-view.css | 1 + 9 files changed, 171 insertions(+), 27 deletions(-) diff --git a/src/applications/tokens/conduit/ConduitAPI_token_give_Method.php b/src/applications/tokens/conduit/ConduitAPI_token_give_Method.php index 3f85072d03..03f7db069c 100644 --- a/src/applications/tokens/conduit/ConduitAPI_token_give_Method.php +++ b/src/applications/tokens/conduit/ConduitAPI_token_give_Method.php @@ -22,8 +22,11 @@ final class ConduitAPI_token_give_Method extends ConduitAPI_token_Method { } public function execute(ConduitAPIRequest $request) { + $content_source = PhabricatorContentSource::newFromConduitRequest($request); + $editor = id(new PhabricatorTokenGivenEditor()) - ->setActor($request->getUser()); + ->setActor($request->getUser()) + ->setContentSource($content_source); if ($request->getValue('tokenPHID')) { $editor->addToken( diff --git a/src/applications/tokens/controller/PhabricatorTokenGiveController.php b/src/applications/tokens/controller/PhabricatorTokenGiveController.php index 480cc992a7..6f39d51b3b 100644 --- a/src/applications/tokens/controller/PhabricatorTokenGiveController.php +++ b/src/applications/tokens/controller/PhabricatorTokenGiveController.php @@ -36,15 +36,16 @@ final class PhabricatorTokenGiveController extends PhabricatorTokenController { $done_uri = $handle->getURI(); if ($request->isDialogFormPost()) { + $content_source = PhabricatorContentSource::newFromRequest($request); + + $editor = id(new PhabricatorTokenGivenEditor()) + ->setActor($user) + ->setContentSource($content_source); if ($is_give) { $token_phid = $request->getStr('tokenPHID'); - $editor = id(new PhabricatorTokenGivenEditor()) - ->setActor($user) - ->addToken($handle->getPHID(), $token_phid); + $editor->addToken($handle->getPHID(), $token_phid); } else { - $editor = id(new PhabricatorTokenGivenEditor()) - ->setActor($user) - ->deleteToken($handle->getPHID()); + $editor->deleteToken($handle->getPHID()); } return id(new AphrontReloadResponse())->setURI($done_uri); diff --git a/src/applications/tokens/editor/PhabricatorTokenGivenEditor.php b/src/applications/tokens/editor/PhabricatorTokenGivenEditor.php index 56b2cee8f3..ea4e8367c0 100644 --- a/src/applications/tokens/editor/PhabricatorTokenGivenEditor.php +++ b/src/applications/tokens/editor/PhabricatorTokenGivenEditor.php @@ -3,9 +3,21 @@ final class PhabricatorTokenGivenEditor extends PhabricatorEditor { + private $contentSource; + + public function setContentSource(PhabricatorContentSource $content_source) { + $this->contentSource = $content_source; + return $this; + } + + public function getContentSource() { + return $this->contentSource; + } + public function addToken($object_phid, $token_phid) { $token = $this->validateToken($token_phid); $object = $this->validateObject($object_phid); + $current_token = $this->loadCurrentToken($object); $actor = $this->requireActor(); @@ -16,7 +28,9 @@ final class PhabricatorTokenGivenEditor $token_given->openTransaction(); - $this->executeDeleteToken($object); + if ($current_token) { + $this->executeDeleteToken($object, $current_token); + } $token_given->save(); @@ -29,6 +43,16 @@ final class PhabricatorTokenGivenEditor $token_given->saveTransaction(); + $current_token_phid = null; + if ($current_token) { + $current_token_phid = $current_token->getTokenPHID(); + } + + $this->publishTransaction( + $object, + $current_token_phid, + $token->getPHID()); + $subscribed_phids = $object->getUsersToNotifyOfTokenGiven(); if ($subscribed_phids) { $related_phids = $subscribed_phids; @@ -57,22 +81,23 @@ final class PhabricatorTokenGivenEditor public function deleteToken($object_phid) { $object = $this->validateObject($object_phid); - return $this->executeDeleteToken($object); - } - - private function executeDeleteToken($object) { - $actor = $this->requireActor(); - - $token_given = id(new PhabricatorTokenGiven())->loadOneWhere( - 'authorPHID = %s AND objectPHID = %s', - $actor->getPHID(), - $object->getPHID()); + $token_given = $this->loadCurrentToken($object); if (!$token_given) { return; } - $token_given->openTransaction(); + $this->executeDeleteToken($object, $token_given); + $this->publishTransaction( + $object, + $token_given->getTokenPHID(), + null); + } + private function executeDeleteToken( + PhabricatorTokenReceiverInterface $object, + PhabricatorTokenGiven $token_given) { + + $token_given->openTransaction(); $token_given->delete(); queryfx( @@ -81,21 +106,20 @@ final class PhabricatorTokenGivenEditor ON DUPLICATE KEY UPDATE tokenCount = tokenCount - 1', id(new PhabricatorTokenCount())->getTableName(), $object->getPHID()); - $token_given->saveTransaction(); } private function validateToken($token_phid) { - $tokens = id(new PhabricatorTokenQuery()) + $token = id(new PhabricatorTokenQuery()) ->setViewer($this->requireActor()) ->withPHIDs(array($token_phid)) - ->execute(); + ->executeOne(); - if (empty($tokens)) { - throw new Exception("No such token!"); + if (!$token) { + throw new Exception(pht('No such token "%s"!', $token_phid)); } - return head($tokens); + return $token; } private function validateObject($object_phid) { @@ -105,10 +129,46 @@ final class PhabricatorTokenGivenEditor ->executeOne(); if (!$object) { - throw new Exception("No such object!"); + throw new Exception(pht('No such object "%s"!', $object_phid)); } return $object; } + private function loadCurrentToken(PhabricatorTokenReceiverInterface $object) { + return id(new PhabricatorTokenGiven())->loadOneWhere( + 'authorPHID = %s AND objectPHID = %s', + $this->requireActor()->getPHID(), + $object->getPHID()); + } + + + private function publishTransaction( + PhabricatorTokenReceiverInterface $object, + $old_token_phid, + $new_token_phid) { + + if (!($object instanceof PhabricatorApplicationTransactionInterface)) { + return; + } + + $actor = $this->requireActor(); + + $xactions = array(); + $xactions[] = id($object->getApplicationTransactionTemplate()) + ->setTransactionType(PhabricatorTransactions::TYPE_TOKEN) + ->setOldValue($old_token_phid) + ->setNewValue($new_token_phid); + + $editor = $object->getApplicationTransactionEditor() + ->setActor($actor) + ->setContentSource($this->getContentSource()) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true); + + $editor->applyTransactions( + $object->getApplicationTransactionObject(), + $xactions); + } + } diff --git a/src/applications/transactions/constants/PhabricatorTransactions.php b/src/applications/transactions/constants/PhabricatorTransactions.php index eb4b84723e..59cccec46f 100644 --- a/src/applications/transactions/constants/PhabricatorTransactions.php +++ b/src/applications/transactions/constants/PhabricatorTransactions.php @@ -10,6 +10,7 @@ final class PhabricatorTransactions { const TYPE_EDGE = 'core:edge'; const TYPE_CUSTOMFIELD = 'core:customfield'; const TYPE_BUILDABLE = 'harbormaster:buildable'; + const TYPE_TOKEN = 'token:give'; const COLOR_RED = 'red'; const COLOR_ORANGE = 'orange'; diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php index 57c5ab1fe0..fea78abb2a 100644 --- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php +++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php @@ -159,6 +159,10 @@ abstract class PhabricatorApplicationTransactionEditor $types[] = PhabricatorTransactions::TYPE_BUILDABLE; } + if ($this->object instanceof PhabricatorTokenReceiverInterface) { + $types[] = PhabricatorTransactions::TYPE_TOKEN; + } + return $types; } @@ -227,6 +231,7 @@ abstract class PhabricatorApplicationTransactionEditor case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_JOIN_POLICY: case PhabricatorTransactions::TYPE_BUILDABLE: + case PhabricatorTransactions::TYPE_TOKEN: return $xaction->getNewValue(); case PhabricatorTransactions::TYPE_EDGE: return $this->getEdgeTransactionNewValue($xaction); @@ -317,6 +322,7 @@ abstract class PhabricatorApplicationTransactionEditor switch ($xaction->getTransactionType()) { case PhabricatorTransactions::TYPE_BUILDABLE: + case PhabricatorTransactions::TYPE_TOKEN: return; case PhabricatorTransactions::TYPE_VIEW_POLICY: $object->setViewPolicy($xaction->getNewValue()); @@ -337,6 +343,7 @@ abstract class PhabricatorApplicationTransactionEditor PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhabricatorTransactions::TYPE_BUILDABLE: + case PhabricatorTransactions::TYPE_TOKEN: return; case PhabricatorTransactions::TYPE_SUBSCRIBERS: $subeditor = id(new PhabricatorSubscriptionsEditor()) diff --git a/src/applications/transactions/interface/PhabricatorApplicationTransactionInterface.php b/src/applications/transactions/interface/PhabricatorApplicationTransactionInterface.php index eac4cf30dd..1c6b4a0049 100644 --- a/src/applications/transactions/interface/PhabricatorApplicationTransactionInterface.php +++ b/src/applications/transactions/interface/PhabricatorApplicationTransactionInterface.php @@ -36,3 +36,23 @@ interface PhabricatorApplicationTransactionInterface { public function getApplicationTransactionTemplate(); } + +// TEMPLATE IMPLEMENTATION ///////////////////////////////////////////////////// + + +/* -( PhabricatorApplicationTransactionInterface )------------------------- */ +/* + + public function getApplicationTransactionEditor() { + return new <<>>Editor(); + } + + public function getApplicationTransactionObject() { + return $this; + } + + public function getApplicationTransactionTemplate() { + return new <<>>Transaction(); + } + +*/ diff --git a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php index 922a8f8325..78836bf859 100644 --- a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php +++ b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php @@ -53,7 +53,7 @@ abstract class PhabricatorApplicationTransaction public function shouldGenerateOldValue() { switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_BUILDABLE: - return false; + case PhabricatorTransactions::TYPE_TOKEN: case PhabricatorTransactions::TYPE_CUSTOMFIELD: return false; } @@ -236,6 +236,8 @@ abstract class PhabricatorApplicationTransaction $phids[] = array($new); } break; + case PhabricatorTransactions::TYPE_TOKEN: + break; case PhabricatorTransactions::TYPE_BUILDABLE: $phid = $this->getMetadataValue('harbormaster:buildablePHID'); if ($phid) { @@ -335,11 +337,33 @@ abstract class PhabricatorApplicationTransaction return 'link'; case PhabricatorTransactions::TYPE_BUILDABLE: return 'wrench'; + case PhabricatorTransactions::TYPE_TOKEN: + if ($this->getNewValue()) { + return 'like'; + } else { + return 'dislike'; + } } return 'edit'; } + public function getToken() { + switch ($this->getTransactionType()) { + case PhabricatorTransactions::TYPE_TOKEN: + $old = $this->getOldValue(); + $new = $this->getNewValue(); + if ($new) { + $icon = substr($new, 10); + } else { + $icon = substr($old, 10); + } + return array($icon, !$this->getNewValue()); + } + + return array(null, null); + } + public function getColor() { switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_BUILDABLE: @@ -400,6 +424,8 @@ abstract class PhabricatorApplicationTransaction public function shouldHideForMail(array $xactions) { switch ($this->getTransactionType()) { + case PhabricatorTransactions::TYPE_TOKEN: + return true; case PhabricatorTransactions::TYPE_BUILDABLE: switch ($this->getNewValue()) { case HarbormasterBuildable::STATUS_PASSED: @@ -414,6 +440,11 @@ abstract class PhabricatorApplicationTransaction } public function shouldHideForFeed() { + switch ($this->getTransactionType()) { + case PhabricatorTransactions::TYPE_TOKEN: + return true; + } + return $this->shouldHide(); } @@ -568,6 +599,21 @@ abstract class PhabricatorApplicationTransaction $this->renderHandleLink($author_phid)); } + case PhabricatorTransactions::TYPE_TOKEN: + if ($old && $new) { + return pht( + '%s updated a token.', + $this->renderHandleLink($author_phid)); + } else if ($old) { + return pht( + '%s rescinded a token.', + $this->renderHandleLink($author_phid)); + } else { + return pht( + '%s awarded a token.', + $this->renderHandleLink($author_phid)); + } + case PhabricatorTransactions::TYPE_BUILDABLE: switch ($this->getNewValue()) { case HarbormasterBuildable::STATUS_PASSED: diff --git a/src/applications/transactions/view/PhabricatorApplicationTransactionView.php b/src/applications/transactions/view/PhabricatorApplicationTransactionView.php index ff1b037305..8ebd96f011 100644 --- a/src/applications/transactions/view/PhabricatorApplicationTransactionView.php +++ b/src/applications/transactions/view/PhabricatorApplicationTransactionView.php @@ -317,6 +317,11 @@ class PhabricatorApplicationTransactionView extends AphrontView { ->setIcon($xaction->getIcon()) ->setColor($xaction->getColor()); + list($token, $token_removed) = $xaction->getToken(); + if ($token) { + $event->setToken($token, $token_removed); + } + if (!$this->shouldSuppressTitle($xaction, $group)) { $title = $xaction->getTitle(); if ($xaction->hasChangeDetails()) { diff --git a/webroot/rsrc/css/phui/phui-timeline-view.css b/webroot/rsrc/css/phui/phui-timeline-view.css index 182d9cbcec..437774a9b6 100644 --- a/webroot/rsrc/css/phui/phui-timeline-view.css +++ b/webroot/rsrc/css/phui/phui-timeline-view.css @@ -127,6 +127,7 @@ .phui-timeline-view .phui-icon-view.phui-timeline-token { vertical-align: middle; + margin-right: 4px; } .phui-timeline-token.strikethrough {