@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add the skeleton for a "transaction.search" Conduit API method

Summary:
Ref T5873. See PHI14. This does the basics that are shared across everything (IDs, PHIDs, dates, comments).

It doesn't do types (I think I don't necessarily want to expose internal types over the API?) or transaction-specific data.

In the next change, I'm going to add ways to let ModularTransactions "opt-in" to providing more data to Conduit. I'll use this to flesh out the actual desired transaction types (comments, presumably inline comments) and likely leave the rest as skeletons for now until use cases arise so we don't create a backward compatibility issue (or a security issue!) by exposing tons of internal stuff as public-facing API.

Test Plan:
Ran queries, used paging. Retrieved an edited, deleted, and normal comment.

{F5120060}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T5873

Differential Revision: https://secure.phabricator.com/D18466

+154
+2
src/__phutil_library_map__.php
··· 4884 4884 'TokenGiveConduitAPIMethod' => 'applications/tokens/conduit/TokenGiveConduitAPIMethod.php', 4885 4885 'TokenGivenConduitAPIMethod' => 'applications/tokens/conduit/TokenGivenConduitAPIMethod.php', 4886 4886 'TokenQueryConduitAPIMethod' => 'applications/tokens/conduit/TokenQueryConduitAPIMethod.php', 4887 + 'TransactionSearchConduitAPIMethod' => 'applications/transactions/conduit/TransactionSearchConduitAPIMethod.php', 4887 4888 'UserConduitAPIMethod' => 'applications/people/conduit/UserConduitAPIMethod.php', 4888 4889 'UserDisableConduitAPIMethod' => 'applications/people/conduit/UserDisableConduitAPIMethod.php', 4889 4890 'UserEnableConduitAPIMethod' => 'applications/people/conduit/UserEnableConduitAPIMethod.php', ··· 10631 10632 'TokenGiveConduitAPIMethod' => 'TokenConduitAPIMethod', 10632 10633 'TokenGivenConduitAPIMethod' => 'TokenConduitAPIMethod', 10633 10634 'TokenQueryConduitAPIMethod' => 'TokenConduitAPIMethod', 10635 + 'TransactionSearchConduitAPIMethod' => 'ConduitAPIMethod', 10634 10636 'UserConduitAPIMethod' => 'ConduitAPIMethod', 10635 10637 'UserDisableConduitAPIMethod' => 'UserConduitAPIMethod', 10636 10638 'UserEnableConduitAPIMethod' => 'UserConduitAPIMethod',
+152
src/applications/transactions/conduit/TransactionSearchConduitAPIMethod.php
··· 1 + <?php 2 + 3 + final class TransactionSearchConduitAPIMethod 4 + extends ConduitAPIMethod { 5 + 6 + public function getAPIMethodName() { 7 + return 'transaction.search'; 8 + } 9 + 10 + public function getMethodDescription() { 11 + return pht('Read transactions for an object.'); 12 + } 13 + 14 + public function getMethodStatus() { 15 + return self::METHOD_STATUS_UNSTABLE; 16 + } 17 + 18 + public function getMethodStatusDescription() { 19 + return pht('This method is new and experimental.'); 20 + } 21 + 22 + protected function defineParamTypes() { 23 + return array( 24 + 'objectIdentifier' => 'phid|string', 25 + ) + $this->getPagerParamTypes(); 26 + } 27 + 28 + protected function defineReturnType() { 29 + return 'list<dict>'; 30 + } 31 + 32 + protected function defineErrorTypes() { 33 + return array(); 34 + } 35 + 36 + protected function execute(ConduitAPIRequest $request) { 37 + $viewer = $request->getUser(); 38 + $pager = $this->newPager($request); 39 + 40 + $object_name = $request->getValue('objectIdentifier', null); 41 + if (!strlen($object_name)) { 42 + throw new Exception( 43 + pht( 44 + 'When calling "transaction.search", you must provide an object to '. 45 + 'retrieve transactions for.')); 46 + } 47 + 48 + $object = id(new PhabricatorObjectQuery()) 49 + ->setViewer($viewer) 50 + ->withNames(array($object_name)) 51 + ->executeOne(); 52 + if (!$object) { 53 + throw new Exception( 54 + pht( 55 + 'No object "%s" exists.', 56 + $object_name)); 57 + } 58 + 59 + if (!($object instanceof PhabricatorApplicationTransactionInterface)) { 60 + throw new Exception( 61 + pht( 62 + 'Object "%s" does not implement "%s", so transactions can not '. 63 + 'be loaded for it.')); 64 + } 65 + 66 + $xaction_query = PhabricatorApplicationTransactionQuery::newQueryForObject( 67 + $object); 68 + 69 + $xactions = $xaction_query 70 + ->withObjectPHIDs(array($object->getPHID())) 71 + ->setViewer($viewer) 72 + ->executeWithCursorPager($pager); 73 + 74 + if ($xactions) { 75 + $template = head($xactions)->getApplicationTransactionCommentObject(); 76 + 77 + $query = new PhabricatorApplicationTransactionTemplatedCommentQuery(); 78 + 79 + $comment_map = $query 80 + ->setViewer($viewer) 81 + ->setTemplate($template) 82 + ->withTransactionPHIDs(mpull($xactions, 'getPHID')) 83 + ->execute(); 84 + 85 + $comment_map = msort($comment_map, 'getCommentVersion'); 86 + $comment_map = array_reverse($comment_map); 87 + $comment_map = mgroup($comment_map, 'getTransactionPHID'); 88 + } else { 89 + $comment_map = array(); 90 + } 91 + 92 + $data = array(); 93 + foreach ($xactions as $xaction) { 94 + $comments = idx($comment_map, $xaction->getPHID()); 95 + 96 + $comment_data = array(); 97 + if ($comments) { 98 + $removed = head($comments)->getIsDeleted(); 99 + 100 + foreach ($comments as $comment) { 101 + if ($removed) { 102 + // If the most recent version of the comment has been removed, 103 + // don't show the history. This is for consistency with the web 104 + // UI, which also prevents users from retrieving the content of 105 + // removed comments. 106 + $content = array( 107 + 'raw' => '', 108 + ); 109 + } else { 110 + $content = array( 111 + 'raw' => (string)$comment->getContent(), 112 + ); 113 + } 114 + 115 + $comment_data[] = array( 116 + 'id' => (int)$comment->getID(), 117 + 'phid' => (string)$comment->getPHID(), 118 + 'version' => (int)$comment->getCommentVersion(), 119 + 'authorPHID' => (string)$comment->getAuthorPHID(), 120 + 'dateCreated' => (int)$comment->getDateCreated(), 121 + 'dateModified' => (int)$comment->getDateModified(), 122 + 'removed' => (bool)$comment->getIsDeleted(), 123 + 'content' => $content, 124 + ); 125 + } 126 + } 127 + 128 + $fields = array(); 129 + 130 + if (!$fields) { 131 + $fields = (object)$fields; 132 + } 133 + 134 + $data[] = array( 135 + 'id' => (int)$xaction->getID(), 136 + 'phid' => (string)$xaction->getPHID(), 137 + 'authorPHID' => (string)$xaction->getAuthorPHID(), 138 + 'objectPHID' => (string)$xaction->getObjectPHID(), 139 + 'dateCreated' => (int)$xaction->getDateCreated(), 140 + 'dateModified' => (int)$xaction->getDateModified(), 141 + 'comments' => $comment_data, 142 + 'fields' => $fields, 143 + ); 144 + } 145 + 146 + $results = array( 147 + 'data' => $data, 148 + ); 149 + 150 + return $this->addPagerResults($results, $pager); 151 + } 152 + }