From 61afd5b3fbed6e9af011a9262db9cbeb474152db Mon Sep 17 00:00:00 2001 From: root <17hado.com@gmail.com> Date: Fri, 21 Dec 2018 16:00:56 +0000 Subject: [PATCH] refs #6292 APIs show number of comments - /api/statuses/*_timeline - /api/search - /api/favorites /api/search enhacement - support exclude_replies parameter --- doc/api.md | 6 ++++- include/api.php | 49 ++++++++++++++++++++++++++++++++++++++- tests/include/ApiTest.php | 14 +++++++++++ 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/doc/api.md b/doc/api.md index 0f2243b5c..f58419417 100644 --- a/doc/api.md +++ b/doc/api.md @@ -657,6 +657,7 @@ Friendica adds some addictional fields: - owner: a user object, it's the owner of the item. - private: boolean, true if the item is marked as private - activities: map with activities related to the item. Every activity is a list of user objects. +- comments: comment numbers This properties are prefixed with "friendica_" in JSON responses and namespaced under "http://friendi.ca/schema/api/1/" in XML responses @@ -681,7 +682,8 @@ JSON: 'attendyes': [], 'attendno': [], 'attendmaybe': [] - } + }, + 'friendica_comments': 12 }, // ... ] @@ -707,6 +709,7 @@ XML: + 21 @@ -756,6 +759,7 @@ Friendica doesn't allow showing followers of other users. * count: alias for the rpp parameter * since_id: returns statuses with ids greater than the given id * max_id: returns statuses with ids lower or equal to the given id +* exclude_replies: don't show replies (default: false) #### Unsupported parameters diff --git a/include/api.php b/include/api.php index 4f4f1c588..fe5cc9168 100644 --- a/include/api.php +++ b/include/api.php @@ -1527,6 +1527,7 @@ function api_search($type) $data = []; $count = 15; + $exclude_replies = !empty($_REQUEST['exclude_replies']); if (!empty($_REQUEST['rpp'])) { $count = $_REQUEST['rpp']; } elseif (!empty($_REQUEST['count'])) { @@ -1552,9 +1553,12 @@ function api_search($type) $itemIds = []; while($term = DBA::fetch($terms)){ $itemIds[] = $term['oid']; } DBA::close($terms); - $condition = ['id' => empty($itemIds) ? [0] : $itemIds ]; + $condition = [$exclude_replies ? "`id` = `parent` AND " : '']; + $condition[0] .= empty($itemIds) ? '' : ' `id` IN ('.implode(", ", $itemIds).')' ; + } else { $condition = ["`id` > ? + ". ($exclude_replies ? " AND `id` = `parent` " : ' ')." AND (`uid` = 0 OR (`uid` = ? AND NOT `global`)) AND `body` LIKE CONCAT('%',?,'%')", $since_id, api_user(), $_REQUEST['q']]; @@ -1569,6 +1573,8 @@ function api_search($type) $data['status'] = api_format_items(Item::inArray($statuses), $user_info); + bindComments($data['status']); + return api_format_data("statuses", $type, $data); } @@ -1650,6 +1656,8 @@ function api_statuses_home_timeline($type) Item::update(['unseen' => false], ['unseen' => true, 'id' => $idarray]); } } + + bindComments($ret); $data = ['status' => $ret]; switch ($type) { @@ -1663,6 +1671,7 @@ function api_statuses_home_timeline($type) return api_format_data("statuses", $type, $data); } + /// @TODO move to top of file or somewhere better api_register_func('api/statuses/home_timeline', 'api_statuses_home_timeline', true); api_register_func('api/statuses/friends_timeline', 'api_statuses_home_timeline', true); @@ -1732,6 +1741,8 @@ function api_statuses_public_timeline($type) $ret = api_format_items($r, $user_info, false, $type); + bindComments($ret); + $data = ['status' => $ret]; switch ($type) { case "atom": @@ -1789,6 +1800,8 @@ function api_statuses_networkpublic_timeline($type) $ret = api_format_items(Item::inArray($statuses), $user_info, false, $type); + bindComments($ret); + $data = ['status' => $ret]; switch ($type) { case "atom": @@ -2192,6 +2205,8 @@ function api_statuses_user_timeline($type) $ret = api_format_items(Item::inArray($statuses), $user_info, true, $type); + bindComments($ret); + $data = ['status' => $ret]; switch ($type) { case "atom": @@ -2337,6 +2352,8 @@ function api_favorites($type) $ret = api_format_items(Item::inArray($statuses), $user_info, false, $type); } + bindComments($ret); + $data = ['status' => $ret]; switch ($type) { case "atom": @@ -5968,6 +5985,36 @@ function api_saved_searches_list($type) /// @TODO move to top of file or somewhere better api_register_func('api/saved_searches/list', 'api_saved_searches_list', true); +/* + * Bind comment numbers(friendica_comments: Int) on each statuses page of *_timeline / favorites / search + * + * @brief Number of comments + * + * @param object $data [Status, Status] + * + * @return void + */ +function bindComments(&$data){ + if(count($data) == 0) return; + + $ids = []; + $comments = []; + foreach($data as $item){ $ids[] = $item['id']; } + + $sql = "SELECT `parent`,COUNT(*) as comments FROM `item` + WHERE `parent` IN ( %s ) AND `deleted` = %d AND `gravity`= %d GROUP BY `parent`"; + $result = q($sql, implode(",", $ids), 0, GRAVITY_COMMENT); + + foreach($result as $records) { + $comments[$records['parent']] = $records['comments']; + } + + foreach($data as $idx => $item){ + $id = $item['id']; + $data[$idx]['friendica_comments'] = isset($comments[$id]) ? $comments[$id] : 0; + } +} + /* @TODO Maybe open to implement? To.Do: diff --git a/tests/include/ApiTest.php b/tests/include/ApiTest.php index 09ca95200..19b82bf84 100644 --- a/tests/include/ApiTest.php +++ b/tests/include/ApiTest.php @@ -1419,6 +1419,20 @@ class ApiTest extends DatabaseTest } } + /** + * Test the api_search() function with an exclude_replies parameter. + * @return void + */ + public function testApiSearchWithExcludeReplies() + { + $_REQUEST['max_id'] = 10; + $_REQUEST['exclude_replies'] = true; + $result = api_search('json'); + foreach ($result['status'] as $status) { + $this->assertStatus($status); + } + } + /** * Test the api_search() function without an authenticated user. * @return void