diff --git a/appinfo/routes.php b/appinfo/routes.php index 90ef2f44..fb80fb7f 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -80,6 +80,7 @@ return [ ['name' => 'Api#savedSearches', 'url' => '/api/saved_searches/list.json', 'verb' => 'GET'], ['name' => 'Api#timelines', 'url' => '/api/v1/timelines/{timeline}/', 'verb' => 'GET'], ['name' => 'Api#notifications', 'url' => '/api/v1/notifications', 'verb' => 'GET'], + ['name' => 'Api#statusNew', 'url' => '/api/v1/statuses', 'verb' => 'POST'], // Api for local front-end // TODO: front-end should be using the new ApiController diff --git a/lib/Controller/ApiController.php b/lib/Controller/ApiController.php index a6dc9fba..fdd334d5 100644 --- a/lib/Controller/ApiController.php +++ b/lib/Controller/ApiController.php @@ -30,7 +30,6 @@ declare(strict_types=1); namespace OCA\Social\Controller; -use OCA\Social\Tools\Traits\TNCDataResponse; use Exception; use OCA\Social\AppInfo\Application; use OCA\Social\Exceptions\AccountDoesNotExistException; @@ -41,19 +40,23 @@ use OCA\Social\Model\ActivityPub\Actor\Person; use OCA\Social\Model\ActivityPub\Stream; use OCA\Social\Model\Client\Options\TimelineOptions; use OCA\Social\Model\Client\SocialClient; +use OCA\Social\Model\Client\Status; +use OCA\Social\Model\Post; use OCA\Social\Service\AccountService; use OCA\Social\Service\CacheActorService; use OCA\Social\Service\ClientService; use OCA\Social\Service\ConfigService; use OCA\Social\Service\FollowService; use OCA\Social\Service\InstanceService; -use OCA\Social\Service\MiscService; +use OCA\Social\Service\PostService; use OCA\Social\Service\StreamService; +use OCA\Social\Tools\Traits\TNCDataResponse; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\IRequest; use OCP\IUserSession; +use Psr\Log\LoggerInterface; /** * Class ApiController @@ -64,35 +67,45 @@ class ApiController extends Controller { use TNCDataResponse; private IUserSession $userSession; + private LoggerInterface $logger; private InstanceService $instanceService; private ClientService $clientService; private AccountService $accountService; private CacheActorService $cacheActorService; private FollowService $followService; private StreamService $streamService; + private PostService $postService; private ConfigService $configService; - private MiscService $miscService; + private string $bearer = ''; private ?SocialClient $client = null; private ?Person $viewer = null; public function __construct( - IRequest $request, IUserSession $userSession, InstanceService $instanceService, - ClientService $clientService, AccountService $accountService, CacheActorService $cacheActorService, - FollowService $followService, StreamService $streamService, ConfigService $configService, - MiscService $miscService + IRequest $request, + IUserSession $userSession, + LoggerInterface $logger, + InstanceService $instanceService, + ClientService $clientService, + AccountService $accountService, + CacheActorService $cacheActorService, + FollowService $followService, + StreamService $streamService, + PostService $postService, + ConfigService $configService ) { parent::__construct(Application::APP_NAME, $request); $this->userSession = $userSession; + $this->logger = $logger; $this->instanceService = $instanceService; $this->clientService = $clientService; $this->accountService = $accountService; $this->cacheActorService = $cacheActorService; $this->followService = $followService; $this->streamService = $streamService; + $this->postService = $postService; $this->configService = $configService; - $this->miscService = $miscService; $authHeader = trim($this->request->getHeader('Authorization')); if (strpos($authHeader, ' ')) { @@ -211,6 +224,40 @@ class ApiController extends Controller { } + /** + * @PublicPage + * @NoCSRFRequired + * + * @return DataResponse + */ + public function statusNew(): DataResponse { + try { + $this->initViewer(true); + + $json = file_get_contents('php://input'); + $this->logger->debug('[ApiController] newStatus: ' . $json); + + $data = json_decode($json, true); + if (!is_array($data) || empty($data)) { + throw new Exception(); + } + + $status = new Status(); + $status->import($data); + + $post = new Post($this->accountService->getActorFromUserId($this->currentSession())); + $post->setContent($status->getStatus()); + $post->setType($status->getVisibility()); + + $activity = $this->postService->createPost($post); + + return new DataResponse([], Http::STATUS_OK); + } catch (Exception $e) { + return $this->error($e->getMessage()); + } + } + + /** * @NoCSRFRequired * @PublicPage @@ -219,18 +266,25 @@ class ApiController extends Controller { * @param int $limit * @param int $max_id * @param int $min_id + * * @return DataResponse */ - public function timelines(string $timeline, int $limit = 20, int $max_id = 0, int $min_id = 0): DataResponse { - $options = new TimelineOptions($this->request); - $options->setFormat(Stream::FORMAT_LOCAL); - $options->setTimeline($timeline); - $options->setLimit($limit); - $options->setMaxId($max_id); - $options->setMinId($min_id); - + public function timelines( + string $timeline, + int $limit = 20, + int $max_id = 0, + int $min_id = 0 + ): DataResponse { try { $this->initViewer(true); + + $options = new TimelineOptions($this->request); + $options->setFormat(Stream::FORMAT_LOCAL); + $options->setTimeline($timeline); + $options->setLimit($limit); + $options->setMaxId($max_id); + $options->setMinId($min_id); + $posts = $this->streamService->getTimeline($options); return new DataResponse($posts, Http::STATUS_OK); @@ -251,8 +305,8 @@ class ApiController extends Controller { try { $userId = $this->currentSession(); - $this->miscService->log( - '[ApiController] initViewer: ' . $userId . ' (bearer=' . $this->bearer . ')', 0 + $this->logger->debug( + '[ApiController] initViewer: ' . $userId . ' (bearer=' . $this->bearer . ')' ); $account = $this->accountService->getActorFromUserId($userId); diff --git a/lib/Model/Client/Status.php b/lib/Model/Client/Status.php new file mode 100644 index 00000000..8e6ba40b --- /dev/null +++ b/lib/Model/Client/Status.php @@ -0,0 +1,163 @@ + + * @copyright 2022, Maxence Lange + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Social\Model\Client; + +use OCA\Social\Tools\Traits\TArrayTools; + +class Status implements \JsonSerializable { + use TArrayTools; + + private string $contentType = ''; + private bool $sensitive = false; + private string $visibility = ''; + private string $spoilerText = ''; + private string $status = ''; + + //"media_ids": [], + + public function __construct() { + } + + + /** + * @param string $contentType + * + * @return Status + */ + public function setContentType(string $contentType): self { + $this->contentType = $contentType; + + return $this; + } + + /** + * @return string + */ + public function getContentType(): string { + return $this->contentType; + } + + + /** + * @param bool $sensitive + * + * @return Status + */ + public function setSensitive(bool $sensitive): self { + $this->sensitive = $sensitive; + + return $this; + } + + /** + * @return bool + */ + public function isSensitive(): bool { + return $this->sensitive; + } + + + /** + * @param string $visibility + * + * @return Status + */ + public function setVisibility(string $visibility): self { + $this->visibility = $visibility; + + return $this; + } + + /** + * @return string + */ + public function getVisibility(): string { + return $this->visibility; + } + + + /** + * @param string $spoilerText + * + * @return Status + */ + public function setSpoilerText(string $spoilerText): self { + $this->spoilerText = $spoilerText; + + return $this; + } + + /** + * @return string + */ + public function getSpoilerText(): string { + return $this->spoilerText; + } + + + /** + * @param string $status + * + * @return Status + */ + public function setStatus(string $status): self { + $this->status = $status; + + return $this; + } + + /** + * @return string + */ + public function getStatus(): string { + return $this->status; + } + + + public function import(array $data): self { + $this->setContentType($this->get('content_type', $data)); + $this->setSensitive($this->getBool('sensitive', $data)); + $this->setVisibility($this->get('visibility', $data)); + $this->setSpoilerText($this->get('spoiler_text', $data)); + $this->setStatus($this->get('status', $data)); + + return $this; + } + + public function jsonSerialize(): array { + return [ + 'contentType' => $this->getContentType(), + 'sensitive' => $this->isSensitive(), + 'visibility' => $this->getVisibility(), + 'spoilerText' => $this->getSpoilerText(), + 'status' => $this->getStatus() + ]; + } +} diff --git a/lib/Service/PostService.php b/lib/Service/PostService.php index a232da6e..b4b1663a 100644 --- a/lib/Service/PostService.php +++ b/lib/Service/PostService.php @@ -97,7 +97,7 @@ class PostService { * @throws StreamNotFoundException * @throws UnauthorizedFediverseException */ - public function createPost(Post $post, &$token = ''): ACore { + public function createPost(Post $post, string &$token = ''): ACore { $this->fixRecipientAndHashtags($post); $note = new Note();