diff --git a/doc/API-Mastodon.md b/doc/API-Mastodon.md index 9a50d9e59..278f5540e 100644 --- a/doc/API-Mastodon.md +++ b/doc/API-Mastodon.md @@ -47,6 +47,7 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en - [`GET /api/v1/accounts/:id/followers`](https://docs.joinmastodon.org/methods/accounts/) - [`GET /api/v1/accounts/:id/following`](https://docs.joinmastodon.org/methods/accounts/) - [`GET /api/v1/accounts/:id/lists`](https://docs.joinmastodon.org/methods/accounts/) +- [`GET /api/v1/accounts/relationships`](https://docs.joinmastodon.org/methods/accounts/) - [`GET /api/v1/accounts/search`](https://docs.joinmastodon.org/methods/accounts) - [`GET /api/v1/accounts/verify_credentials`](https://docs.joinmastodon.org/methods/accounts) - [`POST /api/v1/apps`](https://docs.joinmastodon.org/methods/apps/) @@ -84,11 +85,24 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en - [`GET /api/v1/mutes`](https://docs.joinmastodon.org/methods/accounts/mutes/) - [`GET /api/v1/notifications`](https://docs.joinmastodon.org/methods/notifications/) - [`GET /api/v1/notifications/:id`](https://docs.joinmastodon.org/methods/notifications/) +- [`POST /api/v1/notifications/clear`](https://docs.joinmastodon.org/methods/notifications/) +- [`POST /api/v1/notifications/:id/dismiss`](https://docs.joinmastodon.org/methods/notifications/) - [`GET /api/v1/preferences`](https://docs.joinmastodon.org/methods/accounts/preferences/) - [`GET /api/v1/statuses/:id`](https://docs.joinmastodon.org/methods/statuses/) +- [`DELETE /api/v1/statuses/:id`](https://docs.joinmastodon.org/methods/statuses/) - [`GET /api/v1/statuses/:id/context`](https://docs.joinmastodon.org/methods/statuses/) - [`GET /api/v1/statuses/:id/reblogged_by`](https://docs.joinmastodon.org/methods/statuses/) - [`GET /api/v1/statuses/:id/favourited_by`](https://docs.joinmastodon.org/methods/statuses/) +- [`POST /api/v1/statuses/:id/favourite`](https://docs.joinmastodon.org/methods/statuses/) +- [`POST /api/v1/statuses/:id/unfavourite`](https://docs.joinmastodon.org/methods/statuses/) +- [`POST /api/v1/statuses/:id/reblog`](https://docs.joinmastodon.org/methods/statuses/) +- [`POST /api/v1/statuses/:id/unreblog`](https://docs.joinmastodon.org/methods/statuses/) +- [`POST /api/v1/statuses/:id/bookmark`](https://docs.joinmastodon.org/methods/statuses/) +- [`POST /api/v1/statuses/:id/unbookmark`](https://docs.joinmastodon.org/methods/statuses/) +- [`POST /api/v1/statuses/:id/mute`](https://docs.joinmastodon.org/methods/statuses/) +- [`POST /api/v1/statuses/:id/unmute`](https://docs.joinmastodon.org/methods/statuses/) +- [`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/home`](https://docs.joinmastodon.org/methods/timelines/) - [`GET /api/v1/timelines/list/:id`](https://docs.joinmastodon.org/methods/timelines/) @@ -102,7 +116,6 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en These emdpoints are planned to be implemented - [`POST /api/v1/accounts/:id/note`](https://docs.joinmastodon.org/methods/accounts/) -- [`GET /api/v1/accounts/relationships`](https://docs.joinmastodon.org/methods/accounts/) - [`PATCH /api/v1/accounts/update_credentials`](https://docs.joinmastodon.org/methods/accounts/) - [`GET /api/v1/apps/verify_credentials`](https://docs.joinmastodon.org/methods/apps/) - [`GET /api/v1/conversations`](https://docs.joinmastodon.org/methods/timelines/conversations/) @@ -111,27 +124,13 @@ These emdpoints are planned to be implemented - [`GET /api/v1/instance/activity`](https://docs.joinmastodon.org/methods/instance#weekly-activity) - [`POST /api/v1/media`](https://docs.joinmastodon.org/methods/statuses/media/) - [`PUT /api/v1/media/:id`](https://docs.joinmastodon.org/methods/statuses/media/) -- [`POST /api/v1/notifications/clear`](https://docs.joinmastodon.org/methods/notifications/) -- [`POST /api/v1/notifications/:id/dismiss`](https://docs.joinmastodon.org/methods/notifications/) - [`POST /api/v1/statuses`](https://docs.joinmastodon.org/methods/statuses/) -- [`DELETE /api/v1/statuses/:id`](https://docs.joinmastodon.org/methods/statuses/) -- [`POST /api/v1/statuses/:id/favourite`](https://docs.joinmastodon.org/methods/statuses/) -- [`POST /api/v1/statuses/:id/unfavourite`](https://docs.joinmastodon.org/methods/statuses/) -- [`POST /api/v1/statuses/:id/reblog`](https://docs.joinmastodon.org/methods/statuses/) -- [`POST /api/v1/statuses/:id/unreblog`](https://docs.joinmastodon.org/methods/statuses/) -- [`POST /api/v1/statuses/:id/bookmark`](https://docs.joinmastodon.org/methods/statuses/) -- [`POST /api/v1/statuses/:id/unbookmark`](https://docs.joinmastodon.org/methods/statuses/) -- [`POST /api/v1/statuses/:id/mute`](https://docs.joinmastodon.org/methods/statuses/) -- [`POST /api/v1/statuses/:id/unmute`](https://docs.joinmastodon.org/methods/statuses/) -- [`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/timelines/direct`](https://docs.joinmastodon.org/methods/timelines/) ## Non supportable endpoints These endpoints won't be implemented, since they refer to functionality that doesn't exist in Friendica -- [`GET /api/v1/instance/activity`](https://docs.joinmastodon.org/methods/instance#weekly-activity) - [`POST /api/v1/accounts`](https://docs.joinmastodon.org/methods/accounts/) - [`GET /api/v1/accounts/:id/identity_proofs`](https://docs.joinmastodon.org/methods/accounts/) - [`POST /api/v1/accounts/:id/pin`](https://docs.joinmastodon.org/methods/accounts/) diff --git a/src/Factory/Api/Mastodon/Status.php b/src/Factory/Api/Mastodon/Status.php index 866cfe802..cc8b7e6d8 100644 --- a/src/Factory/Api/Mastodon/Status.php +++ b/src/Factory/Api/Mastodon/Status.php @@ -71,14 +71,14 @@ class Status extends BaseFactory $account = DI::mstdnAccount()->createFromContactId($item['author-id']); $counts = new \Friendica\Object\Api\Mastodon\Status\Counts( - Post::count(['thr-parent-id' => $uriId, 'gravity' => GRAVITY_COMMENT], [], false), - Post::count(['thr-parent-id' => $uriId, 'gravity' => GRAVITY_ACTIVITY, 'vid' => Verb::getID(Activity::ANNOUNCE)], [], false), - Post::count(['thr-parent-id' => $uriId, 'gravity' => GRAVITY_ACTIVITY, 'vid' => Verb::getID(Activity::LIKE)], [], false) + Post::count(['thr-parent-id' => $uriId, 'gravity' => GRAVITY_COMMENT, 'deleted' => false], [], false), + Post::count(['thr-parent-id' => $uriId, 'gravity' => GRAVITY_ACTIVITY, 'vid' => Verb::getID(Activity::ANNOUNCE), 'deleted' => false], [], false), + Post::count(['thr-parent-id' => $uriId, 'gravity' => GRAVITY_ACTIVITY, 'vid' => Verb::getID(Activity::LIKE), 'deleted' => false], [], false) ); $userAttributes = new \Friendica\Object\Api\Mastodon\Status\UserAttributes( - Post::exists(['thr-parent-id' => $uriId, 'uid' => $uid, 'origin' => true, 'gravity' => GRAVITY_ACTIVITY, 'vid' => Verb::getID(Activity::LIKE)]), - Post::exists(['thr-parent-id' => $uriId, 'uid' => $uid, 'origin' => true, 'gravity' => GRAVITY_ACTIVITY, 'vid' => Verb::getID(Activity::ANNOUNCE)]), + Post::exists(['thr-parent-id' => $uriId, 'uid' => $uid, 'origin' => true, 'gravity' => GRAVITY_ACTIVITY, 'vid' => Verb::getID(Activity::LIKE), 'deleted' => false]), + Post::exists(['thr-parent-id' => $uriId, 'uid' => $uid, 'origin' => true, 'gravity' => GRAVITY_ACTIVITY, 'vid' => Verb::getID(Activity::ANNOUNCE), 'deleted' => false]), Post\ThreadUser::getIgnored($uriId, $uid), (bool)$item['starred'], Post\ThreadUser::getPinned($uriId, $uid) diff --git a/src/Module/Api/Mastodon/Accounts/Relationsships.php b/src/Module/Api/Mastodon/Accounts/Relationsships.php new file mode 100644 index 000000000..d485a06a3 --- /dev/null +++ b/src/Module/Api/Mastodon/Accounts/Relationsships.php @@ -0,0 +1,55 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Accounts; + +use Friendica\Core\System; +use Friendica\DI; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/accounts/ + */ +class Relationships extends BaseApi +{ + /** + * @param array $parameters + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + */ + public static function rawContent(array $parameters = []) + { + self::login(); + $uid = self::getCurrentUserID(); + + + if (empty($parameters['id'])) { + DI::mstdnError()->UnprocessableEntity(); + } + + $relationsships = []; + + foreach ($parameters['id'] as $id) { + $relationsships[] = DI::mstdnRelationship()->createFromPublicContactId($id, $uid); + } + + System::jsonExit($relationsships); + } +} diff --git a/src/Module/Api/Mastodon/Accounts/UpdateCredentials.php b/src/Module/Api/Mastodon/Accounts/UpdateCredentials.php new file mode 100644 index 000000000..30b190a33 --- /dev/null +++ b/src/Module/Api/Mastodon/Accounts/UpdateCredentials.php @@ -0,0 +1,42 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Accounts; + +use Friendica\Module\BaseApi; +use Friendica\Util\Network; + +/** + * @see https://docs.joinmastodon.org/methods/accounts/ + */ +class UpdateCredentials extends BaseApi +{ + public static function patch(array $parameters = []) + { + self::login(); + $uid = self::getCurrentUserID(); + + $data = Network::postdata(); + + // @todo Parse the raw data that is in the "multipart/form-data" format + self::unsupported('patch'); + } +} diff --git a/src/Module/Api/Mastodon/Notifications.php b/src/Module/Api/Mastodon/Notifications.php index 8252de7c2..e01951722 100644 --- a/src/Module/Api/Mastodon/Notifications.php +++ b/src/Module/Api/Mastodon/Notifications.php @@ -29,7 +29,7 @@ use Friendica\Model\Notification; use Friendica\Module\BaseApi; /** - * @see https://docs.joinmastodon.org/methods/accounts/mutes/ + * @see https://docs.joinmastodon.org/methods/notifications/ */ class Notifications extends BaseApi { diff --git a/src/Module/Api/Mastodon/Notifications/Clear.php b/src/Module/Api/Mastodon/Notifications/Clear.php new file mode 100644 index 000000000..5e0c53da0 --- /dev/null +++ b/src/Module/Api/Mastodon/Notifications/Clear.php @@ -0,0 +1,42 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Notifications; + +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/notifications/ + */ +class Clear extends BaseApi +{ + public static function post(array $parameters = []) + { + self::login(); + $uid = self::getCurrentUserID(); + + DBA::update('notify', ['seen' => true], ['uid' => $uid]); + + System::jsonExit([]); + } +} diff --git a/src/Module/Api/Mastodon/Notifications/Dismiss.php b/src/Module/Api/Mastodon/Notifications/Dismiss.php new file mode 100644 index 000000000..e8faa3096 --- /dev/null +++ b/src/Module/Api/Mastodon/Notifications/Dismiss.php @@ -0,0 +1,47 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Notifications; + +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/notifications/ + */ +class Dismiss extends BaseApi +{ + public static function post(array $parameters = []) + { + self::login(); + $uid = self::getCurrentUserID(); + + if (empty($parameters['id'])) { + DI::mstdnError()->UnprocessableEntity(); + } + + DBA::update('notify', ['seen' => true], ['uid' => $uid, 'id' => $parameters['id']]); + + System::jsonExit([]); + } +} diff --git a/src/Module/Api/Mastodon/Statuses.php b/src/Module/Api/Mastodon/Statuses.php index afaf15986..974c58bd3 100644 --- a/src/Module/Api/Mastodon/Statuses.php +++ b/src/Module/Api/Mastodon/Statuses.php @@ -21,8 +21,11 @@ namespace Friendica\Module\Api\Mastodon; +use Friendica\Core\Logger; use Friendica\Core\System; use Friendica\DI; +use Friendica\Model\Item; +use Friendica\Model\Post; use Friendica\Module\BaseApi; /** @@ -38,7 +41,23 @@ class Statuses extends BaseApi public static function delete(array $parameters = []) { - self::unsupported('delete'); + self::login(); + $uid = self::getCurrentUserID(); + + if (empty($parameters['id'])) { + DI::mstdnError()->UnprocessableEntity(); + } + + $item = Post::selectFirstForUser($uid, ['id'], ['uri-id' => $parameters['id'], 'uid' => $uid]); + if (empty($item['id'])) { + DI::mstdnError()->RecordNotFound(); + } + + if (!Item::markForDeletionById($item['id'])) { + DI::mstdnError()->RecordNotFound(); + } + + System::jsonExit([]); } /** diff --git a/src/Module/Api/Mastodon/Statuses/Bookmark.php b/src/Module/Api/Mastodon/Statuses/Bookmark.php new file mode 100644 index 000000000..acdf207a3 --- /dev/null +++ b/src/Module/Api/Mastodon/Statuses/Bookmark.php @@ -0,0 +1,58 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Statuses; + +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Item; +use Friendica\Model\Post; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/statuses/ + */ +class Bookmark extends BaseApi +{ + public static function post(array $parameters = []) + { + self::login(); + $uid = self::getCurrentUserID(); + + if (empty($parameters['id'])) { + DI::mstdnError()->UnprocessableEntity(); + } + + $item = Post::selectFirstForUser($uid, ['id', 'gravity'], ['uri-id' => $parameters['id'], 'uid' => [$uid, 0]]); + if (!DBA::isResult($item)) { + DI::mstdnError()->RecordNotFound(); + } + + if ($item['gravity'] != GRAVITY_PARENT) { + DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Only starting posts can be bookmarked')); + } + + Item::update(['starred' => true], ['id' => $item['id']]); + + System::jsonExit(DI::mstdnStatus()->createFromUriId($parameters['id'], $uid)->toArray()); + } +} diff --git a/src/Module/Api/Mastodon/Statuses/Favourite.php b/src/Module/Api/Mastodon/Statuses/Favourite.php new file mode 100644 index 000000000..74892d960 --- /dev/null +++ b/src/Module/Api/Mastodon/Statuses/Favourite.php @@ -0,0 +1,54 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Statuses; + +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Item; +use Friendica\Model\Post; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/statuses/ + */ +class Favourite extends BaseApi +{ + public static function post(array $parameters = []) + { + self::login(); + $uid = self::getCurrentUserID(); + + if (empty($parameters['id'])) { + DI::mstdnError()->UnprocessableEntity(); + } + + $item = Post::selectFirstForUser($uid, ['id'], ['uri-id' => $parameters['id'], 'uid' => [$uid, 0]]); + if (!DBA::isResult($item)) { + DI::mstdnError()->RecordNotFound(); + } + + Item::performActivity($item['id'], 'like', $uid); + + System::jsonExit(DI::mstdnStatus()->createFromUriId($parameters['id'], $uid)->toArray()); + } +} diff --git a/src/Module/Api/Mastodon/Statuses/Mute.php b/src/Module/Api/Mastodon/Statuses/Mute.php new file mode 100644 index 000000000..6a5d16d14 --- /dev/null +++ b/src/Module/Api/Mastodon/Statuses/Mute.php @@ -0,0 +1,57 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Statuses; + +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Post; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/statuses/ + */ +class Mute extends BaseApi +{ + public static function post(array $parameters = []) + { + self::login(); + $uid = self::getCurrentUserID(); + + if (empty($parameters['id'])) { + DI::mstdnError()->UnprocessableEntity(); + } + + $item = Post::selectFirstForUser($uid, ['id', 'gravity'], ['uri-id' => $parameters['id'], 'uid' => [$uid, 0]]); + if (!DBA::isResult($item)) { + DI::mstdnError()->RecordNotFound(); + } + + if ($item['gravity'] != GRAVITY_PARENT) { + DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Only starting posts can be muted')); + } + + Post\ThreadUser::setIgnored($parameters['id'], $uid, true); + + System::jsonExit(DI::mstdnStatus()->createFromUriId($parameters['id'], $uid)->toArray()); + } +} diff --git a/src/Module/Api/Mastodon/Statuses/Pin.php b/src/Module/Api/Mastodon/Statuses/Pin.php new file mode 100644 index 000000000..263780736 --- /dev/null +++ b/src/Module/Api/Mastodon/Statuses/Pin.php @@ -0,0 +1,57 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Statuses; + +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Post; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/statuses/ + */ +class Pin extends BaseApi +{ + public static function post(array $parameters = []) + { + self::login(); + $uid = self::getCurrentUserID(); + + if (empty($parameters['id'])) { + DI::mstdnError()->UnprocessableEntity(); + } + + $item = Post::selectFirstForUser($uid, ['id', 'gravity'], ['uri-id' => $parameters['id'], 'uid' => [$uid, 0]]); + if (!DBA::isResult($item)) { + DI::mstdnError()->RecordNotFound(); + } + + if ($item['gravity'] != GRAVITY_PARENT) { + DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Only starting posts can be pinned')); + } + + Post\ThreadUser::setPinned($parameters['id'], $uid, true); + + System::jsonExit(DI::mstdnStatus()->createFromUriId($parameters['id'], $uid)->toArray()); + } +} diff --git a/src/Module/Api/Mastodon/Statuses/Reblog.php b/src/Module/Api/Mastodon/Statuses/Reblog.php new file mode 100644 index 000000000..cdd788dcf --- /dev/null +++ b/src/Module/Api/Mastodon/Statuses/Reblog.php @@ -0,0 +1,60 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Statuses; + +use Friendica\Content\ContactSelector; +use Friendica\Core\Protocol; +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Item; +use Friendica\Model\Post; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/statuses/ + */ +class Reblog extends BaseApi +{ + public static function post(array $parameters = []) + { + self::login(); + $uid = self::getCurrentUserID(); + + if (empty($parameters['id'])) { + DI::mstdnError()->UnprocessableEntity(); + } + + $item = Post::selectFirstForUser($uid, ['id', 'network'], ['uri-id' => $parameters['id'], 'uid' => [$uid, 0]]); + if (!DBA::isResult($item)) { + DI::mstdnError()->RecordNotFound(); + } + + if (!in_array($item['network'], [Protocol::DFRN, Protocol::ACTIVITYPUB, Protocol::TWITTER])) { + DI::mstdnError()->UnprocessableEntity(DI::l10n()->t("Posts from %s can't be shared", ContactSelector::networkToName($item['network']))); + } + + Item::performActivity($item['id'], 'announce', $uid); + + System::jsonExit(DI::mstdnStatus()->createFromUriId($parameters['id'], $uid)->toArray()); + } +} diff --git a/src/Module/Api/Mastodon/Statuses/Unbookmark.php b/src/Module/Api/Mastodon/Statuses/Unbookmark.php new file mode 100644 index 000000000..dd78d8833 --- /dev/null +++ b/src/Module/Api/Mastodon/Statuses/Unbookmark.php @@ -0,0 +1,58 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Statuses; + +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Item; +use Friendica\Model\Post; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/statuses/ + */ +class Unbookmark extends BaseApi +{ + public static function post(array $parameters = []) + { + self::login(); + $uid = self::getCurrentUserID(); + + if (empty($parameters['id'])) { + DI::mstdnError()->UnprocessableEntity(); + } + + $item = Post::selectFirstForUser($uid, ['id', 'gravity'], ['uri-id' => $parameters['id'], 'uid' => [$uid, 0]]); + if (!DBA::isResult($item)) { + DI::mstdnError()->RecordNotFound(); + } + + if ($item['gravity'] != GRAVITY_PARENT) { + DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Only starting posts can be unbookmarked')); + } + + Item::update(['starred' => false], ['id' => $item['id']]); + + System::jsonExit(DI::mstdnStatus()->createFromUriId($parameters['id'], $uid)->toArray()); + } +} diff --git a/src/Module/Api/Mastodon/Statuses/Unfavourite.php b/src/Module/Api/Mastodon/Statuses/Unfavourite.php new file mode 100644 index 000000000..528ef692e --- /dev/null +++ b/src/Module/Api/Mastodon/Statuses/Unfavourite.php @@ -0,0 +1,54 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Statuses; + +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Item; +use Friendica\Model\Post; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/statuses/ + */ +class Unfavourite extends BaseApi +{ + public static function post(array $parameters = []) + { + self::login(); + $uid = self::getCurrentUserID(); + + if (empty($parameters['id'])) { + DI::mstdnError()->UnprocessableEntity(); + } + + $item = Post::selectFirstForUser($uid, ['id'], ['uri-id' => $parameters['id'], 'uid' => [$uid, 0]]); + if (!DBA::isResult($item)) { + DI::mstdnError()->RecordNotFound(); + } + + Item::performActivity($item['id'], 'unlike', $uid); + + System::jsonExit(DI::mstdnStatus()->createFromUriId($parameters['id'], $uid)->toArray()); + } +} diff --git a/src/Module/Api/Mastodon/Statuses/Unmute.php b/src/Module/Api/Mastodon/Statuses/Unmute.php new file mode 100644 index 000000000..26843be6c --- /dev/null +++ b/src/Module/Api/Mastodon/Statuses/Unmute.php @@ -0,0 +1,57 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Statuses; + +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Post; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/statuses/ + */ +class Unmute extends BaseApi +{ + public static function post(array $parameters = []) + { + self::login(); + $uid = self::getCurrentUserID(); + + if (empty($parameters['id'])) { + DI::mstdnError()->UnprocessableEntity(); + } + + $item = Post::selectFirstForUser($uid, ['id', 'gravity'], ['uri-id' => $parameters['id'], 'uid' => [$uid, 0]]); + if (!DBA::isResult($item)) { + DI::mstdnError()->RecordNotFound(); + } + + if ($item['gravity'] != GRAVITY_PARENT) { + DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Only starting posts can be unmuted')); + } + + Post\ThreadUser::setIgnored($parameters['id'], $uid, false); + + System::jsonExit(DI::mstdnStatus()->createFromUriId($parameters['id'], $uid)->toArray()); + } +} diff --git a/src/Module/Api/Mastodon/Statuses/Unpin.php b/src/Module/Api/Mastodon/Statuses/Unpin.php new file mode 100644 index 000000000..d16bfc33e --- /dev/null +++ b/src/Module/Api/Mastodon/Statuses/Unpin.php @@ -0,0 +1,57 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Statuses; + +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Post; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/statuses/ + */ +class Unpin extends BaseApi +{ + public static function post(array $parameters = []) + { + self::login(); + $uid = self::getCurrentUserID(); + + if (empty($parameters['id'])) { + DI::mstdnError()->UnprocessableEntity(); + } + + $item = Post::selectFirstForUser($uid, ['id', 'gravity'], ['uri-id' => $parameters['id'], 'uid' => [$uid, 0]]); + if (!DBA::isResult($item)) { + DI::mstdnError()->RecordNotFound(); + } + + if ($item['gravity'] != GRAVITY_PARENT) { + DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Only starting posts can be pinned')); + } + + Post\ThreadUser::setPinned($parameters['id'], $uid, false); + + System::jsonExit(DI::mstdnStatus()->createFromUriId($parameters['id'], $uid)->toArray()); + } +} diff --git a/src/Module/Api/Mastodon/Statuses/Unreblog.php b/src/Module/Api/Mastodon/Statuses/Unreblog.php new file mode 100644 index 000000000..1296b7225 --- /dev/null +++ b/src/Module/Api/Mastodon/Statuses/Unreblog.php @@ -0,0 +1,60 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Statuses; + +use Friendica\Content\ContactSelector; +use Friendica\Core\Protocol; +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Item; +use Friendica\Model\Post; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/statuses/ + */ +class Unreblog extends BaseApi +{ + public static function post(array $parameters = []) + { + self::login(); + $uid = self::getCurrentUserID(); + + if (empty($parameters['id'])) { + DI::mstdnError()->UnprocessableEntity(); + } + + $item = Post::selectFirstForUser($uid, ['id', 'network'], ['uri-id' => $parameters['id'], 'uid' => [$uid, 0]]); + if (!DBA::isResult($item)) { + DI::mstdnError()->RecordNotFound(); + } + + if (!in_array($item['network'], [Protocol::DFRN, Protocol::ACTIVITYPUB, Protocol::TWITTER])) { + DI::mstdnError()->UnprocessableEntity(DI::l10n()->t("Posts from %s can't be unshared", ContactSelector::networkToName($item['network']))); + } + + Item::performActivity($item['id'], 'unannounce', $uid); + + System::jsonExit(DI::mstdnStatus()->createFromUriId($parameters['id'], $uid)->toArray()); + } +} diff --git a/static/routes.config.php b/static/routes.config.php index 7c33d5674..ada9de8a5 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -73,10 +73,10 @@ return [ '/accounts/{id:\d+}/pin' => [Module\Api\Mastodon\Unimplemented::class, [ R::POST]], // not supported '/accounts/{id:\d+}/unpin' => [Module\Api\Mastodon\Unimplemented::class, [ R::POST]], // not supported '/accounts/{id:\d+}/note' => [Module\Api\Mastodon\Unimplemented::class, [ R::POST]], // @todo - '/accounts/relationships' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // @todo + '/accounts/relationships' => [Module\Api\Mastodon\Accounts\Relationships::class, [R::GET ]], '/accounts/search' => [Module\Api\Mastodon\Accounts\Search::class, [R::GET ]], '/accounts/verify_credentials' => [Module\Api\Mastodon\Accounts\VerifyCredentials::class, [R::GET ]], - '/accounts/update_credentials' => [Module\Api\Mastodon\Unimplemented::class, [R::PATCH ]], // @todo + '/accounts/update_credentials' => [Module\Api\Mastodon\Accounts\UpdateCredentials::class, [R::PATCH ]], '/admin/accounts' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not supported '/admin/accounts/{id:\d+}' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not supported '/admin/accounts/{id:\d+}/{action}' => [Module\Api\Mastodon\Unimplemented::class, [ R::POST]], // not supported @@ -117,8 +117,8 @@ return [ '/mutes' => [Module\Api\Mastodon\Mutes::class, [R::GET ]], '/notifications' => [Module\Api\Mastodon\Notifications::class, [R::GET ]], '/notifications/{id:\d+}' => [Module\Api\Mastodon\Notifications::class, [R::GET ]], - '/notifications/clear' => [Module\Api\Mastodon\Unimplemented::class, [ R::POST]], // @todo - '/notifications/{id:\d+}/dismiss' => [Module\Api\Mastodon\Unimplemented::class, [ R::POST]], // @todo + '/notifications/clear' => [Module\Api\Mastodon\Notifications\Clear::class, [ R::POST]], + '/notifications/{id:\d+}/dismiss' => [Module\Api\Mastodon\Notifications\Dismiss::class, [ R::POST]], '/polls/{id:\d+}' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not supported '/polls/{id:\d+}/votes' => [Module\Api\Mastodon\Unimplemented::class, [ R::POST]], // not supported '/preferences' => [Module\Api\Mastodon\Preferences::class, [R::GET ]], @@ -130,16 +130,16 @@ return [ '/statuses/{id:\d+}/context' => [Module\Api\Mastodon\Statuses\Context::class, [R::GET ]], '/statuses/{id:\d+}/reblogged_by' => [Module\Api\Mastodon\Statuses\RebloggedBy::class, [R::GET ]], '/statuses/{id:\d+}/favourited_by' => [Module\Api\Mastodon\Statuses\FavouritedBy::class, [R::GET ]], - '/statuses/{id:\d+}/favourite' => [Module\Api\Mastodon\Unimplemented::class, [ R::POST]], // @todo - '/statuses/{id:\d+}/unfavourite' => [Module\Api\Mastodon\Unimplemented::class, [ R::POST]], // @todo - '/statuses/{id:\d+}/reblog' => [Module\Api\Mastodon\Unimplemented::class, [ R::POST]], // @todo - '/statuses/{id:\d+}/unreblog' => [Module\Api\Mastodon\Unimplemented::class, [ R::POST]], // @todo - '/statuses/{id:\d+}/bookmark' => [Module\Api\Mastodon\Unimplemented::class, [ R::POST]], // @todo - '/statuses/{id:\d+}/unbookmark' => [Module\Api\Mastodon\Unimplemented::class, [ R::POST]], // @todo - '/statuses/{id:\d+}/mute' => [Module\Api\Mastodon\Unimplemented::class, [ R::POST]], // @todo - '/statuses/{id:\d+}/unmute' => [Module\Api\Mastodon\Unimplemented::class, [ R::POST]], // @todo - '/statuses/{id:\d+}/pin' => [Module\Api\Mastodon\Unimplemented::class, [ R::POST]], // @todo - '/statuses/{id:\d+}/unpin' => [Module\Api\Mastodon\Unimplemented::class, [ R::POST]], // @todo + '/statuses/{id:\d+}/favourite' => [Module\Api\Mastodon\Statuses\Favourite::class, [ R::POST]], + '/statuses/{id:\d+}/unfavourite' => [Module\Api\Mastodon\Statuses\Unfavourite::class, [ R::POST]], + '/statuses/{id:\d+}/reblog' => [Module\Api\Mastodon\Statuses\Reblog::class, [ R::POST]], + '/statuses/{id:\d+}/unreblog' => [Module\Api\Mastodon\Statuses\Unreblog::class, [ R::POST]], + '/statuses/{id:\d+}/bookmark' => [Module\Api\Mastodon\Statuses\Bookmark::class, [ R::POST]], + '/statuses/{id:\d+}/unbookmark' => [Module\Api\Mastodon\Statuses\Unbookmark::class, [ R::POST]], + '/statuses/{id:\d+}/mute' => [Module\Api\Mastodon\Statuses\Mute::class, [ R::POST]], + '/statuses/{id:\d+}/unmute' => [Module\Api\Mastodon\Statuses\Unmute::class, [ R::POST]], + '/statuses/{id:\d+}/pin' => [Module\Api\Mastodon\Statuses\Pin::class, [ R::POST]], + '/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 diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po index e6e0e55db..f2e2a1293 100644 --- a/view/lang/C/messages.po +++ b/view/lang/C/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 2021.06-dev\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-05-13 15:15+0000\n" +"POT-Creation-Date: 2021-05-15 10:54+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -7200,6 +7200,37 @@ msgstr "" msgid "Missing parameters" msgstr "" +#: src/Module/Api/Mastodon/Statuses/Bookmark.php:51 +msgid "Only starting posts can be bookmarked" +msgstr "" + +#: src/Module/Api/Mastodon/Statuses/Mute.php:50 +msgid "Only starting posts can be muted" +msgstr "" + +#: src/Module/Api/Mastodon/Statuses/Pin.php:50 +#: src/Module/Api/Mastodon/Statuses/Unpin.php:50 +msgid "Only starting posts can be pinned" +msgstr "" + +#: src/Module/Api/Mastodon/Statuses/Reblog.php:53 +#, php-format +msgid "Posts from %s can't be shared" +msgstr "" + +#: src/Module/Api/Mastodon/Statuses/Unbookmark.php:51 +msgid "Only starting posts can be unbookmarked" +msgstr "" + +#: src/Module/Api/Mastodon/Statuses/Unmute.php:50 +msgid "Only starting posts can be unmuted" +msgstr "" + +#: src/Module/Api/Mastodon/Statuses/Unreblog.php:53 +#, php-format +msgid "Posts from %s can't be unshared" +msgstr "" + #: src/Module/Api/Twitter/ContactEndpoint.php:65 src/Module/Contact.php:400 msgid "Contact not found" msgstr "" @@ -8850,11 +8881,11 @@ msgstr "" msgid "Unsupported or missing response type" msgstr "" -#: src/Module/OAuth/Authorize.php:54 src/Module/OAuth/Token.php:51 +#: src/Module/OAuth/Authorize.php:54 src/Module/OAuth/Token.php:55 msgid "Incomplete request data" msgstr "" -#: src/Module/OAuth/Token.php:46 +#: src/Module/OAuth/Token.php:79 msgid "Unsupported or missing grant type" msgstr ""