diff --git a/lib/Controller/PollController.php b/lib/Controller/PollController.php index 762529e08e3a..ae94b66ae4f8 100644 --- a/lib/Controller/PollController.php +++ b/lib/Controller/PollController.php @@ -30,6 +30,7 @@ use JsonException; use OCA\Talk\Chat\ChatManager; use OCA\Talk\Exceptions\WrongPermissionsException; +use OCA\Talk\Middleware\Attribute\FederationSupported; use OCA\Talk\Middleware\Attribute\RequireModeratorOrNoLobby; use OCA\Talk\Middleware\Attribute\RequireParticipant; use OCA\Talk\Middleware\Attribute\RequirePermission; @@ -80,12 +81,19 @@ public function __construct( * 201: Poll created successfully * 400: Creating poll is not possible */ + #[FederationSupported] #[PublicPage] #[RequireModeratorOrNoLobby] #[RequireParticipant] #[RequirePermission(permission: RequirePermission::CHAT)] #[RequireReadWriteConversation] public function createPoll(string $question, array $options, int $resultMode, int $maxVotes): DataResponse { + if ($this->room->getRemoteServer() !== '') { + /** @var \OCA\Talk\Federation\Proxy\TalkV1\Controller\PollController $proxy */ + $proxy = \OCP\Server::get(\OCA\Talk\Federation\Proxy\TalkV1\Controller\PollController::class); + return $proxy->createPoll($this->room, $this->participant, $question, $options, $resultMode, $maxVotes); + } + if ($this->room->getType() !== Room::TYPE_GROUP && $this->room->getType() !== Room::TYPE_PUBLIC) { return new DataResponse([], Http::STATUS_BAD_REQUEST); @@ -140,10 +148,17 @@ public function createPoll(string $question, array $options, int $resultMode, in * 200: Poll returned * 404: Poll not found */ + #[FederationSupported] #[PublicPage] #[RequireModeratorOrNoLobby] #[RequireParticipant] public function showPoll(int $pollId): DataResponse { + if ($this->room->getRemoteServer() !== '') { + /** @var \OCA\Talk\Federation\Proxy\TalkV1\Controller\PollController $proxy */ + $proxy = \OCP\Server::get(\OCA\Talk\Federation\Proxy\TalkV1\Controller\PollController::class); + return $proxy->showPoll($this->room, $this->participant, $pollId); + } + try { $poll = $this->pollService->getPoll($this->room->getId(), $pollId); } catch (DoesNotExistException $e) { @@ -171,10 +186,17 @@ public function showPoll(int $pollId): DataResponse { * 400: Voting is not possible * 404: Poll not found */ + #[FederationSupported] #[PublicPage] #[RequireModeratorOrNoLobby] #[RequireParticipant] public function votePoll(int $pollId, array $optionIds = []): DataResponse { + if ($this->room->getRemoteServer() !== '') { + /** @var \OCA\Talk\Federation\Proxy\TalkV1\Controller\PollController $proxy */ + $proxy = \OCP\Server::get(\OCA\Talk\Federation\Proxy\TalkV1\Controller\PollController::class); + return $proxy->votePoll($this->room, $this->participant, $pollId, $optionIds); + } + try { $poll = $this->pollService->getPoll($this->room->getId(), $pollId); } catch (\Exception $e) { @@ -225,10 +247,17 @@ public function votePoll(int $pollId, array $optionIds = []): DataResponse { * 403: Missing permissions to close poll * 404: Poll not found */ + #[FederationSupported] #[PublicPage] #[RequireModeratorOrNoLobby] #[RequireParticipant] public function closePoll(int $pollId): DataResponse { + if ($this->room->getRemoteServer() !== '') { + /** @var \OCA\Talk\Federation\Proxy\TalkV1\Controller\PollController $proxy */ + $proxy = \OCP\Server::get(\OCA\Talk\Federation\Proxy\TalkV1\Controller\PollController::class); + return $proxy->closePoll($this->room, $this->participant, $pollId); + } + try { $poll = $this->pollService->getPoll($this->room->getId(), $pollId); } catch (\Exception $e) { diff --git a/lib/Federation/Proxy/TalkV1/Controller/PollController.php b/lib/Federation/Proxy/TalkV1/Controller/PollController.php new file mode 100644 index 000000000000..468e95515458 --- /dev/null +++ b/lib/Federation/Proxy/TalkV1/Controller/PollController.php @@ -0,0 +1,181 @@ + + * + * @author Joas Schilling + * + * @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\Talk\Federation\Proxy\TalkV1\Controller; + +use OCA\Talk\Exceptions\CannotReachRemoteException; +use OCA\Talk\Federation\Proxy\TalkV1\ProxyRequest; +use OCA\Talk\Federation\Proxy\TalkV1\UserConverter; +use OCA\Talk\Participant; +use OCA\Talk\ResponseDefinitions; +use OCA\Talk\Room; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; + +/** + * @psalm-import-type TalkPoll from ResponseDefinitions + */ +class PollController { + public function __construct( + protected ProxyRequest $proxy, + protected UserConverter $userConverter, + ) { + } + + /** + * @return DataResponse|DataResponse, array{}> + * @throws CannotReachRemoteException + * + * 200: Poll returned + * 404: Poll not found + * + * @see \OCA\Talk\Controller\PollController::showPoll() + */ + public function showPoll(Room $room, Participant $participant, int $pollId): DataResponse { + $proxy = $this->proxy->get( + $participant->getAttendee()->getInvitedCloudId(), + $participant->getAttendee()->getAccessToken(), + $room->getRemoteServer() . '/ocs/v2.php/apps/spreed/api/v1/poll/' . $room->getRemoteToken() . '/' . $pollId, + ); + + if ($proxy->getStatusCode() === Http::STATUS_NOT_FOUND) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + + /** @var TalkPoll $data */ + $data = $this->proxy->getOCSData($proxy); + $data = $this->userConverter->convertAttendee($room, $data, 'actorType', 'actorId', 'actorDisplayName'); + + return new DataResponse($data); + } + + /** + * @return DataResponse|DataResponse, array{}> + * @throws CannotReachRemoteException + * + * 200: Voted successfully + * 400: Voting is not possible + * 404: Poll not found + * + * @see \OCA\Talk\Controller\PollController::votePoll() + */ + public function votePoll(Room $room, Participant $participant, int $pollId, array $optionIds): DataResponse { + $proxy = $this->proxy->post( + $participant->getAttendee()->getInvitedCloudId(), + $participant->getAttendee()->getAccessToken(), + $room->getRemoteServer() . '/ocs/v2.php/apps/spreed/api/v1/poll/' . $room->getRemoteToken() . '/' . $pollId, + ['optionIds' => $optionIds], + ); + + $statusCode = $proxy->getStatusCode(); + if ($statusCode !== Http::STATUS_OK) { + if (!in_array($statusCode, [ + Http::STATUS_BAD_REQUEST, + Http::STATUS_NOT_FOUND, + ], true)) { + $statusCode = $this->proxy->logUnexpectedStatusCode(__METHOD__, $statusCode); + } + return new DataResponse([], $statusCode); + } + + /** @var TalkPoll $data */ + $data = $this->proxy->getOCSData($proxy); + $data = $this->userConverter->convertAttendee($room, $data, 'actorType', 'actorId', 'actorDisplayName'); + + return new DataResponse($data); + } + + + /** + * @return DataResponse|DataResponse, array{}> + * @throws CannotReachRemoteException + * + * 201: Poll created successfully + * 400: Creating poll is not possible + * + * @see \OCA\Talk\Controller\PollController::createPoll() + */ + public function createPoll(Room $room, Participant $participant, string $question, array $options, int $resultMode, int $maxVotes): DataResponse { + $proxy = $this->proxy->post( + $participant->getAttendee()->getInvitedCloudId(), + $participant->getAttendee()->getAccessToken(), + $room->getRemoteServer() . '/ocs/v2.php/apps/spreed/api/v1/poll/' . $room->getRemoteToken(), + [ + 'question' => $question, + 'options' => $options, + 'resultMode' => $resultMode, + 'maxVotes' => $maxVotes, + ], + ); + + if ($proxy->getStatusCode() === Http::STATUS_BAD_REQUEST) { + return new DataResponse([], Http::STATUS_BAD_REQUEST); + } + + /** @var TalkPoll $data */ + $data = $this->proxy->getOCSData($proxy, [Http::STATUS_CREATED]); + $data = $this->userConverter->convertAttendee($room, $data, 'actorType', 'actorId', 'actorDisplayName'); + + return new DataResponse($data, Http::STATUS_CREATED); + } + + /** + * @return DataResponse|DataResponse, array{}> + * @throws CannotReachRemoteException + * + * 200: Poll closed successfully + * 400: Poll already closed + * 403: Missing permissions to close poll + * 404: Poll not found + * + * @see \OCA\Talk\Controller\PollController::closePoll() + */ + public function closePoll(Room $room, Participant $participant, int $pollId): DataResponse { + $proxy = $this->proxy->delete( + $participant->getAttendee()->getInvitedCloudId(), + $participant->getAttendee()->getAccessToken(), + $room->getRemoteServer() . '/ocs/v2.php/apps/spreed/api/v1/poll/' . $room->getRemoteToken() . '/' . $pollId, + ); + + $statusCode = $proxy->getStatusCode(); + if ($statusCode !== Http::STATUS_OK) { + if (!in_array($statusCode, [ + Http::STATUS_BAD_REQUEST, + Http::STATUS_FORBIDDEN, + Http::STATUS_NOT_FOUND, + ], true)) { + $statusCode = $this->proxy->logUnexpectedStatusCode(__METHOD__, $statusCode); + } + return new DataResponse([], $statusCode); + } + + /** @var TalkPoll $data */ + $data = $this->proxy->getOCSData($proxy); + $data = $this->userConverter->convertAttendee($room, $data, 'actorType', 'actorId', 'actorDisplayName'); + + return new DataResponse($data); + } +}