diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 1580da7510..644c43f8d0 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -602,6 +602,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationTransactionCommentEditor' => 'applications/transactions/editor/PhabricatorApplicationTransactionCommentEditor.php', 'PhabricatorApplicationTransactionCommentQuery' => 'applications/transactions/query/PhabricatorApplicationTransactionCommentQuery.php', 'PhabricatorApplicationTransactionEditor' => 'applications/transactions/editor/PhabricatorApplicationTransactionEditor.php', + 'PhabricatorApplicationTransactionFeedStory' => 'applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php', 'PhabricatorApplicationTransactionQuery' => 'applications/transactions/query/PhabricatorApplicationTransactionQuery.php', 'PhabricatorApplicationTransactions' => 'applications/transactions/application/PhabricatorApplicationTransactions.php', 'PhabricatorApplicationUIExamples' => 'applications/uiexample/application/PhabricatorApplicationUIExamples.php', @@ -1320,6 +1321,7 @@ phutil_register_library_map(array( 'phabricator_render_form' => 'infrastructure/javelin/markup.php', 'phabricator_render_form_magic' => 'infrastructure/javelin/markup.php', 'phabricator_time' => 'view/viewutils.php', + 'phid_get_subtype' => 'applications/phid/utils.php', 'phid_get_type' => 'applications/phid/utils.php', 'phid_group_by_type' => 'applications/phid/utils.php', 'require_celerity_resource' => 'infrastructure/celerity/api.php', @@ -1851,15 +1853,21 @@ phutil_register_library_map(array( 'PhabricatorApplicationSlowvote' => 'PhabricatorApplication', 'PhabricatorApplicationStatusView' => 'AphrontView', 'PhabricatorApplicationSubscriptions' => 'PhabricatorApplication', - 'PhabricatorApplicationTransaction' => 'PhabricatorLiskDAO', + 'PhabricatorApplicationTransaction' => + array( + 0 => 'PhabricatorLiskDAO', + 1 => 'PhabricatorPolicyInterface', + ), 'PhabricatorApplicationTransactionComment' => array( 0 => 'PhabricatorLiskDAO', 1 => 'PhabricatorMarkupInterface', + 2 => 'PhabricatorPolicyInterface', ), 'PhabricatorApplicationTransactionCommentEditor' => 'PhabricatorEditor', 'PhabricatorApplicationTransactionCommentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorApplicationTransactionEditor' => 'PhabricatorEditor', + 'PhabricatorApplicationTransactionFeedStory' => 'PhabricatorFeedStory', 'PhabricatorApplicationTransactionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorApplicationTransactions' => 'PhabricatorApplication', 'PhabricatorApplicationUIExamples' => 'PhabricatorApplication', @@ -2463,7 +2471,7 @@ phutil_register_library_map(array( 'PholioReplyHandler' => 'PhabricatorMailReplyHandler', 'PholioTransaction' => 'PhabricatorApplicationTransaction', 'PholioTransactionComment' => 'PhabricatorApplicationTransactionComment', - 'PholioTransactionQuery' => 'PhabricatorOffsetPagedQuery', + 'PholioTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PholioTransactionType' => 'PholioConstants', 'PhortuneMonthYearExpiryControl' => 'AphrontFormControl', 'PhortuneStripeBaseController' => 'PhabricatorController', diff --git a/src/applications/phid/handle/PhabricatorObjectHandleData.php b/src/applications/phid/handle/PhabricatorObjectHandleData.php index eb0db7707b..d737b872ab 100644 --- a/src/applications/phid/handle/PhabricatorObjectHandleData.php +++ b/src/applications/phid/handle/PhabricatorObjectHandleData.php @@ -104,6 +104,28 @@ final class PhabricatorObjectHandleData { $objects[$mock->getPHID()] = $mock; } break; + case PhabricatorPHIDConstants::PHID_TYPE_XACT: + $subtypes = array(); + foreach ($phids as $phid) { + $subtypes[phid_get_subtype($phid)][] = $phid; + } + $xactions = array(); + foreach ($subtypes as $subtype => $subtype_phids) { + // TODO: Do this magically. + switch ($subtype) { + case PhabricatorPHIDConstants::PHID_TYPE_MOCK: + $results = id(new PholioTransactionQuery()) + ->setViewer($this->viewer) + ->withPHIDs($subtype_phids) + ->execute(); + $xactions += mpull($results, null, 'getPHID'); + break; + } + } + foreach ($xactions as $xaction) { + $objects[$xaction->getPHID()] = $xaction; + } + break; } } @@ -572,7 +594,7 @@ final class PhabricatorObjectHandleData { } else { $mock = $mocks[$phid]; $handle->setName($mock->getName()); - $handle->setFullName($mock->getName()); + $handle->setFullName('M'.$mock->getID().': '.$mock->getName()); $handle->setURI('/M'.$mock->getID()); $handle->setComplete(true); } diff --git a/src/applications/phid/utils.php b/src/applications/phid/utils.php index 060c7add59..a321a96936 100644 --- a/src/applications/phid/utils.php +++ b/src/applications/phid/utils.php @@ -36,3 +36,10 @@ function phid_group_by_type($phids) { } return $result; } + +function phid_get_subtype($phid) { + if (isset($phid[14]) && ($phid[14] == '-')) { + return substr($phid, 10, 4); + } + return null; +} diff --git a/src/applications/pholio/editor/PholioMockEditor.php b/src/applications/pholio/editor/PholioMockEditor.php index ff28ba73bd..1583b02be5 100644 --- a/src/applications/pholio/editor/PholioMockEditor.php +++ b/src/applications/pholio/editor/PholioMockEditor.php @@ -125,4 +125,8 @@ final class PholioMockEditor extends PhabricatorApplicationTransactionEditor { return PhabricatorEnv::getEnvConfig('metamta.pholio.subject-prefix'); } + protected function supportsFeed() { + return true; + } + } diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php index 51a0e4cc3c..9b124ec58c 100644 --- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php +++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php @@ -2,6 +2,7 @@ /** * @task mail Sending Mail + * @task feed Publishing Feed Stories */ abstract class PhabricatorApplicationTransactionEditor extends PhabricatorEditor { @@ -247,7 +248,17 @@ abstract class PhabricatorApplicationTransactionEditor } // TODO: Index object. - // TODO: Publish feed/notifications. + + if ($this->supportsFeed()) { + $mailed = array(); + if ($mail) { + $mailed = $mail->buildRecipientList(); + } + $this->publishFeedStory( + $object, + $xactions, + $mailed); + } $this->didApplyTransactions($object, $xactions); @@ -550,7 +561,7 @@ abstract class PhabricatorApplicationTransactionEditor $mail_tags = $this->getMailTags($object, $xactions); - $action = $this->getStrongestAction($object, $xactions); + $action = $this->getStrongestAction($object, $xactions)->getActionName(); $template ->setFrom($this->requireActor()->getPHID()) @@ -590,7 +601,7 @@ abstract class PhabricatorApplicationTransactionEditor protected function getStrongestAction( PhabricatorLiskDAO $object, array $xactions) { - return last(msort($xactions, 'getActionStrength'))->getActionName(); + return last(msort($xactions, 'getActionStrength')); } @@ -683,4 +694,95 @@ abstract class PhabricatorApplicationTransactionEditor } +/* -( Publishing Feed Stories )-------------------------------------------- */ + + + /** + * @task feed + */ + protected function supportsFeed() { + return false; + } + + + /** + * @task feed + */ + protected function getFeedStoryType() { + return 'PhabricatorApplicationTransactionFeedStory'; + } + + + /** + * @task feed + */ + protected function getFeedRelatedPHIDs( + PhabricatorLiskDAO $object, + array $xactions) { + + return array( + $object->getPHID(), + $this->requireActor()->getPHID(), + ); + } + + + /** + * @task feed + */ + protected function getFeedNotifyPHIDs( + PhabricatorLiskDAO $object, + array $xactions) { + + return array_merge( + $this->getMailTo($object), + $this->getMailCC($object)); + } + + + /** + * @task feed + */ + protected function getFeedStoryData( + PhabricatorLiskDAO $object, + array $xactions) { + + $xactions = msort($xactions, 'getActionStrength'); + $xactions = array_reverse($xactions); + + return array( + 'objectPHID' => $object->getPHID(), + 'transactionPHIDs' => mpull($xactions, 'getPHID'), + ); + } + + + /** + * @task feed + */ + protected function publishFeedStory( + PhabricatorLiskDAO $object, + array $xactions, + array $mailed_phids) { + + $related_phids = $this->getFeedRelatedPHIDs($object, $xactions); + $subscribed_phids = $this->getFeedNotifyPHIDs($object, $xactions); + + $story_type = $this->getFeedStoryType(); + $story_data = $this->getFeedStoryData($object, $xactions); + + phlog($subscribed_phids); + + id(new PhabricatorFeedStoryPublisher()) + ->setStoryType($story_type) + ->setStoryData($story_data) + ->setStoryTime(time()) + ->setStoryAuthorPHID($this->requireActor()->getPHID()) + ->setRelatedPHIDs($related_phids) + ->setPrimaryObjectPHID($object->getPHID()) + ->setSubscribedPHIDs($subscribed_phids) + ->setMailRecipientPHIDs($mailed_phids) + ->publish(); + } + } diff --git a/src/applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php b/src/applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php new file mode 100644 index 0000000000..0a04a29380 --- /dev/null +++ b/src/applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php @@ -0,0 +1,51 @@ +getValue('objectPHID'); + } + + public function getRequiredObjectPHIDs() { + return array( + $this->getPrimaryTransactionPHID(), + ); + } + + public function getRequiredHandlePHIDs() { + $phids = array(); + $phids[] = array($this->getValue('objectPHID')); + $phids[] = $this->getPrimaryTransaction()->getRequiredHandlePHIDs(); + return array_mergev($phids); + } + + protected function getPrimaryTransactionPHID() { + return head($this->getValue('transactionPHIDs')); + } + + protected function getPrimaryTransaction() { + return $this->getObject($this->getPrimaryTransactionPHID()); + } + + public function renderView() { + $view = new PhabricatorFeedStoryView(); + $view->setViewed($this->getHasViewed()); + + $href = $this->getHandle($this->getPrimaryObjectPHID())->getURI(); + $view->setHref($view); + + $xaction_phids = $this->getValue('transactionPHIDs'); + $xaction = $this->getObject(head($xaction_phids)); + + $xaction->setHandles($this->getHandles()); + $view->setTitle($xaction->getTitleForFeed()); + $view->setOneLineStory(true); + + return $view; + } + +} diff --git a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php index f669011711..205f09b14a 100644 --- a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php +++ b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php @@ -220,6 +220,39 @@ abstract class PhabricatorApplicationTransaction } } + public function getTitleForFeed() { + $author_phid = $this->getAuthorPHID(); + $object_phid = $this->getObjectPHID(); + + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + switch ($this->getTransactionType()) { + case PhabricatorTransactions::TYPE_COMMENT: + return pht( + '%s added a comment to %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + case PhabricatorTransactions::TYPE_VIEW_POLICY: + return pht( + '%s changed the visibility for %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + case PhabricatorTransactions::TYPE_EDIT_POLICY: + return pht( + '%s changed the edit policy for %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + case PhabricatorTransactions::TYPE_SUBSCRIBERS: + return pht( + '%s updated subscribers of %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + } + + return $this->getTitle(); + } + public function getActionStrength() { switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT: