From ee620bde6dbc376d8becbc41ac5209c38f3e7e0c Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 17 Dec 2011 13:27:11 -0800 Subject: [PATCH] Publish feed stories from Maniphest Summary: I didn't get around to this earlier; add Feed/Maniphest integration. This is partly motivated by wanting Projects to not be terrible. Pretty straightforward. Test Plan: - Created, updated, reassigned and closed a task. - Verified feed stories render reasonably. Reviewers: btrahan, jungejason Reviewed By: btrahan CC: aran, btrahan Maniphest Tasks: T681 Differential Revision: 1232 --- src/__phutil_library_map__.php | 4 + .../PhabricatorFeedStoryTypeConstants.php | 1 + .../PhabricatorFeedStoryManiphest.php | 94 +++++++++++++++++++ .../feed/story/maniphest/__init__.php | 18 ++++ .../constants/action/ManiphestAction.php | 65 +++++++++++++ .../maniphest/constants/action/__init__.php | 14 +++ .../ManiphestTransactionEditor.php | 79 ++++++++++++++-- .../maniphest/editor/transaction/__init__.php | 3 + 8 files changed, 269 insertions(+), 9 deletions(-) create mode 100644 src/applications/feed/story/maniphest/PhabricatorFeedStoryManiphest.php create mode 100644 src/applications/feed/story/maniphest/__init__.php create mode 100644 src/applications/maniphest/constants/action/ManiphestAction.php create mode 100644 src/applications/maniphest/constants/action/__init__.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 03de550fb9..eed3233591 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -337,6 +337,7 @@ phutil_register_library_map(array( 'LiskIsolationTestCase' => 'storage/lisk/dao/__tests__', 'LiskIsolationTestDAO' => 'storage/lisk/dao/__tests__', 'LiskIsolationTestDAOException' => 'storage/lisk/dao/__tests__', + 'ManiphestAction' => 'applications/maniphest/constants/action', 'ManiphestAuxiliaryFieldDefaultSpecification' => 'applications/maniphest/auxiliaryfield/default', 'ManiphestAuxiliaryFieldSpecification' => 'applications/maniphest/auxiliaryfield/base', 'ManiphestAuxiliaryFieldTypeException' => 'applications/maniphest/auxiliaryfield/typeexception', @@ -438,6 +439,7 @@ phutil_register_library_map(array( 'PhabricatorFeedStory' => 'applications/feed/story/base', 'PhabricatorFeedStoryData' => 'applications/feed/storage/story', 'PhabricatorFeedStoryDifferential' => 'applications/feed/story/differential', + 'PhabricatorFeedStoryManiphest' => 'applications/feed/story/maniphest', 'PhabricatorFeedStoryPhriction' => 'applications/feed/story/phriction', 'PhabricatorFeedStoryPublisher' => 'applications/feed/publisher', 'PhabricatorFeedStoryReference' => 'applications/feed/storage/storyreference', @@ -1017,6 +1019,7 @@ phutil_register_library_map(array( 'JavelinViewExampleServerView' => 'AphrontView', 'LiskIsolationTestCase' => 'PhabricatorTestCase', 'LiskIsolationTestDAO' => 'LiskDAO', + 'ManiphestAction' => 'PhrictionConstants', 'ManiphestAuxiliaryFieldDefaultSpecification' => 'ManiphestAuxiliaryFieldSpecification', 'ManiphestController' => 'PhabricatorController', 'ManiphestDAO' => 'PhabricatorLiskDAO', @@ -1101,6 +1104,7 @@ phutil_register_library_map(array( 'PhabricatorFeedPublicStreamController' => 'PhabricatorFeedController', 'PhabricatorFeedStoryData' => 'PhabricatorFeedDAO', 'PhabricatorFeedStoryDifferential' => 'PhabricatorFeedStory', + 'PhabricatorFeedStoryManiphest' => 'PhabricatorFeedStory', 'PhabricatorFeedStoryPhriction' => 'PhabricatorFeedStory', 'PhabricatorFeedStoryReference' => 'PhabricatorFeedDAO', 'PhabricatorFeedStoryStatus' => 'PhabricatorFeedStory', diff --git a/src/applications/feed/constants/story/PhabricatorFeedStoryTypeConstants.php b/src/applications/feed/constants/story/PhabricatorFeedStoryTypeConstants.php index 0ac7f802e8..4ab63dd596 100644 --- a/src/applications/feed/constants/story/PhabricatorFeedStoryTypeConstants.php +++ b/src/applications/feed/constants/story/PhabricatorFeedStoryTypeConstants.php @@ -23,5 +23,6 @@ final class PhabricatorFeedStoryTypeConstants const STORY_STATUS = 'PhabricatorFeedStoryStatus'; const STORY_DIFFERENTIAL = 'PhabricatorFeedStoryDifferential'; const STORY_PHRICTION = 'PhabricatorFeedStoryPhriction'; + const STORY_MANIPHEST = 'PhabricatorFeedStoryManiphest'; } diff --git a/src/applications/feed/story/maniphest/PhabricatorFeedStoryManiphest.php b/src/applications/feed/story/maniphest/PhabricatorFeedStoryManiphest.php new file mode 100644 index 0000000000..ef27673a63 --- /dev/null +++ b/src/applications/feed/story/maniphest/PhabricatorFeedStoryManiphest.php @@ -0,0 +1,94 @@ +getStoryData(); + return array( + $this->getStoryData()->getAuthorPHID(), + $data->getValue('taskPHID'), + $data->getValue('ownerPHID'), + ); + } + + public function getRequiredObjectPHIDs() { + return array( + $this->getStoryData()->getAuthorPHID(), + ); + } + + public function renderView() { + $data = $this->getStoryData(); + + $handles = $this->getHandles(); + $author_phid = $data->getAuthorPHID(); + $owner_phid = $data->getValue('ownerPHID'); + $task_phid = $data->getValue('taskPHID'); + + $objects = $this->getObjects(); + $action = $data->getValue('action'); + + $view = new PhabricatorFeedStoryView(); + + $verb = ManiphestAction::getActionPastTenseVerb($action); + $title = + ''.$handles[$author_phid]->renderLink().''. + " {$verb} ". + ''.$handles[$task_phid]->renderLink().''; + switch ($action) { + case ManiphestAction::ACTION_ASSIGN: + $title .= + ' to '. + ''.$handles[$owner_phid]->renderLink().''; + break; + } + $title .= '.'; + $view->setTitle($title); + + switch ($action) { + case ManiphestAction::ACTION_CREATE: + $full_size = true; + break; + default: + $full_size = false; + break; + } + + $view->setEpoch($data->getEpoch()); + + if ($full_size) { + if (!empty($objects[$author_phid])) { + $image_phid = $objects[$author_phid]->getProfileImagePHID(); + $image_uri = PhabricatorFileURI::getViewURIForPHID($image_phid); + $view->setImage($image_uri); + } + + $content = phutil_escape_html( + phutil_utf8_shorten($data->getValue('description'), 128)); + $content = str_replace("\n", '
', $content); + + $view->appendChild($content); + } else { + $view->setOneLineStory(true); + } + + return $view; + } + +} diff --git a/src/applications/feed/story/maniphest/__init__.php b/src/applications/feed/story/maniphest/__init__.php new file mode 100644 index 0000000000..5a8b993c9f --- /dev/null +++ b/src/applications/feed/story/maniphest/__init__.php @@ -0,0 +1,18 @@ + 'created', + self::ACTION_CLOSE => 'closed', + self::ACTION_UPDATE => 'updated', + self::ACTION_ASSIGN => 'assigned', + ); + + return idx($map, $action, "brazenly {$action}'d"); + } + + /** + * If a group of transactions contain several actions, select the "strongest" + * action. For instance, a close is stronger than an update, because we want + * to render "User U closed task T" instead of "User U updated task T" when + * a user closes a task. + */ + public static function selectStrongestAction(array $actions) { + static $strengths = array( + self::ACTION_UPDATE => 0, + self::ACTION_ASSIGN => 1, + self::ACTION_CREATE => 2, + self::ACTION_CLOSE => 3, + ); + + $strongest = null; + $strength = -1; + foreach ($actions as $action) { + if ($strengths[$action] > $strength) { + $strength = $strengths[$action]; + $strongest = $action; + } + } + return $strongest; + } + +} diff --git a/src/applications/maniphest/constants/action/__init__.php b/src/applications/maniphest/constants/action/__init__.php new file mode 100644 index 0000000000..712d81ed5f --- /dev/null +++ b/src/applications/maniphest/constants/action/__init__.php @@ -0,0 +1,14 @@ +getCCPHIDs()); + $this->publishFeedStory($task, $transactions); + // TODO: Do this offline via timeline PhabricatorSearchManiphestIndexer::indexTask($task); @@ -207,15 +209,7 @@ class ManiphestTransactionEditor { $view->setHandles($handles); list($action, $body) = $view->renderForEmail($with_date = false); - $is_create = false; - foreach ($transactions as $transaction) { - $type = $transaction->getTransactionType(); - if (($type == ManiphestTransactionType::TYPE_STATUS) && - ($transaction->getOldValue() === null) && - ($transaction->getNewValue() == ManiphestTaskStatus::STATUS_OPEN)) { - $is_create = true; - } - } + $is_create = $this->isCreate($transactions); $task_uri = PhabricatorEnv::getURI('/T'.$task->getID()); @@ -276,4 +270,71 @@ class ManiphestTransactionEditor { return $handler_object; } + + private function publishFeedStory(ManiphestTask $task, array $transactions) { + $actions = array(ManiphestAction::ACTION_UPDATE); + $comments = null; + foreach ($transactions as $transaction) { + if ($transaction->hasComments()) { + $comments = $transaction->getComments(); + } + switch ($transaction->getTransactionType()) { + case ManiphestTransactionType::TYPE_OWNER: + $actions[] = ManiphestAction::ACTION_ASSIGN; + break; + case ManiphestTransactionType::TYPE_STATUS: + if ($task->getStatus() != ManiphestTaskStatus::STATUS_OPEN) { + $actions[] = ManiphestAction::ACTION_CLOSE; + } else if ($this->isCreate($transactions)) { + $actions[] = ManiphestAction::ACTION_CREATE; + } + break; + default: + break; + } + } + + $action_type = ManiphestAction::selectStrongestAction($actions); + $owner_phid = $task->getOwnerPHID(); + $actor_phid = head($transactions)->getAuthorPHID(); + $author_phid = $task->getAuthorPHID(); + + id(new PhabricatorFeedStoryPublisher()) + ->setStoryType(PhabricatorFeedStoryTypeConstants::STORY_MANIPHEST) + ->setStoryData(array( + 'taskPHID' => $task->getPHID(), + 'transactionIDs' => mpull($transactions, 'getID'), + 'ownerPHID' => $owner_phid, + 'action' => $action_type, + 'comments' => $comments, + 'description' => $task->getDescription(), + )) + ->setStoryTime(time()) + ->setStoryAuthorPHID($actor_phid) + ->setRelatedPHIDs( + array_merge( + array_filter( + array( + $task->getPHID(), + $author_phid, + $actor_phid, + $owner_phid, + )), + $task->getProjectPHIDs())) + ->publish(); + } + + private function isCreate(array $transactions) { + $is_create = false; + foreach ($transactions as $transaction) { + $type = $transaction->getTransactionType(); + if (($type == ManiphestTransactionType::TYPE_STATUS) && + ($transaction->getOldValue() === null) && + ($transaction->getNewValue() == ManiphestTaskStatus::STATUS_OPEN)) { + $is_create = true; + } + } + return $is_create; + } + } diff --git a/src/applications/maniphest/editor/transaction/__init__.php b/src/applications/maniphest/editor/transaction/__init__.php index 75f2b7d20e..09a4a08fb1 100644 --- a/src/applications/maniphest/editor/transaction/__init__.php +++ b/src/applications/maniphest/editor/transaction/__init__.php @@ -6,6 +6,9 @@ +phutil_require_module('phabricator', 'applications/feed/constants/story'); +phutil_require_module('phabricator', 'applications/feed/publisher'); +phutil_require_module('phabricator', 'applications/maniphest/constants/action'); phutil_require_module('phabricator', 'applications/maniphest/constants/status'); phutil_require_module('phabricator', 'applications/maniphest/constants/transactiontype'); phutil_require_module('phabricator', 'applications/maniphest/view/transactiondetail');