From 00f1389f72db4d08065940220b47031c75edabbb Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 28 Dec 2015 04:25:01 -0800 Subject: [PATCH] Add phame.post.search Conduit API endpoint Summary: Ref T9897. Mostly straightforward, but also modernize/fixup the Query a little so that posts never load with no blog. Test Plan: Queried posts via API. Reviewers: chad Reviewed By: chad Maniphest Tasks: T9897 Differential Revision: https://secure.phabricator.com/D14901 --- src/__phutil_library_map__.php | 3 + .../PhamePostSearchConduitAPIMethod.php | 18 ++++ .../phame/query/PhamePostQuery.php | 64 +++++++-------- .../phame/query/PhamePostSearchEngine.php | 21 ++--- src/applications/phame/storage/PhamePost.php | 82 ++++++++++++++----- 5 files changed, 125 insertions(+), 63 deletions(-) create mode 100644 src/applications/phame/conduit/PhamePostSearchConduitAPIMethod.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 19f1e74f05..b43ecd7be5 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3440,6 +3440,7 @@ phutil_register_library_map(array( 'PhamePostPublishController' => 'applications/phame/controller/post/PhamePostPublishController.php', 'PhamePostQuery' => 'applications/phame/query/PhamePostQuery.php', 'PhamePostReplyHandler' => 'applications/phame/mail/PhamePostReplyHandler.php', + 'PhamePostSearchConduitAPIMethod' => 'applications/phame/conduit/PhamePostSearchConduitAPIMethod.php', 'PhamePostSearchEngine' => 'applications/phame/query/PhamePostSearchEngine.php', 'PhamePostTransaction' => 'applications/phame/storage/PhamePostTransaction.php', 'PhamePostTransactionComment' => 'applications/phame/storage/PhamePostTransactionComment.php', @@ -7886,6 +7887,7 @@ phutil_register_library_map(array( 'PhabricatorSubscribableInterface', 'PhabricatorDestructibleInterface', 'PhabricatorTokenReceiverInterface', + 'PhabricatorConduitResultInterface', ), 'PhamePostCommentController' => 'PhamePostController', 'PhamePostController' => 'PhameController', @@ -7900,6 +7902,7 @@ phutil_register_library_map(array( 'PhamePostPublishController' => 'PhamePostController', 'PhamePostQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhamePostReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', + 'PhamePostSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PhamePostSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhamePostTransaction' => 'PhabricatorApplicationTransaction', 'PhamePostTransactionComment' => 'PhabricatorApplicationTransactionComment', diff --git a/src/applications/phame/conduit/PhamePostSearchConduitAPIMethod.php b/src/applications/phame/conduit/PhamePostSearchConduitAPIMethod.php new file mode 100644 index 0000000000..3dce92b6cf --- /dev/null +++ b/src/applications/phame/conduit/PhamePostSearchConduitAPIMethod.php @@ -0,0 +1,18 @@ +establishConnection('r'); + return $this->loadStandardPage($this->newResultObject()); + } - $where_clause = $this->buildWhereClause($conn_r); - $order_clause = $this->buildOrderClause($conn_r); - $limit_clause = $this->buildLimitClause($conn_r); + protected function willFilterPage(array $posts) { + // We require blogs to do visibility checks, so load them unconditionally. + $blog_phids = mpull($posts, 'getBlogPHID'); - $data = queryfx_all( - $conn_r, - 'SELECT * FROM %T p %Q %Q %Q', - $table->getTableName(), - $where_clause, - $order_clause, - $limit_clause); + $blogs = id(new PhameBlogQuery()) + ->setViewer($this->getViewer()) + ->needProfileImage(true) + ->withPHIDs($blog_phids) + ->execute(); - $posts = $table->loadAllFromArray($data); + $blogs = mpull($blogs, null, 'getPHID'); + foreach ($posts as $key => $post) { + $blog_phid = $post->getBlogPHID(); - if ($posts) { - // We require these to do visibility checks, so load them unconditionally. - $blog_phids = mpull($posts, 'getBlogPHID'); - $blogs = id(new PhameBlogQuery()) - ->setViewer($this->getViewer()) - ->needProfileImage(true) - ->withPHIDs($blog_phids) - ->execute(); - $blogs = mpull($blogs, null, 'getPHID'); - foreach ($posts as $post) { - if (isset($blogs[$post->getBlogPHID()])) { - $post->setBlog($blogs[$post->getBlogPHID()]); - } + $blog = idx($blogs, $blog_phid); + if (!$blog) { + $this->didRejectResult($post); + unset($posts[$key]); + continue; } + + $post->attachBlog($blog); } return $posts; @@ -82,42 +80,42 @@ final class PhamePostQuery extends PhabricatorCursorPagedPolicyAwareQuery { if ($this->ids) { $where[] = qsprintf( $conn, - 'p.id IN (%Ld)', + 'id IN (%Ld)', $this->ids); } if ($this->phids) { $where[] = qsprintf( $conn, - 'p.phid IN (%Ls)', + 'phid IN (%Ls)', $this->phids); } if ($this->bloggerPHIDs) { $where[] = qsprintf( $conn, - 'p.bloggerPHID IN (%Ls)', + 'bloggerPHID IN (%Ls)', $this->bloggerPHIDs); } if ($this->visibility !== null) { $where[] = qsprintf( $conn, - 'p.visibility = %d', + 'visibility = %d', $this->visibility); } if ($this->publishedAfter !== null) { $where[] = qsprintf( $conn, - 'p.datePublished > %d', + 'datePublished > %d', $this->publishedAfter); } - if ($this->blogPHIDs) { + if ($this->blogPHIDs !== null) { $where[] = qsprintf( $conn, - 'p.blogPHID in (%Ls)', + 'blogPHID in (%Ls)', $this->blogPHIDs); } diff --git a/src/applications/phame/query/PhamePostSearchEngine.php b/src/applications/phame/query/PhamePostSearchEngine.php index 5002c84e0d..a7a331fbdf 100644 --- a/src/applications/phame/query/PhamePostSearchEngine.php +++ b/src/applications/phame/query/PhamePostSearchEngine.php @@ -30,10 +30,11 @@ final class PhamePostSearchEngine id(new PhabricatorSearchSelectField()) ->setKey('visibility') ->setLabel(pht('Visibility')) - ->setOptions(array( - '' => pht('All'), - PhameConstants::VISIBILITY_PUBLISHED => pht('Published'), - PhameConstants::VISIBILITY_DRAFT => pht('Draft'), + ->setOptions( + array( + '' => pht('All'), + PhameConstants::VISIBILITY_PUBLISHED => pht('Published'), + PhameConstants::VISIBILITY_DRAFT => pht('Draft'), )), ); } @@ -68,6 +69,8 @@ final class PhamePostSearchEngine return parent::buildSavedQueryFromBuiltin($query_key); } + + protected function renderResultList( array $posts, PhabricatorSavedQuery $query, @@ -82,12 +85,10 @@ final class PhamePostSearchEngine foreach ($posts as $post) { $id = $post->getID(); $blog = $post->getBlog(); - if ($blog) { - $blog_name = $viewer->renderHandle($post->getBlogPHID())->render(); - $blog_name = pht('Blog: %s', $blog_name); - } else { - $blog_name = pht('[No Blog]'); - } + + $blog_name = $viewer->renderHandle($post->getBlogPHID())->render(); + $blog_name = pht('Blog: %s', $blog_name); + $item = id(new PHUIObjectItemView()) ->setUser($viewer) ->setObject($post) diff --git a/src/applications/phame/storage/PhamePost.php b/src/applications/phame/storage/PhamePost.php index 94e9c63f4a..57519bd2f1 100644 --- a/src/applications/phame/storage/PhamePost.php +++ b/src/applications/phame/storage/PhamePost.php @@ -9,7 +9,8 @@ final class PhamePost extends PhameDAO PhabricatorApplicationTransactionInterface, PhabricatorSubscribableInterface, PhabricatorDestructibleInterface, - PhabricatorTokenReceiverInterface { + PhabricatorTokenReceiverInterface, + PhabricatorConduitResultInterface { const MARKUP_FIELD_BODY = 'markup:body'; const MARKUP_FIELD_SUMMARY = 'markup:summary'; @@ -24,7 +25,7 @@ final class PhamePost extends PhameDAO protected $blogPHID; protected $mailKey; - private $blog; + private $blog = self::ATTACHABLE; public static function initializePost( PhabricatorUser $blogger, @@ -33,19 +34,20 @@ final class PhamePost extends PhameDAO $post = id(new PhamePost()) ->setBloggerPHID($blogger->getPHID()) ->setBlogPHID($blog->getPHID()) - ->setBlog($blog) + ->attachBlog($blog) ->setDatePublished(PhabricatorTime::getNow()) ->setVisibility(PhameConstants::VISIBILITY_PUBLISHED); + return $post; } - public function setBlog(PhameBlog $blog) { + public function attachBlog(PhameBlog $blog) { $this->blog = $blog; return $this; } public function getBlog() { - return $this->blog; + return $this->assertAttached($this->blog); } public function getLiveURI() { @@ -146,21 +148,6 @@ final class PhamePost extends PhameDAO return PhabricatorSlug::normalizeProjectSlug($this->getTitle(), true); } - public function toDictionary() { - return array( - 'id' => $this->getID(), - 'phid' => $this->getPHID(), - 'blogPHID' => $this->getBlogPHID(), - 'bloggerPHID' => $this->getBloggerPHID(), - 'viewURI' => $this->getViewURI(), - 'title' => $this->getTitle(), - 'body' => $this->getBody(), - 'summary' => PhabricatorMarkupEngine::summarize($this->getBody()), - 'datePublished' => $this->getDatePublished(), - 'published' => !$this->isDraft(), - ); - } - /* -( PhabricatorPolicyInterface Implementation )-------------------------- */ @@ -303,4 +290,59 @@ final class PhamePost extends PhameDAO return true; } + +/* -( PhabricatorConduitResultInterface )---------------------------------- */ + + + public function getFieldSpecificationsForConduit() { + return array( + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('title') + ->setType('string') + ->setDescription(pht('Title of the post.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('slug') + ->setType('string') + ->setDescription(pht('Slug for the post.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('blogPHID') + ->setType('phid') + ->setDescription(pht('PHID of the blog that the post belongs to.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('authorPHID') + ->setType('phid') + ->setDescription(pht('PHID of the author of the post.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('body') + ->setType('string') + ->setDescription(pht('Body of the post.')), + id(new PhabricatorConduitSearchFieldSpecification()) + ->setKey('datePublished') + ->setType('epoch?') + ->setDescription(pht('Publish date, if the post has been published.')), + + ); + } + + public function getFieldValuesForConduit() { + if ($this->isDraft()) { + $date_published = null; + } else { + $date_published = (int)$this->getDatePublished(); + } + + return array( + 'title' => $this->getTitle(), + 'slug' => $this->getSlug(), + 'blogPHID' => $this->getBlogPHID(), + 'authorPHID' => $this->getBloggerPHID(), + 'body' => $this->getBody(), + 'datePublished' => $date_published, + ); + } + + public function getConduitSearchAttachments() { + return array(); + } + }