1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-19 12:00:55 +01:00

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
This commit is contained in:
epriestley 2015-12-28 04:25:01 -08:00
parent b74f93f229
commit 00f1389f72
5 changed files with 125 additions and 63 deletions

View file

@ -3440,6 +3440,7 @@ phutil_register_library_map(array(
'PhamePostPublishController' => 'applications/phame/controller/post/PhamePostPublishController.php', 'PhamePostPublishController' => 'applications/phame/controller/post/PhamePostPublishController.php',
'PhamePostQuery' => 'applications/phame/query/PhamePostQuery.php', 'PhamePostQuery' => 'applications/phame/query/PhamePostQuery.php',
'PhamePostReplyHandler' => 'applications/phame/mail/PhamePostReplyHandler.php', 'PhamePostReplyHandler' => 'applications/phame/mail/PhamePostReplyHandler.php',
'PhamePostSearchConduitAPIMethod' => 'applications/phame/conduit/PhamePostSearchConduitAPIMethod.php',
'PhamePostSearchEngine' => 'applications/phame/query/PhamePostSearchEngine.php', 'PhamePostSearchEngine' => 'applications/phame/query/PhamePostSearchEngine.php',
'PhamePostTransaction' => 'applications/phame/storage/PhamePostTransaction.php', 'PhamePostTransaction' => 'applications/phame/storage/PhamePostTransaction.php',
'PhamePostTransactionComment' => 'applications/phame/storage/PhamePostTransactionComment.php', 'PhamePostTransactionComment' => 'applications/phame/storage/PhamePostTransactionComment.php',
@ -7886,6 +7887,7 @@ phutil_register_library_map(array(
'PhabricatorSubscribableInterface', 'PhabricatorSubscribableInterface',
'PhabricatorDestructibleInterface', 'PhabricatorDestructibleInterface',
'PhabricatorTokenReceiverInterface', 'PhabricatorTokenReceiverInterface',
'PhabricatorConduitResultInterface',
), ),
'PhamePostCommentController' => 'PhamePostController', 'PhamePostCommentController' => 'PhamePostController',
'PhamePostController' => 'PhameController', 'PhamePostController' => 'PhameController',
@ -7900,6 +7902,7 @@ phutil_register_library_map(array(
'PhamePostPublishController' => 'PhamePostController', 'PhamePostPublishController' => 'PhamePostController',
'PhamePostQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhamePostQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhamePostReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhamePostReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
'PhamePostSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
'PhamePostSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhamePostSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhamePostTransaction' => 'PhabricatorApplicationTransaction', 'PhamePostTransaction' => 'PhabricatorApplicationTransaction',
'PhamePostTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhamePostTransactionComment' => 'PhabricatorApplicationTransactionComment',

View file

@ -0,0 +1,18 @@
<?php
final class PhamePostSearchConduitAPIMethod
extends PhabricatorSearchEngineAPIMethod {
public function getAPIMethodName() {
return 'phame.post.search';
}
public function newSearchEngine() {
return new PhamePostSearchEngine();
}
public function getMethodSummary() {
return pht('Read information about blog posts.');
}
}

View file

@ -39,38 +39,36 @@ final class PhamePostQuery extends PhabricatorCursorPagedPolicyAwareQuery {
return $this; return $this;
} }
public function newResultObject() {
return new PhamePost();
}
protected function loadPage() { protected function loadPage() {
$table = new PhamePost(); return $this->loadStandardPage($this->newResultObject());
$conn_r = $table->establishConnection('r'); }
$where_clause = $this->buildWhereClause($conn_r); protected function willFilterPage(array $posts) {
$order_clause = $this->buildOrderClause($conn_r); // We require blogs to do visibility checks, so load them unconditionally.
$limit_clause = $this->buildLimitClause($conn_r); $blog_phids = mpull($posts, 'getBlogPHID');
$data = queryfx_all( $blogs = id(new PhameBlogQuery())
$conn_r, ->setViewer($this->getViewer())
'SELECT * FROM %T p %Q %Q %Q', ->needProfileImage(true)
$table->getTableName(), ->withPHIDs($blog_phids)
$where_clause, ->execute();
$order_clause,
$limit_clause);
$posts = $table->loadAllFromArray($data); $blogs = mpull($blogs, null, 'getPHID');
foreach ($posts as $key => $post) {
$blog_phid = $post->getBlogPHID();
if ($posts) { $blog = idx($blogs, $blog_phid);
// We require these to do visibility checks, so load them unconditionally. if (!$blog) {
$blog_phids = mpull($posts, 'getBlogPHID'); $this->didRejectResult($post);
$blogs = id(new PhameBlogQuery()) unset($posts[$key]);
->setViewer($this->getViewer()) continue;
->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()]);
}
} }
$post->attachBlog($blog);
} }
return $posts; return $posts;
@ -82,42 +80,42 @@ final class PhamePostQuery extends PhabricatorCursorPagedPolicyAwareQuery {
if ($this->ids) { if ($this->ids) {
$where[] = qsprintf( $where[] = qsprintf(
$conn, $conn,
'p.id IN (%Ld)', 'id IN (%Ld)',
$this->ids); $this->ids);
} }
if ($this->phids) { if ($this->phids) {
$where[] = qsprintf( $where[] = qsprintf(
$conn, $conn,
'p.phid IN (%Ls)', 'phid IN (%Ls)',
$this->phids); $this->phids);
} }
if ($this->bloggerPHIDs) { if ($this->bloggerPHIDs) {
$where[] = qsprintf( $where[] = qsprintf(
$conn, $conn,
'p.bloggerPHID IN (%Ls)', 'bloggerPHID IN (%Ls)',
$this->bloggerPHIDs); $this->bloggerPHIDs);
} }
if ($this->visibility !== null) { if ($this->visibility !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn, $conn,
'p.visibility = %d', 'visibility = %d',
$this->visibility); $this->visibility);
} }
if ($this->publishedAfter !== null) { if ($this->publishedAfter !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn, $conn,
'p.datePublished > %d', 'datePublished > %d',
$this->publishedAfter); $this->publishedAfter);
} }
if ($this->blogPHIDs) { if ($this->blogPHIDs !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn, $conn,
'p.blogPHID in (%Ls)', 'blogPHID in (%Ls)',
$this->blogPHIDs); $this->blogPHIDs);
} }

View file

@ -30,10 +30,11 @@ final class PhamePostSearchEngine
id(new PhabricatorSearchSelectField()) id(new PhabricatorSearchSelectField())
->setKey('visibility') ->setKey('visibility')
->setLabel(pht('Visibility')) ->setLabel(pht('Visibility'))
->setOptions(array( ->setOptions(
'' => pht('All'), array(
PhameConstants::VISIBILITY_PUBLISHED => pht('Published'), '' => pht('All'),
PhameConstants::VISIBILITY_DRAFT => pht('Draft'), PhameConstants::VISIBILITY_PUBLISHED => pht('Published'),
PhameConstants::VISIBILITY_DRAFT => pht('Draft'),
)), )),
); );
} }
@ -68,6 +69,8 @@ final class PhamePostSearchEngine
return parent::buildSavedQueryFromBuiltin($query_key); return parent::buildSavedQueryFromBuiltin($query_key);
} }
protected function renderResultList( protected function renderResultList(
array $posts, array $posts,
PhabricatorSavedQuery $query, PhabricatorSavedQuery $query,
@ -82,12 +85,10 @@ final class PhamePostSearchEngine
foreach ($posts as $post) { foreach ($posts as $post) {
$id = $post->getID(); $id = $post->getID();
$blog = $post->getBlog(); $blog = $post->getBlog();
if ($blog) {
$blog_name = $viewer->renderHandle($post->getBlogPHID())->render(); $blog_name = $viewer->renderHandle($post->getBlogPHID())->render();
$blog_name = pht('Blog: %s', $blog_name); $blog_name = pht('Blog: %s', $blog_name);
} else {
$blog_name = pht('[No Blog]');
}
$item = id(new PHUIObjectItemView()) $item = id(new PHUIObjectItemView())
->setUser($viewer) ->setUser($viewer)
->setObject($post) ->setObject($post)

View file

@ -9,7 +9,8 @@ final class PhamePost extends PhameDAO
PhabricatorApplicationTransactionInterface, PhabricatorApplicationTransactionInterface,
PhabricatorSubscribableInterface, PhabricatorSubscribableInterface,
PhabricatorDestructibleInterface, PhabricatorDestructibleInterface,
PhabricatorTokenReceiverInterface { PhabricatorTokenReceiverInterface,
PhabricatorConduitResultInterface {
const MARKUP_FIELD_BODY = 'markup:body'; const MARKUP_FIELD_BODY = 'markup:body';
const MARKUP_FIELD_SUMMARY = 'markup:summary'; const MARKUP_FIELD_SUMMARY = 'markup:summary';
@ -24,7 +25,7 @@ final class PhamePost extends PhameDAO
protected $blogPHID; protected $blogPHID;
protected $mailKey; protected $mailKey;
private $blog; private $blog = self::ATTACHABLE;
public static function initializePost( public static function initializePost(
PhabricatorUser $blogger, PhabricatorUser $blogger,
@ -33,19 +34,20 @@ final class PhamePost extends PhameDAO
$post = id(new PhamePost()) $post = id(new PhamePost())
->setBloggerPHID($blogger->getPHID()) ->setBloggerPHID($blogger->getPHID())
->setBlogPHID($blog->getPHID()) ->setBlogPHID($blog->getPHID())
->setBlog($blog) ->attachBlog($blog)
->setDatePublished(PhabricatorTime::getNow()) ->setDatePublished(PhabricatorTime::getNow())
->setVisibility(PhameConstants::VISIBILITY_PUBLISHED); ->setVisibility(PhameConstants::VISIBILITY_PUBLISHED);
return $post; return $post;
} }
public function setBlog(PhameBlog $blog) { public function attachBlog(PhameBlog $blog) {
$this->blog = $blog; $this->blog = $blog;
return $this; return $this;
} }
public function getBlog() { public function getBlog() {
return $this->blog; return $this->assertAttached($this->blog);
} }
public function getLiveURI() { public function getLiveURI() {
@ -146,21 +148,6 @@ final class PhamePost extends PhameDAO
return PhabricatorSlug::normalizeProjectSlug($this->getTitle(), true); 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 )-------------------------- */ /* -( PhabricatorPolicyInterface Implementation )-------------------------- */
@ -303,4 +290,59 @@ final class PhamePost extends PhameDAO
return true; 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();
}
} }