From db8b0b9666f67fb0bd965c322bac4543f40ca230 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 20 May 2021 04:39:45 +0000 Subject: [PATCH] The next mail endpoint is done --- doc/API-Mastodon.md | 2 +- src/Factory/Api/Mastodon/Status.php | 28 ++----- src/Module/Api/Mastodon/Conversation.php | 4 +- src/Module/Api/Mastodon/Timelines/Direct.php | 84 ++++++++++++++++++++ src/Protocol/ActivityPub/Transmitter.php | 44 +++++----- static/routes.config.php | 2 +- 6 files changed, 120 insertions(+), 44 deletions(-) create mode 100644 src/Module/Api/Mastodon/Timelines/Direct.php diff --git a/doc/API-Mastodon.md b/doc/API-Mastodon.md index 5cb4535547..a734bd5445 100644 --- a/doc/API-Mastodon.md +++ b/doc/API-Mastodon.md @@ -108,6 +108,7 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en - [`POST /api/v1/statuses/:id/pin`](https://docs.joinmastodon.org/methods/statuses/) - [`POST /api/v1/statuses/:id/unpin`](https://docs.joinmastodon.org/methods/statuses/) - [`GET /api/v1/suggestions`](https://docs.joinmastodon.org/methods/accounts/suggestions/) +- [`GET /api/v1/timelines/direct`](https://docs.joinmastodon.org/methods/timelines/) - [`GET /api/v1/timelines/home`](https://docs.joinmastodon.org/methods/timelines/) - [`GET /api/v1/timelines/list/:id`](https://docs.joinmastodon.org/methods/timelines/) - [`GET /api/v1/timelines/public`](https://docs.joinmastodon.org/methods/timelines/) @@ -122,7 +123,6 @@ These emdpoints are planned to be implemented - [`PATCH /api/v1/accounts/update_credentials`](https://docs.joinmastodon.org/methods/accounts/) - [`GET /api/v1/instance/activity`](https://docs.joinmastodon.org/methods/instance#weekly-activity) -- [`GET /api/v1/timelines/direct`](https://docs.joinmastodon.org/methods/timelines/) ## Non supportable endpoints diff --git a/src/Factory/Api/Mastodon/Status.php b/src/Factory/Api/Mastodon/Status.php index 3df4e28e7b..23825591fb 100644 --- a/src/Factory/Api/Mastodon/Status.php +++ b/src/Factory/Api/Mastodon/Status.php @@ -27,11 +27,11 @@ use Friendica\Content\ContactSelector; use Friendica\Content\Text\BBCode; use Friendica\Database\DBA; use Friendica\DI; -use Friendica\Model\Item; use Friendica\Model\Post; use Friendica\Model\Verb; use Friendica\Network\HTTPException; use Friendica\Protocol\Activity; +use Friendica\Protocol\ActivityPub; use Friendica\Repository\ProfileField; use Psr\Log\LoggerInterface; @@ -128,19 +128,14 @@ class Status extends BaseFactory * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public function createFromMailId(int $id, $uid = 0) + public function createFromMailId(int $id, $uid) { - $mail = DBA::selectFirst('mail', [], ['id' => $id, 'uid' => $uid]); - if (!$mail) { + $item = ActivityPub\Transmitter::ItemArrayFromMail($id, true); + if (empty($item)) { DI::mstdnError()->RecordNotFound(); } - $conv = DBA::selectFirst('conv', ['subject'], ['id' => $mail['convid'], 'uid' => $uid]); - if (!$conv) { - DI::mstdnError()->RecordNotFound(); - } - - $account = DI::mstdnAccount()->createFromContactId($mail['contact-id']); + $account = DI::mstdnAccount()->createFromContactId($item['author-id']); $counts = new \Friendica\Object\Api\Mastodon\Status\Counts(0, 0, 0); @@ -154,19 +149,6 @@ class Status extends BaseFactory $attachments = []; $reshare = []; - $item = [ - 'uri-id' => $mail['id'], - 'created' => $mail['created'], - 'thr-parent-id' => 0, - 'parent-author-id' => 0, - 'title' => $conv['subject'], - 'private' => Item::PRIVATE, - 'language' => '', - 'uri' => $mail['uri'], - 'plink' => '', - 'body' => BBCode::convert($mail['body'], false, BBCode::API) - ]; - return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts, $userAttributes, $sensitive, $application, $mentions, $tags, $card, $attachments, $reshare); } } diff --git a/src/Module/Api/Mastodon/Conversation.php b/src/Module/Api/Mastodon/Conversation.php index c1badcdc4a..e87818ac27 100644 --- a/src/Module/Api/Mastodon/Conversation.php +++ b/src/Module/Api/Mastodon/Conversation.php @@ -84,10 +84,12 @@ class Conversation extends BaseApi $conversations = []; - foreach ($convs as $conv) { + while ($conv = DBA::fetch($convs)) { $conversations[] = DI::mstdnConversation()->CreateFromConvId($conv['id']); } + DBA::close($convs); + if (!empty($request['min_id'])) { array_reverse($conversations); } diff --git a/src/Module/Api/Mastodon/Timelines/Direct.php b/src/Module/Api/Mastodon/Timelines/Direct.php new file mode 100644 index 0000000000..5c454f2f6b --- /dev/null +++ b/src/Module/Api/Mastodon/Timelines/Direct.php @@ -0,0 +1,84 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Timelines; + +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Post; +use Friendica\Module\BaseApi; +use Friendica\Network\HTTPException; + +/** + * @see https://docs.joinmastodon.org/methods/timelines/ + */ +class Direct extends BaseApi +{ + /** + * @param array $parameters + * @throws HTTPException\InternalServerErrorException + */ + public static function rawContent(array $parameters = []) + { + self::login(self::SCOPE_READ); + $uid = self::getCurrentUserID(); + + $request = self::getRequest([ + 'max_id' => 0, // Return results older than id + 'since_id' => 0, // Return results newer than id + 'min_id' => 0, // Return results immediately newer than id + 'limit' => 20, // Maximum number of results to return. Defaults to 20. + ]); + + $params = ['order' => ['id' => true], 'limit' => $request['limit']]; + + $condition = ['uid' => $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']; + } + + $mails = DBA::select('mail', ['id', 'uid'], $condition, $params); + + $statuses = []; + + while ($mail = DBA::fetch($mails)) { + $statuses[] = DI::mstdnStatus()->createFromMailId($mail['id'], $mail['uid']); + } + + if (!empty($request['min_id'])) { + array_reverse($statuses); + } + + System::jsonExit($statuses); + } +} diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index 9773a5a48b..20c1e49b88 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -861,7 +861,7 @@ class Transmitter * @return array * @throws \Exception */ - public static function ItemArrayFromMail($mail_id) + public static function ItemArrayFromMail($mail_id, $use_title = false) { $mail = DBA::selectFirst('mail', [], ['id' => $mail_id]); if (!DBA::isResult($mail)) { @@ -870,29 +870,37 @@ class Transmitter $mail['uri-id'] = ItemURI::insert(['uri' => $mail['uri'], 'guid' => $mail['guid']]); - $reply = DBA::selectFirst('mail', ['uri'], ['parent-uri' => $mail['parent-uri'], 'reply' => false]); + $reply = DBA::selectFirst('mail', ['uri', 'from-url', 'guid'], ['parent-uri' => $mail['parent-uri'], 'reply' => false]); // Making the post more compatible for Mastodon by: // - Making it a note and not an article (no title) // - Moving the title into the "summary" field that is used as a "content warning" - $mail['body'] = '[abstract]' . $mail['title'] . "[/abstract]\n" . $mail['body']; - $mail['title'] = ''; - $mail['author-link'] = $mail['owner-link'] = $mail['from-url']; - $mail['allow_cid'] = '<'.$mail['contact-id'].'>'; - $mail['allow_gid'] = ''; - $mail['deny_cid'] = ''; - $mail['deny_gid'] = ''; - $mail['private'] = true; - $mail['deleted'] = false; - $mail['edited'] = $mail['created']; - $mail['plink'] = $mail['uri']; - $mail['thr-parent'] = $reply['uri']; - $mail['gravity'] = ($mail['reply'] ? GRAVITY_COMMENT: GRAVITY_PARENT); + if ($use_title) { + $mail['body'] = $mail['body']; + $mail['title'] = $mail['title']; + } else { + $mail['body'] = '[abstract]' . $mail['title'] . "[/abstract]\n" . $mail['body']; + $mail['title'] = ''; + } - $mail['event-type'] = ''; - - $mail['parent'] = 0; + $mail['author-link'] = $mail['owner-link'] = $mail['from-url']; + $mail['author-id'] = Contact::getIdForURL($mail['author-link'], 0, false); + $mail['allow_cid'] = '<'.$mail['contact-id'].'>'; + $mail['allow_gid'] = ''; + $mail['deny_cid'] = ''; + $mail['deny_gid'] = ''; + $mail['private'] = Item::PRIVATE; + $mail['deleted'] = false; + $mail['edited'] = $mail['created']; + $mail['plink'] = $mail['uri']; + $mail['thr-parent'] = $reply['uri']; + $mail['thr-parent-id'] = ItemURI::insert(['uri' => $reply['uri'], 'guid' => $reply['guid']]); + $mail['parent-author-id'] = Contact::getIdForURL($reply['from-url'], 0, false); + $mail['gravity'] = ($mail['reply'] ? GRAVITY_COMMENT: GRAVITY_PARENT); + $mail['event-type'] = ''; + $mail['language'] = ''; + $mail['parent'] = 0; return $mail; } diff --git a/static/routes.config.php b/static/routes.config.php index 6b87d55bce..80b1aadeb8 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -142,7 +142,7 @@ return [ '/statuses/{id:\d+}/unpin' => [Module\Api\Mastodon\Statuses\Unpin::class, [ R::POST]], '/suggestions' => [Module\Api\Mastodon\Suggestions::class, [R::GET ]], '/suggestions/{id:\d+}' => [Module\Api\Mastodon\Unimplemented::class, [R::DELETE ]], // not implemented - '/timelines/direct' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // @todo + '/timelines/direct' => [Module\Api\Mastodon\Timelines\Direct::class, [R::GET ]], '/timelines/home' => [Module\Api\Mastodon\Timelines\Home::class, [R::GET ]], '/timelines/list/{id:\d+}' => [Module\Api\Mastodon\Timelines\ListTimeline::class, [R::GET ]], '/timelines/public' => [Module\Api\Mastodon\Timelines\PublicTimeline::class, [R::GET ]],