diff --git a/src/Content/Widget/SavedSearches.php b/src/Content/Widget/SavedSearches.php index 6b6202ba32..1bf9e76a26 100644 --- a/src/Content/Widget/SavedSearches.php +++ b/src/Content/Widget/SavedSearches.php @@ -37,7 +37,7 @@ class SavedSearches public static function getHTML(string $return_url, string $search = ''): string { $saved = []; - $saved_searches = DBA::select('search', ['id', 'term'], ['uid' => DI::userSession()->getLocalUserId()]); + $saved_searches = DBA::select('search', ['id', 'term'], ['uid' => DI::userSession()->getLocalUserId()], ['order' => ['term']]); while ($saved_search = DBA::fetch($saved_searches)) { $saved[] = [ 'id' => $saved_search['id'], diff --git a/src/Module/Api/Mastodon/FollowedTags.php b/src/Module/Api/Mastodon/FollowedTags.php new file mode 100644 index 0000000000..6e95783c9f --- /dev/null +++ b/src/Module/Api/Mastodon/FollowedTags.php @@ -0,0 +1,83 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon; + +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/followed_tags/ + */ +class FollowedTags extends BaseApi +{ + protected function rawContent(array $request = []) + { + self::checkAllowedScope(self::SCOPE_READ); + $uid = self::getCurrentUserID(); + + $request = $this->getRequest([ + 'max_id' => 0, + 'since_id' => 0, + 'min_id' => 0, + 'limit' => 100, // Maximum number of results to return. Defaults to 100. Paginate using the HTTP Link header. + ], $request); + + $params = ['order' => ['id' => true], 'limit' => $request['limit']]; + + $condition = ["`uid` = ? AND `term` LIKE ?", $uid, '#%']; + + if (!empty($request['max_id'])) { + $condition = DBA::mergeConditions($condition, ["`id` < ?", $request['max_id']]); + } + + if (!empty($request['since_id'])) { + $condition = DBA::mergeConditions($condition, ["`id` > ?", $request['since_id']]); + } + + if (!empty($request['min_id'])) { + $condition = DBA::mergeConditions($condition, ["`id` > ?", $request['min_id']]); + + $params['order'] = ['id']; + } + + $return = []; + + $saved_searches = DBA::select('search', ['id', 'term'], $condition); + while ($saved_search = DBA::fetch($saved_searches)) { + self::setBoundaries($saved_search['id']); + $tag = ['name' => substr($saved_search['term'], 1)]; + + $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $tag, [], true); + $return[] = $hashtag->toArray(); + } + + DBA::close($saved_searches); + + if (!empty($request['min_id'])) { + $return = array_reverse($return); + } + + self::setLinkHeader(); + System::jsonExit($return); + } +} diff --git a/src/Module/Api/Mastodon/Tags.php b/src/Module/Api/Mastodon/Tags.php index 97631b506a..442f0f6576 100644 --- a/src/Module/Api/Mastodon/Tags.php +++ b/src/Module/Api/Mastodon/Tags.php @@ -21,8 +21,8 @@ namespace Friendica\Module\Api\Mastodon; -use Friendica\App\Router; -use Friendica\Core\Logger; +use Friendica\Core\System; +use Friendica\Database\DBA; use Friendica\DI; use Friendica\Module\BaseApi; @@ -43,6 +43,11 @@ class Tags extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $this->response->unsupported(Router::GET, $request); + $tag = ltrim($this->parameters['hashtag'], '#'); + $following = DBA::exists('search', ['uid' => $uid, 'term' => '#' . $tag]); + $term = ['term' => $tag]; + + $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $term, [], $following); + System::jsonExit($hashtag->toArray()); } } diff --git a/src/Module/Api/Mastodon/Tags/Follow.php b/src/Module/Api/Mastodon/Tags/Follow.php index 9a813f7257..e2261f3fd5 100644 --- a/src/Module/Api/Mastodon/Tags/Follow.php +++ b/src/Module/Api/Mastodon/Tags/Follow.php @@ -21,7 +21,8 @@ namespace Friendica\Module\Api\Mastodon\Tags; -use Friendica\App\Router; +use Friendica\Core\System; +use Friendica\Database\DBA; use Friendica\DI; use Friendica\Module\BaseApi; @@ -39,6 +40,12 @@ class Follow extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $this->response->unsupported(Router::POST, $request); + $fields = ['uid' => $uid, 'term' => '#' . $this->parameters['hashtag']]; + if (!DBA::exists('search', $fields)) { + DBA::insert('search', $fields); + } + + $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $fields, [], true); + System::jsonExit($hashtag->toArray()); } } diff --git a/src/Module/Api/Mastodon/Tags/Unfollow.php b/src/Module/Api/Mastodon/Tags/Unfollow.php index a20b824b8d..465c1974b5 100644 --- a/src/Module/Api/Mastodon/Tags/Unfollow.php +++ b/src/Module/Api/Mastodon/Tags/Unfollow.php @@ -21,7 +21,8 @@ namespace Friendica\Module\Api\Mastodon\Tags; -use Friendica\App\Router; +use Friendica\Core\System; +use Friendica\Database\DBA; use Friendica\DI; use Friendica\Module\BaseApi; @@ -39,6 +40,11 @@ class Unfollow extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $this->response->unsupported(Router::POST, $request); + $term = ['uid' => $uid, 'term' => '#' . $this->parameters['hashtag']]; + + DBA::delete('search', $term); + + $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $term, [], false); + System::jsonExit($hashtag->toArray()); } } diff --git a/src/Object/Api/Mastodon/Tag.php b/src/Object/Api/Mastodon/Tag.php index 340e30f703..e40b793e26 100644 --- a/src/Object/Api/Mastodon/Tag.php +++ b/src/Object/Api/Mastodon/Tag.php @@ -37,18 +37,23 @@ class Tag extends BaseDataTransferObject protected $url = null; /** @var array */ protected $history = []; + /** @var bool */ + protected $following = false; /** * Creates a hashtag record from an tag-view record. * * @param BaseURL $baseUrl - * @param array $tag tag-view record + * @param array $tag tag-view record + * @param array $history + * @param array $following "true" if the user is following this tag * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public function __construct(BaseURL $baseUrl, array $tag, array $history = []) + public function __construct(BaseURL $baseUrl, array $tag, array $history = [], bool $following = false) { - $this->name = strtolower($tag['name']); - $this->url = $baseUrl . '/search?tag=' . urlencode($this->name); - $this->history = $history; + $this->name = strtolower($tag['name']); + $this->url = $baseUrl . '/search?tag=' . urlencode($this->name); + $this->history = $history; + $this->following = $following; } } diff --git a/static/routes.config.php b/static/routes.config.php index 07c2b45508..42333e65fa 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -236,7 +236,7 @@ return [ '/filters/{id:\d+}' => [Module\Api\Mastodon\Unimplemented::class, [R::GET, R::POST, R::PUT, R::DELETE]], // not supported '/follow_requests' => [Module\Api\Mastodon\FollowRequests::class, [R::GET ]], '/follow_requests/{id:\d+}/{action}' => [Module\Api\Mastodon\FollowRequests::class, [ R::POST]], - '/followed_tags' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // @todo + '/followed_tags' => [Module\Api\Mastodon\FollowedTags::class, [R::GET ]], '/instance' => [Module\Api\Mastodon\Instance::class, [R::GET ]], '/instance/activity' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // @todo '/instance/peers' => [Module\Api\Mastodon\Instance\Peers::class, [R::GET ]],