diff --git a/lib/Capabilities.php b/lib/Capabilities.php index 79bed2d1a48..c35a8ea9ad8 100644 --- a/lib/Capabilities.php +++ b/lib/Capabilities.php @@ -185,8 +185,8 @@ public function __construct( /** * @return array{ - * spreed: TalkCapabilities, - * }|array + * spreed?: TalkCapabilities, + * } */ public function getCapabilities(): array { $user = $this->userSession->getUser(); diff --git a/lib/Chat/ChatManager.php b/lib/Chat/ChatManager.php index 28319640f61..19c56f1ca43 100644 --- a/lib/Chat/ChatManager.php +++ b/lib/Chat/ChatManager.php @@ -23,6 +23,7 @@ use OCA\Talk\Model\Message; use OCA\Talk\Model\Poll; use OCA\Talk\Participant; +use OCA\Talk\ResponseDefinitions; use OCA\Talk\Room; use OCA\Talk\Service\AttachmentService; use OCA\Talk\Service\ParticipantService; @@ -59,6 +60,8 @@ * * When a message is saved the mentioned users are notified as needed, and * pending notifications are removed if the messages are deleted. + * + * @psalm-import-type TalkChatMentionSuggestion from ResponseDefinitions */ class ChatManager { public const MAX_CHAT_LENGTH = 32000; @@ -968,6 +971,10 @@ public function searchForObjectsWithFilters(string $search, array $objectIds, st return $this->commentsManager->searchForObjectsWithFilters($search, 'chat', $objectIds, $verb, $since, $until, $actorType, $actorId, $offset, $limit); } + /** + * @param list $results + * @return list + */ public function addConversationNotify(array $results, string $search, Room $room, Participant $participant): array { if ($room->getType() === Room::TYPE_ONE_TO_ONE) { return $results; diff --git a/lib/Chat/ReactionManager.php b/lib/Chat/ReactionManager.php index 11a0efe3e1b..3fc31b74cfe 100644 --- a/lib/Chat/ReactionManager.php +++ b/lib/Chat/ReactionManager.php @@ -127,7 +127,7 @@ public function deleteReactionMessage(Room $chat, string $actorType, string $act } /** - * @return array + * @return array> * @throws PreConditionNotMetException */ public function retrieveReactionMessages(Room $chat, Participant $participant, int $messageId, ?string $reaction = null): array { diff --git a/lib/Controller/ChatController.php b/lib/Controller/ChatController.php index 6d12bc13bf8..361b96c248f 100644 --- a/lib/Controller/ChatController.php +++ b/lib/Controller/ChatController.php @@ -199,7 +199,7 @@ protected function parseCommentToResponse(IComment $comment, ?Message $parentMes * @param int $replyTo Parent id which this message is a reply to * @psalm-param non-negative-int $replyTo * @param bool $silent If sent silent the chat message will not create any notifications - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse * * 201: Message sent successfully * 400: Sending message is not possible @@ -221,12 +221,12 @@ public function sendMessage(string $message, string $actorDisplayName = '', stri } if (trim($message) === '') { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'message'], Http::STATUS_BAD_REQUEST); } [$actorType, $actorId] = $this->getActorInfo($actorDisplayName); if (!$actorId) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'actor'], Http::STATUS_NOT_FOUND); } $parent = $parentMessage = null; @@ -235,13 +235,13 @@ public function sendMessage(string $message, string $actorDisplayName = '', stri $parent = $this->chatManager->getParentComment($this->room, (string)$replyTo); } catch (NotFoundException $e) { // Someone is trying to reply cross-rooms or to a non-existing message - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'reply-to'], Http::STATUS_BAD_REQUEST); } $parentMessage = $this->messageParser->createMessage($this->room, $this->participant, $parent, $this->l); $this->messageParser->parseMessage($parentMessage); if (!$parentMessage->isReplyable()) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'reply-to'], Http::STATUS_BAD_REQUEST); } } @@ -251,11 +251,11 @@ public function sendMessage(string $message, string $actorDisplayName = '', stri try { $comment = $this->chatManager->sendMessage($this->room, $this->participant, $actorType, $actorId, $message, $creationDateTime, $parent, $referenceId, $silent); } catch (MessageTooLongException) { - return new DataResponse([], Http::STATUS_REQUEST_ENTITY_TOO_LARGE); + return new DataResponse(['error' => 'message'], Http::STATUS_REQUEST_ENTITY_TOO_LARGE); } catch (IRateLimitExceededException) { - return new DataResponse([], Http::STATUS_TOO_MANY_REQUESTS); + return new DataResponse(['error' => 'mentions'], Http::STATUS_TOO_MANY_REQUESTS); } catch (\Exception $e) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'message'], Http::STATUS_BAD_REQUEST); } return $this->parseCommentToResponse($comment, $parentMessage); @@ -272,7 +272,7 @@ public function sendMessage(string $message, string $actorDisplayName = '', stri * @param string $metaData Additional metadata * @param string $actorDisplayName Guest name * @param string $referenceId Reference ID - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse * * 201: Object shared successfully * 400: Sharing object is not possible @@ -287,7 +287,7 @@ public function sendMessage(string $message, string $actorDisplayName = '', stri public function shareObjectToChat(string $objectType, string $objectId, string $metaData = '', string $actorDisplayName = '', string $referenceId = ''): DataResponse { [$actorType, $actorId] = $this->getActorInfo($actorDisplayName); if (!$actorId) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'actor'], Http::STATUS_NOT_FOUND); } /** @var TalkRichObjectParameter $data */ @@ -301,18 +301,18 @@ public function shareObjectToChat(string $objectType, string $objectId, string $ $data['icon-url'] = $this->avatarService->getAvatarUrl($this->room); if (isset($data['link']) && !$this->trustedDomainHelper->isTrustedUrl($data['link'])) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'link'], Http::STATUS_BAD_REQUEST); } try { $this->richObjectValidator->validate('{object}', ['object' => $data]); } catch (InvalidObjectExeption $e) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'object'], Http::STATUS_BAD_REQUEST); } if ($data['type'] === 'geo-location' && !preg_match(ChatManager::GEO_LOCATION_VALIDATOR, $data['id'])) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'object'], Http::STATUS_BAD_REQUEST); } $this->participantService->ensureOneToOneRoomIsFilled($this->room); @@ -330,9 +330,9 @@ public function shareObjectToChat(string $objectType, string $objectId, string $ try { $comment = $this->chatManager->addSystemMessage($this->room, $actorType, $actorId, $message, $creationDateTime, true, $referenceId); } catch (MessageTooLongException $e) { - return new DataResponse([], Http::STATUS_REQUEST_ENTITY_TOO_LARGE); + return new DataResponse(['error' => 'message'], Http::STATUS_REQUEST_ENTITY_TOO_LARGE); } catch (\Exception $e) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'message'], Http::STATUS_BAD_REQUEST); } return $this->parseCommentToResponse($comment); @@ -413,7 +413,7 @@ protected function preloadShares(array $comments): void { * @param 0|1 $includeLastKnown Include the $lastKnownMessageId in the messages when 1 (default 0) * @param 0|1 $noStatusUpdate When the user status should not be automatically set to online set to 1 (default 0) * @param 0|1 $markNotificationsAsRead Set to 0 when notifications should not be marked as read (default 1) - * @return DataResponse|DataResponse, array> + * @return DataResponse, array{'X-Chat-Last-Common-Read'?: numeric-string, X-Chat-Last-Given?: numeric-string}>|DataResponse * * 200: Messages returned * 304: No messages @@ -511,7 +511,7 @@ public function receiveMessages(int $lookIntoFuture, * Required capability: `chat-summary-api` * * @param positive-int $fromMessageId Offset from where on the summary should be generated - * @return DataResponse|DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse|DataResponse * @throws \InvalidArgumentException * * 201: Summary was scheduled, use the returned taskId to get the status @@ -599,7 +599,7 @@ public function summarizeChat( } if (empty($messages)) { - return new DataResponse([], Http::STATUS_NO_CONTENT); + return new DataResponse(null, Http::STATUS_NO_CONTENT); } $task = new Task( @@ -638,7 +638,7 @@ public function summarizeChat( } /** - * @return DataResponse + * @return DataResponse, array{'X-Chat-Last-Common-Read'?: numeric-string, X-Chat-Last-Given?: numeric-string}>|DataResponse */ protected function prepareCommentsAsDataResponse(array $comments, int $lastCommonReadId = 0): DataResponse { if (empty($comments)) { @@ -653,7 +653,7 @@ protected function prepareCommentsAsDataResponse(array $comments, int $lastCommo return new DataResponse([], Http::STATUS_OK, $headers); } } - return new DataResponse([], Http::STATUS_NOT_MODIFIED); + return new DataResponse(null, Http::STATUS_NOT_MODIFIED); } $this->preloadShares($comments); @@ -774,7 +774,7 @@ protected function prepareCommentsAsDataResponse(array $comments, int $lastCommo * @param int $messageId The focused message which should be in the "middle" of the returned context * @psalm-param non-negative-int $messageId * @param int<1, 100> $limit Number of chat messages to receive in both directions (50 by default, 100 at most, might return 201 messages) - * @return DataResponse|DataResponse, array> + * @return DataResponse, array{'X-Chat-Last-Common-Read'?: numeric-string, X-Chat-Last-Given?: numeric-string}>|DataResponse * * 200: Message context returned * 304: No messages @@ -802,6 +802,12 @@ public function getMessageContext( return $this->prepareCommentsAsDataResponse(array_merge($commentsHistory, $commentsFuture)); } + /** + * @psalm-template T as list + * @psalm-param T $messages + * @param array $commentIdToIndex + * @psalm-return T + */ protected function loadSelfReactions(array $messages, array $commentIdToIndex): array { // Get message ids with reactions $messageIdsWithReactions = array_map( @@ -829,7 +835,7 @@ protected function loadSelfReactions(array $messages, array $commentIdToIndex): // Inject the reactions self into the $messages array foreach ($reactionsById as $messageId => $reactions) { - if (isset($commentIdToIndex[$messageId]) && isset($messages[$commentIdToIndex[$messageId]])) { + if (isset($commentIdToIndex[$messageId], $messages[$commentIdToIndex[$messageId]])) { $messages[$commentIdToIndex[$messageId]]['reactionsSelf'] = $reactions; } @@ -843,6 +849,7 @@ protected function loadSelfReactions(array $messages, array $commentIdToIndex): } } + /** @psalm-var T $messages */ return $messages; } @@ -851,7 +858,7 @@ protected function loadSelfReactions(array $messages, array $commentIdToIndex): * * @param int $messageId ID of the message * @psalm-param non-negative-int $messageId - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse * * 200: Message deleted successfully * 202: Message deleted successfully, but a bot or Matterbridge is configured, so the information can be replicated elsewhere @@ -879,8 +886,8 @@ public function deleteMessage(int $messageId): DataResponse { try { $message = $this->chatManager->getComment($this->room, (string)$messageId); - } catch (NotFoundException $e) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + } catch (NotFoundException) { + return new DataResponse(['error' => 'message'], Http::STATUS_NOT_FOUND); } $attendee = $this->participant->getAttendee(); @@ -894,12 +901,12 @@ public function deleteMessage(int $messageId): DataResponse { || $this->room->getType() === Room::TYPE_ONE_TO_ONE || $this->room->getType() === Room::TYPE_ONE_TO_ONE_FORMER)) { // Actor is not a moderator or not the owner of the message - return new DataResponse([], Http::STATUS_FORBIDDEN); + return new DataResponse(['error' => 'permission'], Http::STATUS_FORBIDDEN); } if ($message->getVerb() !== ChatManager::VERB_MESSAGE && $message->getVerb() !== ChatManager::VERB_OBJECT_SHARED) { // System message (since the message is not parsed, it has type "system") - return new DataResponse([], Http::STATUS_METHOD_NOT_ALLOWED); + return new DataResponse(['error' => 'message'], Http::STATUS_METHOD_NOT_ALLOWED); } try { @@ -909,8 +916,8 @@ public function deleteMessage(int $messageId): DataResponse { $this->participant, $this->timeFactory->getDateTime() ); - } catch (ShareNotFound $e) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + } catch (ShareNotFound) { + return new DataResponse(['error' => 'message'], Http::STATUS_NOT_FOUND); } $systemMessage = $this->messageParser->createMessage($this->room, $this->participant, $systemMessageComment, $this->l); @@ -942,7 +949,7 @@ public function deleteMessage(int $messageId): DataResponse { * @param int $messageId ID of the message * @param string $message the message to send * @psalm-param non-negative-int $messageId - * @return DataResponse|DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse|DataResponse * * 200: Message edited successfully * 202: Message edited successfully, but a bot or Matterbridge is configured, so the information can be replicated to other services @@ -973,7 +980,7 @@ public function editMessage(int $messageId, string $message): DataResponse { try { $comment = $this->chatManager->getComment($this->room, (string)$messageId); } catch (NotFoundException $e) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'message'], Http::STATUS_NOT_FOUND); } $attendee = $this->participant->getAttendee(); @@ -987,12 +994,12 @@ public function editMessage(int $messageId, string $message): DataResponse { || $this->room->getType() === Room::TYPE_ONE_TO_ONE || $this->room->getType() === Room::TYPE_ONE_TO_ONE_FORMER)) { // Actor is not a moderator or not the owner of the message - return new DataResponse([], Http::STATUS_FORBIDDEN); + return new DataResponse(['error' => 'permission'], Http::STATUS_FORBIDDEN); } if ($comment->getVerb() !== ChatManager::VERB_MESSAGE && $comment->getVerb() !== ChatManager::VERB_OBJECT_SHARED) { // System message (since the message is not parsed, it has type "system") - return new DataResponse([], Http::STATUS_METHOD_NOT_ALLOWED); + return new DataResponse(['error' => 'message'], Http::STATUS_METHOD_NOT_ALLOWED); } if ($this->room->getType() !== Room::TYPE_NOTE_TO_SELF) { @@ -1012,10 +1019,10 @@ public function editMessage(int $messageId, string $message): DataResponse { $message ); } catch (MessageTooLongException) { - return new DataResponse([], Http::STATUS_REQUEST_ENTITY_TOO_LARGE); + return new DataResponse(['error' => 'message'], Http::STATUS_REQUEST_ENTITY_TOO_LARGE); } catch (\InvalidArgumentException $e) { if ($e->getMessage() === 'object_share') { - return new DataResponse([], Http::STATUS_METHOD_NOT_ALLOWED); + return new DataResponse(['error' => 'message'], Http::STATUS_METHOD_NOT_ALLOWED); } return new DataResponse(['error' => $e->getMessage()], Http::STATUS_BAD_REQUEST); } @@ -1167,10 +1174,10 @@ protected function validateMessageExists(int $messageId, bool $sync = false): vo /** * Clear the chat history * - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse * * 200: History cleared successfully - * 202: History cleared successfully, but Matterbridge is configured, so the information can be replicated elsewhere + * 202: History cleared successfully, but Federation or Matterbridge is configured, so the information can be replicated elsewhere * 403: Missing permissions to clear history */ #[NoAdminRequired] @@ -1182,7 +1189,7 @@ public function clearHistory(): DataResponse { || $this->room->getType() === Room::TYPE_ONE_TO_ONE || $this->room->getType() === Room::TYPE_ONE_TO_ONE_FORMER) { // Actor is not a moderator or not the owner of the message - return new DataResponse([], Http::STATUS_FORBIDDEN); + return new DataResponse(null, Http::STATUS_FORBIDDEN); } $systemMessageComment = $this->chatManager->clearHistory( @@ -1319,7 +1326,7 @@ public function markUnread(): DataResponse { * Get objects that are shared in the room overview * * @param int<1, 20> $limit Maximum number of objects - * @return DataResponse, array{}> + * @return DataResponse>, array{}> * * 200: List of shared objects messages of each type returned */ @@ -1345,7 +1352,7 @@ public function getObjectsSharedInRoomOverview(int $limit = 7): DataResponse { // Get all attachments foreach ($objectTypes as $objectType) { $attachments = $this->attachmentService->getAttachmentsByType($this->room, $objectType, 0, $limit); - $messageIdsByType[$objectType] = array_map(static fn (Attachment $attachment): int => $attachment->getMessageId(), $attachments); + $messageIdsByType[$objectType] = array_map(static fn (Attachment $attachment): string => (string)$attachment->getMessageId(), $attachments); } $messages = $this->getMessagesForRoom(array_merge(...array_values($messageIdsByType))); @@ -1372,7 +1379,7 @@ public function getObjectsSharedInRoomOverview(int $limit = 7): DataResponse { * @param int $lastKnownMessageId ID of the last known message * @psalm-param non-negative-int $lastKnownMessageId * @param int<1, 200> $limit Maximum number of objects - * @return DataResponse + * @return DataResponse, array{X-Chat-Last-Given?: numeric-string}> * * 200: List of shared objects messages returned */ @@ -1386,7 +1393,6 @@ public function getObjectsSharedInRoom(string $objectType, int $lastKnownMessage $attachments = $this->attachmentService->getAttachmentsByType($this->room, $objectType, $offset, $limit); $messageIds = array_map(static fn (Attachment $attachment): int => $attachment->getMessageId(), $attachments); - /** @var TalkChatMessage[] $messages */ $messages = $this->getMessagesForRoom($messageIds); $headers = []; @@ -1399,7 +1405,7 @@ public function getObjectsSharedInRoom(string $objectType, int $lastKnownMessage } /** - * @return TalkChatMessage[] + * @return array */ protected function getMessagesForRoom(array $messageIds): array { $comments = $this->chatManager->getMessagesForRoomById($this->room, $messageIds); @@ -1422,7 +1428,7 @@ protected function getMessagesForRoom(array $messageIds): array { continue; } - $messages[(int)$comment->getId()] = $message->toArray($this->getResponseFormat()); + $messages[$comment->getId()] = $message->toArray($this->getResponseFormat()); } return $messages; @@ -1434,7 +1440,7 @@ protected function getMessagesForRoom(array $messageIds): array { * @param string $search Text to search for * @param int $limit Maximum number of results * @param bool $includeStatus Include the user statuses - * @return DataResponse + * @return DataResponse, array{}> * * 200: List of mention suggestions returned */ @@ -1490,8 +1496,8 @@ public function mentions(string $search, int $limit = 20, bool $includeStatus = /** * @param array $results - * @param IUserStatus[] $statuses - * @return TalkChatMentionSuggestion[] + * @param array $statuses + * @return list */ protected function prepareResultArray(array $results, array $statuses): array { $output = []; diff --git a/lib/Controller/PollController.php b/lib/Controller/PollController.php index 0b4722d47c6..02db3d10d14 100644 --- a/lib/Controller/PollController.php +++ b/lib/Controller/PollController.php @@ -30,7 +30,6 @@ use OCP\AppFramework\Http\Attribute\PublicPage; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Utility\ITimeFactory; -use OCP\DB\Exception; use OCP\IRequest; use Psr\Log\LoggerInterface; @@ -169,7 +168,7 @@ public function getAllDraftPolls(): DataResponse { * * @param int $pollId ID of the poll * @psalm-param non-negative-int $pollId - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse * * 200: Poll returned * 404: Poll not found @@ -188,11 +187,11 @@ public function showPoll(int $pollId): DataResponse { try { $poll = $this->pollService->getPoll($this->room->getId(), $pollId); } catch (DoesNotExistException) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'poll'], Http::STATUS_NOT_FOUND); } if ($poll->getStatus() === Poll::STATUS_DRAFT && !$this->participant->hasModeratorPermissions()) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'poll'], Http::STATUS_NOT_FOUND); } $votedSelf = $this->pollService->getVotesForActor($this->participant, $poll); @@ -209,8 +208,8 @@ public function showPoll(int $pollId): DataResponse { * * @param int $pollId ID of the poll * @psalm-param non-negative-int $pollId - * @param int[] $optionIds IDs of the selected options - * @return DataResponse|DataResponse, array{}> + * @param list $optionIds IDs of the selected options + * @return DataResponse|DataResponse * * 200: Voted successfully * 400: Voting is not possible @@ -230,21 +229,21 @@ public function votePoll(int $pollId, array $optionIds = []): DataResponse { try { $poll = $this->pollService->getPoll($this->room->getId(), $pollId); } catch (DoesNotExistException) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'poll'], Http::STATUS_NOT_FOUND); } if ($poll->getStatus() === Poll::STATUS_DRAFT) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'poll'], Http::STATUS_NOT_FOUND); } if ($poll->getStatus() === Poll::STATUS_CLOSED) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'poll'], Http::STATUS_BAD_REQUEST); } try { $votedSelf = $this->pollService->votePoll($this->participant, $poll, $optionIds); } catch (\RuntimeException $e) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'options'], Http::STATUS_BAD_REQUEST); } if ($poll->getResultMode() === Poll::MODE_PUBLIC) { @@ -274,7 +273,7 @@ public function votePoll(int $pollId, array $optionIds = []): DataResponse { * * @param int $pollId ID of the poll * @psalm-param non-negative-int $pollId - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse|DataResponse * * 200: Poll closed successfully * 202: Poll draft was deleted successfully @@ -296,27 +295,24 @@ public function closePoll(int $pollId): DataResponse { try { $poll = $this->pollService->getPoll($this->room->getId(), $pollId); } catch (DoesNotExistException) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'poll'], Http::STATUS_NOT_FOUND); } if ($poll->getStatus() === Poll::STATUS_DRAFT) { $this->pollService->deleteByPollId($poll->getId()); - return new DataResponse([], Http::STATUS_ACCEPTED); + return new DataResponse(null, Http::STATUS_ACCEPTED); } if ($poll->getStatus() === Poll::STATUS_CLOSED) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'poll'], Http::STATUS_BAD_REQUEST); } $poll->setStatus(Poll::STATUS_CLOSED); try { $this->pollService->updatePoll($this->participant, $poll); - } catch (WrongPermissionsException $e) { - return new DataResponse([], Http::STATUS_FORBIDDEN); - } catch (Exception $e) { - $this->logger->error($e->getMessage(), ['exception' => $e]); - return new DataResponse([], Http::STATUS_INTERNAL_SERVER_ERROR); + } catch (WrongPermissionsException) { + return new DataResponse(['error' => 'poll'], Http::STATUS_FORBIDDEN); } $attendee = $this->participant->getAttendee(); @@ -366,10 +362,10 @@ protected function renderPoll(Poll $poll, array $votedSelf = [], array $detailed $data['numVoters'] = 0; } } elseif ($poll->getResultMode() === Poll::MODE_PUBLIC && $poll->getStatus() === Poll::STATUS_CLOSED) { - $data['details'] = array_map(static fn (Vote $vote) => $vote->asArray(), $detailedVotes); + $data['details'] = array_values(array_map(static fn (Vote $vote) => $vote->asArray(), $detailedVotes)); } - $data['votedSelf'] = array_map(static fn (Vote $vote) => $vote->getOptionId(), $votedSelf); + $data['votedSelf'] = array_values(array_map(static fn (Vote $vote) => $vote->getOptionId(), $votedSelf)); return $data; } diff --git a/lib/Controller/PublicShareAuthController.php b/lib/Controller/PublicShareAuthController.php index f40882b1915..c1129d722fd 100644 --- a/lib/Controller/PublicShareAuthController.php +++ b/lib/Controller/PublicShareAuthController.php @@ -49,7 +49,7 @@ public function __construct( * otherwise. * * @param string $shareToken Token of the file share - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse * * 201: Room created successfully * 404: Share not found @@ -59,18 +59,18 @@ public function __construct( public function createRoom(string $shareToken): DataResponse { try { $share = $this->shareManager->getShareByToken($shareToken); - } catch (ShareNotFound $e) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + } catch (ShareNotFound) { + return new DataResponse(null, Http::STATUS_NOT_FOUND); } if (!$share->getSendPasswordByTalk()) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(null, Http::STATUS_NOT_FOUND); } $sharerUser = $this->userManager->get($share->getSharedBy()); if (!$sharerUser instanceof IUser) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(null, Http::STATUS_NOT_FOUND); } if ($share->getShareType() === IShare::TYPE_EMAIL) { diff --git a/lib/Controller/ReactionController.php b/lib/Controller/ReactionController.php index 85b90aaeab5..e84b84365cd 100644 --- a/lib/Controller/ReactionController.php +++ b/lib/Controller/ReactionController.php @@ -43,7 +43,7 @@ public function __construct( * @param int $messageId ID of the message * @psalm-param non-negative-int $messageId * @param string $reaction Emoji to add - * @return DataResponse|\stdClass, array{}>|DataResponse, array{}> + * @return DataResponse>|\stdClass, array{}>|DataResponse * * 200: Reaction already existed * 201: Reaction added successfully @@ -73,11 +73,11 @@ public function react(int $messageId, string $reaction): DataResponse { ); $status = Http::STATUS_CREATED; } catch (NotFoundException $e) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(null, Http::STATUS_NOT_FOUND); } catch (ReactionAlreadyExistsException $e) { $status = Http::STATUS_OK; } catch (ReactionNotSupportedException|ReactionOutOfContextException|\Exception $e) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(null, Http::STATUS_BAD_REQUEST); } $reactions = $this->reactionManager->retrieveReactionMessages($this->getRoom(), $this->getParticipant(), $messageId); return new DataResponse($this->formatReactions($reactions), $status); @@ -89,7 +89,7 @@ public function react(int $messageId, string $reaction): DataResponse { * @param int $messageId ID of the message * @psalm-param non-negative-int $messageId * @param string $reaction Emoji to remove - * @return DataResponse|\stdClass, array{}>|DataResponse, array{}> + * @return DataResponse>|\stdClass, array{}>|DataResponse * * 200: Reaction deleted successfully * 400: Deleting reaction is not possible @@ -118,9 +118,9 @@ public function delete(int $messageId, string $reaction): DataResponse { ); $reactions = $this->reactionManager->retrieveReactionMessages($this->getRoom(), $this->getParticipant(), $messageId); } catch (ReactionNotSupportedException|ReactionOutOfContextException|NotFoundException $e) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(null, Http::STATUS_NOT_FOUND); } catch (\Exception $e) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(null, Http::STATUS_BAD_REQUEST); } return new DataResponse($this->formatReactions($reactions), Http::STATUS_OK); @@ -132,7 +132,7 @@ public function delete(int $messageId, string $reaction): DataResponse { * @param int $messageId ID of the message * @psalm-param non-negative-int $messageId * @param string|null $reaction Emoji to filter - * @return DataResponse|\stdClass, array{}>|DataResponse, array{}> + * @return DataResponse>|\stdClass, array{}>|DataResponse * * 200: Reactions returned * 404: Message or reaction not found @@ -152,7 +152,7 @@ public function getReactions(int $messageId, ?string $reaction): DataResponse { // Verify that messageId is part of the room $this->reactionManager->getCommentToReact($this->getRoom(), (string)$messageId); } catch (ReactionNotSupportedException|ReactionOutOfContextException|NotFoundException $e) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(null, Http::STATUS_NOT_FOUND); } $reactions = $this->reactionManager->retrieveReactionMessages($this->getRoom(), $this->getParticipant(), $messageId, $reaction); @@ -161,8 +161,8 @@ public function getReactions(int $messageId, ?string $reaction): DataResponse { } /** - * @param array $reactions - * @return array|\stdClass + * @param array> $reactions + * @return array>|\stdClass */ protected function formatReactions(array $reactions): array|\stdClass { if ($this->getResponseFormat() === 'json' && empty($reactions)) { diff --git a/lib/Controller/RoomController.php b/lib/Controller/RoomController.php index 4800d04b7b6..410398b7317 100644 --- a/lib/Controller/RoomController.php +++ b/lib/Controller/RoomController.php @@ -13,10 +13,12 @@ use OCA\Talk\Events\AAttendeeRemovedEvent; use OCA\Talk\Events\BeforeRoomsFetchEvent; use OCA\Talk\Exceptions\CannotReachRemoteException; +use OCA\Talk\Exceptions\FederationRestrictionException; use OCA\Talk\Exceptions\ForbiddenException; use OCA\Talk\Exceptions\GuestImportException; use OCA\Talk\Exceptions\InvalidPasswordException; use OCA\Talk\Exceptions\ParticipantNotFoundException; +use OCA\Talk\Exceptions\ParticipantProperty\PermissionsException; use OCA\Talk\Exceptions\RoomNotFoundException; use OCA\Talk\Exceptions\RoomProperty\DefaultPermissionsException; use OCA\Talk\Exceptions\RoomProperty\DescriptionException; @@ -177,7 +179,7 @@ protected function getTalkHashHeader(): array { * @param bool $includeStatus Include the user status * @param int $modifiedSince Filter rooms modified after a timestamp * @psalm-param non-negative-int $modifiedSince - * @return DataResponse + * @return DataResponse, array{X-Nextcloud-Talk-Hash: string, X-Nextcloud-Talk-Modified-Before: numeric-string, X-Nextcloud-Talk-Federation-Invites?: numeric-string}> * * 200: Return list of rooms */ @@ -286,7 +288,7 @@ public function getRooms(int $noStatusUpdate = 0, bool $includeStatus = false, i * Get listed rooms with optional search term * * @param string $searchTerm search term - * @return DataResponse + * @return DataResponse, array{}> * * 200: Return list of matching rooms */ @@ -307,7 +309,7 @@ public function getListedRooms(string $searchTerm = ''): DataResponse { * * All for moderators and in case of "free selection", or the assigned breakout room for other participants * - * @return DataResponse|DataResponse + * @return DataResponse, array{}>|DataResponse * * 200: Breakout rooms returned * 400: Getting breakout rooms is not possible @@ -503,7 +505,7 @@ protected function formatRoom(Room $room, ?Participant $currentParticipant, ?arr * @param string $objectType Type of the object * @param string $objectId ID of the object * @param string $password The room password (only available with `conversation-creation-password` capability) - * @return DataResponse|DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse * * 200: Room already existed * 201: Room created successfully @@ -526,7 +528,7 @@ public function createRoom( $user = $this->userManager->get($this->userId); if ($this->talkConfig->isNotAllowedToCreateConversations($user)) { - return new DataResponse([], Http::STATUS_FORBIDDEN); + return new DataResponse(['error' => 'permissions'], Http::STATUS_FORBIDDEN); } } @@ -545,29 +547,30 @@ public function createRoom( return $this->createEmptyRoom($roomName, true, $objectType, $objectId, $password); } - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'type'], Http::STATUS_BAD_REQUEST); } /** * Initiates a one-to-one video call from the current user to the recipient * * @param string $targetUserId ID of the user - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse */ #[NoAdminRequired] protected function createOneToOneRoom(string $targetUserId): DataResponse { $currentUser = $this->userManager->get($this->userId); if (!$currentUser instanceof IUser) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + // Should never happen, basically an internal server error so we reuse another error + return new DataResponse(['error' => 'invite'], Http::STATUS_NOT_FOUND); } if ($targetUserId === MatterbridgeManager::BRIDGE_BOT_USERID) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'invite'], Http::STATUS_NOT_FOUND); } $targetUser = $this->userManager->get($targetUserId); if (!$targetUser instanceof IUser) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'invite'], Http::STATUS_NOT_FOUND); } try { @@ -590,9 +593,9 @@ protected function createOneToOneRoom(string $targetUserId): DataResponse { ); } catch (\InvalidArgumentException $e) { // Same current and target user - return new DataResponse([], Http::STATUS_FORBIDDEN); + return new DataResponse(['error' => 'invite'], Http::STATUS_FORBIDDEN); } catch (RoomNotFoundException $e) { - return new DataResponse([], Http::STATUS_FORBIDDEN); + return new DataResponse(['error' => 'invite'], Http::STATUS_FORBIDDEN); } } @@ -600,18 +603,19 @@ protected function createOneToOneRoom(string $targetUserId): DataResponse { * Initiates a group video call from the selected group * * @param string $targetGroupName - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse */ #[NoAdminRequired] protected function createGroupRoom(string $targetGroupName): DataResponse { $currentUser = $this->userManager->get($this->userId); if (!$currentUser instanceof IUser) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + // Should never happen, basically an internal server error so we reuse another error + return new DataResponse(['error' => 'invite'], Http::STATUS_NOT_FOUND); } $targetGroup = $this->groupManager->get($targetGroupName); if (!$targetGroup instanceof IGroup) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'invite'], Http::STATUS_NOT_FOUND); } // Create the room @@ -626,23 +630,24 @@ protected function createGroupRoom(string $targetGroupName): DataResponse { * Initiates a group video call from the selected circle * * @param string $targetCircleId - * @return DataResponse|DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse */ #[NoAdminRequired] protected function createCircleRoom(string $targetCircleId): DataResponse { if (!$this->appManager->isEnabledForUser('circles')) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'invite'], Http::STATUS_BAD_REQUEST); } $currentUser = $this->userManager->get($this->userId); if (!$currentUser instanceof IUser) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + // Should never happen, basically an internal server error so we reuse another error + return new DataResponse(['error' => 'invite'], Http::STATUS_NOT_FOUND); } try { $circle = $this->participantService->getCircle($targetCircleId, $this->userId); } catch (\Exception $e) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'invite'], Http::STATUS_NOT_FOUND); } // Create the room @@ -654,13 +659,14 @@ protected function createCircleRoom(string $targetCircleId): DataResponse { } /** - * @return DataResponse|DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse */ #[NoAdminRequired] protected function createEmptyRoom(string $roomName, bool $public = true, string $objectType = '', string $objectId = '', string $password = ''): DataResponse { $currentUser = $this->userManager->get($this->userId); if (!$currentUser instanceof IUser) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + // Should never happen, basically an internal server error so we reuse another error + return new DataResponse(['error' => 'invite'], Http::STATUS_NOT_FOUND); } $roomType = $public ? Room::TYPE_PUBLIC : Room::TYPE_GROUP; @@ -725,7 +731,7 @@ protected function createEmptyRoom(string $roomName, bool $public = true, string /** * Add a room to the favorites * - * @return DataResponse, array{}> + * @return DataResponse * * 200: Successfully added room to favorites */ @@ -734,13 +740,13 @@ protected function createEmptyRoom(string $roomName, bool $public = true, string #[RequireLoggedInParticipant] public function addToFavorites(): DataResponse { $this->participantService->updateFavoriteStatus($this->participant, true); - return new DataResponse([]); + return new DataResponse($this->formatRoom($this->room, $this->participant)); } /** * Remove a room from the favorites * - * @return DataResponse, array{}> + * @return DataResponse * * 200: Successfully removed room from favorites */ @@ -749,7 +755,7 @@ public function addToFavorites(): DataResponse { #[RequireLoggedInParticipant] public function removeFromFavorites(): DataResponse { $this->participantService->updateFavoriteStatus($this->participant, false); - return new DataResponse([]); + return new DataResponse($this->formatRoom($this->room, $this->participant)); } /** @@ -757,7 +763,7 @@ public function removeFromFavorites(): DataResponse { * * @param int $level New level * @psalm-param Participant::NOTIFY_* $level - * @return DataResponse, array{}> + * @return DataResponse|DataResponse * * 200: Notification level updated successfully * 400: Updating notification level is not possible @@ -768,11 +774,11 @@ public function removeFromFavorites(): DataResponse { public function setNotificationLevel(int $level): DataResponse { try { $this->participantService->updateNotificationLevel($this->participant, $level); - } catch (\InvalidArgumentException $e) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + } catch (\InvalidArgumentException) { + return new DataResponse(['error' => 'level'], Http::STATUS_BAD_REQUEST); } - return new DataResponse(); + return new DataResponse($this->formatRoom($this->room, $this->participant)); } /** @@ -780,7 +786,7 @@ public function setNotificationLevel(int $level): DataResponse { * * @param int $level New level * @psalm-param Participant::NOTIFY_CALLS_* $level - * @return DataResponse, array{}> + * @return DataResponse|DataResponse * * 200: Call notification level updated successfully * 400: Updating call notification level is not possible @@ -790,18 +796,18 @@ public function setNotificationLevel(int $level): DataResponse { public function setNotificationCalls(int $level): DataResponse { try { $this->participantService->updateNotificationCalls($this->participant, $level); - } catch (\InvalidArgumentException $e) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + } catch (\InvalidArgumentException) { + return new DataResponse(['error' => 'level'], Http::STATUS_BAD_REQUEST); } - return new DataResponse(); + return new DataResponse($this->formatRoom($this->room, $this->participant)); } /** * Rename a room * * @param string $roomName New name - * @return DataResponse, array{}>|DataResponse + * @return DataResponse|DataResponse * * 200: Room renamed successfully * 400: Renaming room is not possible @@ -814,14 +820,14 @@ public function renameRoom(string $roomName): DataResponse { } catch (NameException $e) { return new DataResponse(['error' => $e->getReason()], Http::STATUS_BAD_REQUEST); } - return new DataResponse(); + return new DataResponse($this->formatRoom($this->room, $this->participant)); } /** * Update the description of a room * * @param string $description New description - * @return DataResponse, array{}>|DataResponse + * @return DataResponse|DataResponse * * 200: Description updated successfully * 400: Updating description is not possible @@ -835,13 +841,13 @@ public function setDescription(string $description): DataResponse { return new DataResponse(['error' => $e->getReason()], Http::STATUS_BAD_REQUEST); } - return new DataResponse(); + return new DataResponse($this->formatRoom($this->room, $this->participant)); } /** * Delete a room * - * @return DataResponse, array{}> + * @return DataResponse * * 200: Room successfully deleted * 400: Deleting room is not possible @@ -850,12 +856,12 @@ public function setDescription(string $description): DataResponse { #[RequireModeratorParticipant] public function deleteRoom(): DataResponse { if ($this->room->getType() === Room::TYPE_ONE_TO_ONE || $this->room->getType() === Room::TYPE_ONE_TO_ONE_FORMER) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(null, Http::STATUS_BAD_REQUEST); } $this->roomService->deleteRoom($this->room); - return new DataResponse([]); + return new DataResponse(null); } /** @@ -863,7 +869,7 @@ public function deleteRoom(): DataResponse { * Get a list of participants for a room * * @param bool $includeStatus Include the user statuses - * @return DataResponse|DataResponse, array{}> + * @return DataResponse, array{X-Nextcloud-Has-User-Statuses?: bool}>|DataResponse * * 200: Participants returned * 403: Missing permissions for getting participants @@ -916,7 +922,7 @@ public function getParticipants(bool $includeStatus = false): DataResponse { } if ($this->participant->getAttendee()->getParticipantType() === Participant::GUEST) { - return new DataResponse([], Http::STATUS_FORBIDDEN); + return new DataResponse(null, Http::STATUS_FORBIDDEN); } $participants = $this->participantService->getSessionsAndParticipantsForRoom($this->room); @@ -928,7 +934,7 @@ public function getParticipants(bool $includeStatus = false): DataResponse { * Get the breakout room participants for a room * * @param bool $includeStatus Include the user statuses - * @return DataResponse|DataResponse|DataResponse, array{}> + * @return DataResponse, array{X-Nextcloud-Has-User-Statuses?: bool}>|DataResponse|DataResponse * * 200: Breakout room participants returned * 400: Getting breakout room participants is not possible @@ -939,7 +945,7 @@ public function getParticipants(bool $includeStatus = false): DataResponse { #[RequireParticipant] public function getBreakoutRoomParticipants(bool $includeStatus = false): DataResponse { if ($this->participant->getAttendee()->getParticipantType() === Participant::GUEST) { - return new DataResponse([], Http::STATUS_FORBIDDEN); + return new DataResponse(null, Http::STATUS_FORBIDDEN); } try { @@ -1131,7 +1137,7 @@ protected function formatParticipantList(array $participants, bool $includeStatu * * @param string $newParticipant New participant * @param 'users'|'groups'|'circles'|'emails'|'federated_users'|'phones' $source Source of the participant - * @return DataResponse, array{}>|DataResponse, array{}>|DataResponse + * @return DataResponse|DataResponse * * 200: Participant successfully added * 400: Adding participant is not possible, e.g. when the user is banned (check error attribute of response for detail key) @@ -1145,7 +1151,7 @@ public function addParticipantToRoom(string $newParticipant, string $source = 'u || $this->room->getType() === Room::TYPE_ONE_TO_ONE_FORMER || $this->room->getType() === Room::TYPE_NOTE_TO_SELF || $this->room->getObjectType() === Room::OBJECT_TYPE_VIDEO_VERIFICATION) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'room-type'], Http::STATUS_BAD_REQUEST); } if ($source !== 'users' && $this->room->getObjectType() === BreakoutRoom::PARENT_OBJECT_TYPE) { @@ -1173,12 +1179,12 @@ public function addParticipantToRoom(string $newParticipant, string $source = 'u if ($source === 'users') { if ($newParticipant === MatterbridgeManager::BRIDGE_BOT_USERID) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'new-participant'], Http::STATUS_NOT_FOUND); } $newUser = $this->userManager->get($newParticipant); if (!$newUser instanceof IUser) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'new-participant'], Http::STATUS_NOT_FOUND); } //Check if the user is banned @@ -1194,19 +1200,19 @@ public function addParticipantToRoom(string $newParticipant, string $source = 'u } elseif ($source === 'groups') { $group = $this->groupManager->get($newParticipant); if (!$group instanceof IGroup) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'new-participant'], Http::STATUS_NOT_FOUND); } $this->participantService->addGroup($this->room, $group, $participants); } elseif ($source === 'circles') { if (!$this->appManager->isEnabledForUser('circles')) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'new-participant'], Http::STATUS_BAD_REQUEST); } try { $circle = $this->participantService->getCircle($newParticipant, $this->userId); - } catch (\Exception $e) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + } catch (\Exception) { + return new DataResponse(['error' => 'new-participant'], Http::STATUS_NOT_FOUND); } $this->participantService->addCircle($this->room, $circle, $participants); @@ -1230,7 +1236,7 @@ public function addParticipantToRoom(string $newParticipant, string $source = 'u return new DataResponse($data); } elseif ($source === 'federated_users') { if (!$this->talkConfig->isFederationEnabled()) { - return new DataResponse([], Http::STATUS_NOT_IMPLEMENTED); + return new DataResponse(['error' => 'federation'], Http::STATUS_NOT_IMPLEMENTED); } try { $newUser = $this->cloudIdManager->resolveCloudId($newParticipant); @@ -1238,12 +1244,12 @@ public function addParticipantToRoom(string $newParticipant, string $source = 'u $this->logger->error($e->getMessage(), [ 'exception' => $e, ]); - return new DataResponse(['error' => 'cloudId'], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'cloud-id'], Http::STATUS_BAD_REQUEST); } try { $this->federationManager->isAllowedToInvite($addedBy, $newUser); - } catch (\InvalidArgumentException $e) { - return new DataResponse(['error' => $e->getMessage()], Http::STATUS_BAD_REQUEST); + } catch (FederationRestrictionException $e) { + return new DataResponse(['error' => $e->getReason()], Http::STATUS_BAD_REQUEST); } $participantsToAdd[] = [ @@ -1258,7 +1264,7 @@ public function addParticipantToRoom(string $newParticipant, string $source = 'u || !$this->talkConfig->canUserDialOutSIP($addedBy) || preg_match(Room::SIP_INCOMPATIBLE_REGEX, $this->room->getToken()) || ($this->room->getType() !== Room::TYPE_GROUP && $this->room->getType() !== Room::TYPE_PUBLIC)) { - return new DataResponse([], Http::STATUS_NOT_IMPLEMENTED); + return new DataResponse(['error' => 'sip'], Http::STATUS_NOT_IMPLEMENTED); } $phoneRegion = $this->config->getSystemValueString('default_phone_region'); @@ -1279,7 +1285,7 @@ public function addParticipantToRoom(string $newParticipant, string $source = 'u ]; } else { $this->logger->error('Trying to add participant from unsupported source ' . $source); - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'source'], Http::STATUS_BAD_REQUEST); } // attempt adding the listed users to the room @@ -1318,7 +1324,9 @@ public function addParticipantToRoom(string $newParticipant, string $source = 'u try { $this->breakoutRoomService->removeAttendeeFromBreakoutRoom($parentRoom, Attendee::ACTOR_USERS, $newParticipant); } catch (\InvalidArgumentException $e) { - return new DataResponse(['error' => $e->getMessage()], Http::STATUS_BAD_REQUEST); + /** @var 'moderator' $error */ + $error = $e->getMessage(); + return new DataResponse(['error' => $error], Http::STATUS_BAD_REQUEST); } } @@ -1326,7 +1334,7 @@ public function addParticipantToRoom(string $newParticipant, string $source = 'u try { $this->participantService->addUsers($this->room, $participantsToAdd, $addedBy); } catch (CannotReachRemoteException $e) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'reach-remote'], Http::STATUS_NOT_FOUND); } return new DataResponse([]); @@ -1335,7 +1343,7 @@ public function addParticipantToRoom(string $newParticipant, string $source = 'u /** * Remove the current user from a room * - * @return DataResponse, array{}> + * @return DataResponse|DataResponse * * * 200: Participant removed successfully * 400: Removing participant is not possible @@ -1349,7 +1357,7 @@ public function removeSelfFromRoom(): DataResponse { } /** - * @return DataResponse, array{}> + * @return DataResponse|DataResponse */ protected function removeSelfFromRoomLogic(Room $room, Participant $participant): DataResponse { if ($room->isFederatedConversation()) { @@ -1360,7 +1368,7 @@ protected function removeSelfFromRoomLogic(Room $room, Participant $participant) if ($participant->hasModeratorPermissions(false) && $this->participantService->getNumberOfUsers($room) > 1 && $this->participantService->getNumberOfModerators($room) === 1) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'last-moderator'], Http::STATUS_BAD_REQUEST); } } @@ -1373,17 +1381,17 @@ protected function removeSelfFromRoomLogic(Room $room, Participant $participant) Participant::OWNER, ], true)) { $this->roomService->deleteRoom($room); - return new DataResponse(); + return new DataResponse(null); } $currentUser = $this->userManager->get($this->userId); if (!$currentUser instanceof IUser) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'participant'], Http::STATUS_NOT_FOUND); } $this->participantService->removeUser($room, $currentUser, AAttendeeRemovedEvent::REASON_LEFT); - return new DataResponse(); + return new DataResponse(null); } /** @@ -1391,7 +1399,7 @@ protected function removeSelfFromRoomLogic(Room $room, Participant $participant) * * @param int $attendeeId ID of the attendee * @psalm-param non-negative-int $attendeeId - * @return DataResponse, array{}> + * @return DataResponse|DataResponse * * 200: Attendee removed successfully * 400: Removing attendee is not possible @@ -1404,16 +1412,16 @@ public function removeAttendeeFromRoom(int $attendeeId): DataResponse { try { $targetParticipant = $this->participantService->getParticipantByAttendeeId($this->room, $attendeeId); } catch (ParticipantNotFoundException $e) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'participant'], Http::STATUS_NOT_FOUND); } if ($targetParticipant->getAttendee()->getActorType() === Attendee::ACTOR_USERS && $targetParticipant->getAttendee()->getActorId() === MatterbridgeManager::BRIDGE_BOT_USERID) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'participant'], Http::STATUS_NOT_FOUND); } if ($this->room->getType() === Room::TYPE_ONE_TO_ONE || $this->room->getType() === Room::TYPE_ONE_TO_ONE_FORMER) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(['error' => 'room-type'], Http::STATUS_BAD_REQUEST); } if ($this->participant->getAttendee()->getId() === $targetParticipant->getAttendee()->getId()) { @@ -1421,11 +1429,11 @@ public function removeAttendeeFromRoom(int $attendeeId): DataResponse { } if ($targetParticipant->getAttendee()->getParticipantType() === Participant::OWNER) { - return new DataResponse([], Http::STATUS_FORBIDDEN); + return new DataResponse(['error' => 'owner'], Http::STATUS_FORBIDDEN); } $this->participantService->removeAttendee($this->room, $targetParticipant, AAttendeeRemovedEvent::REASON_REMOVED); - return new DataResponse([]); + return new DataResponse(null); } /** @@ -1434,7 +1442,7 @@ public function removeAttendeeFromRoom(int $attendeeId): DataResponse { * Required capability: `conversation-creation-password` for `string $password` parameter * * @param string $password New password (only available with `conversation-creation-password` capability) - * @return DataResponse, array{}>|DataResponse + * @return DataResponse|DataResponse * * 200: Allowed guests successfully * 400: Allowing guests is not possible @@ -1458,13 +1466,13 @@ public function makePublic(string $password = ''): DataResponse { return new DataResponse(['error' => $e->getReason()], Http::STATUS_BAD_REQUEST); } - return new DataResponse(); + return new DataResponse($this->formatRoom($this->room, $this->participant)); } /** * Disallowed guests to join conversation * - * @return DataResponse, array{}>|DataResponse + * @return DataResponse|DataResponse * * 200: Room unpublished Disallowing guests successfully * 400: Disallowing guests is not possible @@ -1478,7 +1486,7 @@ public function makePrivate(): DataResponse { return new DataResponse(['error' => $e->getReason()], Http::STATUS_BAD_REQUEST); } - return new DataResponse(); + return new DataResponse($this->formatRoom($this->room, $this->participant)); } /** @@ -1486,7 +1494,7 @@ public function makePrivate(): DataResponse { * * @param 0|1 $state New read-only state * @psalm-param Room::READ_* $state - * @return DataResponse, array{}>|DataResponse + * @return DataResponse|DataResponse * * 200: Read-only state updated successfully * 400: Updating read-only state is not possible @@ -1509,7 +1517,7 @@ public function setReadOnly(int $state): DataResponse { } } - return new DataResponse(); + return new DataResponse($this->formatRoom($this->room, $this->participant)); } /** @@ -1517,7 +1525,7 @@ public function setReadOnly(int $state): DataResponse { * * @param 0|1|2 $scope Scope where the room is listable * @psalm-param Room::LISTABLE_* $scope - * @return DataResponse, array{}>|DataResponse + * @return DataResponse|DataResponse * * 200: Made room listable successfully * 400: Making room listable is not possible @@ -1531,7 +1539,7 @@ public function setListable(int $scope): DataResponse { return new DataResponse(['error' => $e->getReason()], Http::STATUS_BAD_REQUEST); } - return new DataResponse(); + return new DataResponse($this->formatRoom($this->room, $this->participant)); } /** @@ -1560,7 +1568,7 @@ public function setMentionPermissions(int $mentionPermissions): DataResponse { * Set a password for a room * * @param string $password New password - * @return DataResponse, array{}>|DataResponse + * @return DataResponse|DataResponse * * 200: Password set successfully * 400: Setting password is not possible @@ -1578,7 +1586,7 @@ public function setPassword(string $password): DataResponse { return new DataResponse($data, Http::STATUS_BAD_REQUEST); } - return new DataResponse(); + return new DataResponse($this->formatRoom($this->room, $this->participant)); } /** @@ -1621,7 +1629,7 @@ public function unarchiveConversation(): DataResponse { * @param string $token Token of the room * @param string $password Password of the room * @param bool $force Create a new session if necessary - * @return DataResponse|DataResponse>|DataResponse, array>|DataResponse> + * @return DataResponse|DataResponse|DataResponse|DataResponse * * 200: Room joined successfully * 403: Joining room is not allowed @@ -1637,7 +1645,7 @@ public function joinRoom(string $token, string $password = '', bool $force = tru // The participant is just joining, so enforce to not load any session $room = $this->manager->getRoomForUserByToken($token, $this->userId, null); } catch (RoomNotFoundException $e) { - $response = new DataResponse([], Http::STATUS_NOT_FOUND); + $response = new DataResponse(null, Http::STATUS_NOT_FOUND); $response->throttle(['token' => $token, 'action' => 'talkRoomToken']); return $response; } @@ -1721,7 +1729,7 @@ public function joinRoom(string $token, string $password = '', bool $force = tru $response->throttle(['token' => $token, 'action' => 'talkRoomPassword']); return $response; } catch (UnauthorizedException $e) { - $response = new DataResponse([], Http::STATUS_NOT_FOUND); + $response = new DataResponse(null, Http::STATUS_NOT_FOUND); $response->throttle(['token' => $token, 'action' => 'talkRoomToken']); return $response; } @@ -1746,7 +1754,7 @@ public function joinRoom(string $token, string $password = '', bool $force = tru if ($response->getStatus() === Http::STATUS_NOT_FOUND) { $this->participantService->removeAttendee($room, $participant, AAttendeeRemovedEvent::REASON_REMOVED); - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(null, Http::STATUS_NOT_FOUND); } /** @var TalkRoom $data */ @@ -1819,7 +1827,7 @@ public function joinFederatedRoom(string $token, ?string $sessionId): DataRespon * Verify a dial-in PIN (SIP bridge) * * @param numeric-string $pin PIN the participant used to dial-in - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse * * 200: Participant returned * 401: SIP request invalid @@ -1833,24 +1841,24 @@ public function joinFederatedRoom(string $token, ?string $sessionId): DataRespon public function verifyDialInPin(string $pin): DataResponse { try { if (!$this->validateSIPBridgeRequest($this->room->getToken())) { - $response = new DataResponse([], Http::STATUS_UNAUTHORIZED); + $response = new DataResponse(null, Http::STATUS_UNAUTHORIZED); $response->throttle(['action' => 'talkSipBridgeSecret']); return $response; } } catch (UnauthorizedException) { - $response = new DataResponse([], Http::STATUS_UNAUTHORIZED); + $response = new DataResponse(null, Http::STATUS_UNAUTHORIZED); $response->throttle(['action' => 'talkSipBridgeSecret']); return $response; } if (!$this->talkConfig->isSIPConfigured()) { - return new DataResponse([], Http::STATUS_NOT_IMPLEMENTED); + return new DataResponse(null, Http::STATUS_NOT_IMPLEMENTED); } try { $participant = $this->participantService->getParticipantByPin($this->room, $pin); } catch (ParticipantNotFoundException $e) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(null, Http::STATUS_NOT_FOUND); } return new DataResponse($this->formatRoom($this->room, $participant)); @@ -1861,7 +1869,7 @@ public function verifyDialInPin(string $pin): DataResponse { * * @param string $number E164 formatted phone number * @param array{actorId?: string, actorType?: string, attendeeId?: int} $options Additional details to verify the validity of the request - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse * * 200: Participant created successfully * 400: Phone number and details could not be confirmed @@ -1876,32 +1884,32 @@ public function verifyDialInPin(string $pin): DataResponse { public function verifyDialOutNumber(string $number, array $options = []): DataResponse { try { if (!$this->validateSIPBridgeRequest($this->room->getToken())) { - $response = new DataResponse([], Http::STATUS_UNAUTHORIZED); + $response = new DataResponse(null, Http::STATUS_UNAUTHORIZED); $response->throttle(['action' => 'talkSipBridgeSecret']); return $response; } } catch (UnauthorizedException) { - $response = new DataResponse([], Http::STATUS_UNAUTHORIZED); + $response = new DataResponse(null, Http::STATUS_UNAUTHORIZED); $response->throttle(['action' => 'talkSipBridgeSecret']); return $response; } if (!$this->talkConfig->isSIPConfigured() || !$this->talkConfig->isSIPDialOutEnabled()) { - return new DataResponse([], Http::STATUS_NOT_IMPLEMENTED); + return new DataResponse(null, Http::STATUS_NOT_IMPLEMENTED); } if (!isset($options['actorId'], $options['actorType']) || $options['actorType'] !== Attendee::ACTOR_PHONES) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(null, Http::STATUS_BAD_REQUEST); } try { $participant = $this->participantService->getParticipantByActor($this->room, Attendee::ACTOR_PHONES, $options['actorId']); } catch (ParticipantNotFoundException) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(null, Http::STATUS_NOT_FOUND); } if ($participant->getAttendee()->getPhoneNumber() !== $number) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(null, Http::STATUS_BAD_REQUEST); } return new DataResponse($this->formatRoom($this->room, $participant)); @@ -1910,7 +1918,7 @@ public function verifyDialOutNumber(string $number, array $options = []): DataRe /** * Create a guest by their dial-in * - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse * * 200: Participant created successfully * 400: SIP not enabled @@ -1923,18 +1931,18 @@ public function verifyDialOutNumber(string $number, array $options = []): DataRe public function createGuestByDialIn(): DataResponse { try { if (!$this->validateSIPBridgeRequest($this->room->getToken())) { - $response = new DataResponse([], Http::STATUS_UNAUTHORIZED); + $response = new DataResponse(null, Http::STATUS_UNAUTHORIZED); $response->throttle(['action' => 'talkSipBridgeSecret']); return $response; } } catch (UnauthorizedException $e) { - $response = new DataResponse([], Http::STATUS_UNAUTHORIZED); + $response = new DataResponse(null, Http::STATUS_UNAUTHORIZED); $response->throttle(['action' => 'talkSipBridgeSecret']); return $response; } if ($this->room->getSIPEnabled() !== Webinary::SIP_ENABLED_NO_PIN) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(null, Http::STATUS_BAD_REQUEST); } $participant = $this->participantService->joinRoomAsNewGuest($this->roomService, $this->room, '', true); @@ -1947,7 +1955,7 @@ public function createGuestByDialIn(): DataResponse { * * @param string $callId The call ID provided by the SIP bridge earlier to uniquely identify the call to terminate * @param array{actorId?: string, actorType?: string, attendeeId?: int} $options Additional details to verify the validity of the request - * @return DataResponse, array{}> + * @return DataResponse * * 200: Call ID reset * 400: Call ID mismatch or attendeeId not found in $options @@ -1962,33 +1970,33 @@ public function createGuestByDialIn(): DataResponse { public function rejectedDialOutRequest(string $callId, array $options = []): DataResponse { try { if (!$this->validateSIPBridgeRequest($this->room->getToken())) { - $response = new DataResponse([], Http::STATUS_UNAUTHORIZED); + $response = new DataResponse(null, Http::STATUS_UNAUTHORIZED); $response->throttle(['action' => 'talkSipBridgeSecret']); return $response; } } catch (UnauthorizedException $e) { - $response = new DataResponse([], Http::STATUS_UNAUTHORIZED); + $response = new DataResponse(null, Http::STATUS_UNAUTHORIZED); $response->throttle(['action' => 'talkSipBridgeSecret']); return $response; } if (empty($options['attendeeId'])) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(null, Http::STATUS_BAD_REQUEST); } if (!$this->talkConfig->isSIPConfigured() || !$this->talkConfig->isSIPDialOutEnabled()) { - return new DataResponse([], Http::STATUS_NOT_IMPLEMENTED); + return new DataResponse(null, Http::STATUS_NOT_IMPLEMENTED); } try { $this->participantService->resetDialOutRequest($this->room, $options['attendeeId'], $callId); } catch (ParticipantNotFoundException) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(null, Http::STATUS_NOT_FOUND); } catch (\InvalidArgumentException) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(null, Http::STATUS_BAD_REQUEST); } - return new DataResponse([], Http::STATUS_OK); + return new DataResponse(null); } /** @@ -1996,7 +2004,7 @@ public function rejectedDialOutRequest(string $callId, array $options = []): Dat * * @param 0|1 $state of the room * @psalm-param Session::STATE_* $state - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse * * 200: Session state set successfully * 400: The provided new state was invalid @@ -2007,13 +2015,13 @@ public function rejectedDialOutRequest(string $callId, array $options = []): Dat #[RequireParticipant] public function setSessionState(int $state): DataResponse { if (!$this->participant->getSession() instanceof Session) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(null, Http::STATUS_NOT_FOUND); } try { $this->sessionService->updateSessionState($this->participant->getSession(), $state); } catch (\InvalidArgumentException) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(null, Http::STATUS_BAD_REQUEST); } return new DataResponse($this->formatRoom($this->room, $this->participant)); @@ -2023,7 +2031,7 @@ public function setSessionState(int $state): DataResponse { * Leave a room * * @param string $token Token of the room - * @return DataResponse, array{}> + * @return DataResponse * * 200: Successfully left the room */ @@ -2046,7 +2054,7 @@ public function leaveRoom(string $token): DataResponse { } catch (RoomNotFoundException|ParticipantNotFoundException) { } - return new DataResponse(); + return new DataResponse(null); } /** @@ -2054,7 +2062,7 @@ public function leaveRoom(string $token): DataResponse { * * @param string $token Token of the room * @param string $sessionId Federated session id to leave with - * @return DataResponse, array{}>|DataResponse + * @return DataResponse * * 200: Successfully left the room * 404: Room not found (non-federation request) @@ -2095,7 +2103,7 @@ public function leaveFederatedRoom(string $token, string $sessionId): DataRespon } catch (RoomNotFoundException|ParticipantNotFoundException) { } - return new DataResponse(); + return new DataResponse(null); } /** @@ -2103,7 +2111,7 @@ public function leaveFederatedRoom(string $token, string $sessionId): DataRespon * * @param int $attendeeId ID of the attendee * @psalm-param non-negative-int $attendeeId - * @return DataResponse, array{}> + * @return DataResponse * * 200: Attendee promoted to moderator successfully * 400: Promoting attendee to moderator is not possible @@ -2121,7 +2129,7 @@ public function promoteModerator(int $attendeeId): DataResponse { * * @param int $attendeeId ID of the attendee * @psalm-param non-negative-int $attendeeId - * @return DataResponse, array{}> + * @return DataResponse * * 200: Attendee demoted from moderator successfully * 400: Demoting attendee from moderator is not possible @@ -2141,35 +2149,35 @@ public function demoteModerator(int $attendeeId): DataResponse { * @param int $attendeeId * @psalm-param non-negative-int $attendeeId * @param bool $promote Shall the attendee be promoted or demoted - * @return DataResponse, array{}> + * @return DataResponse */ protected function changeParticipantType(int $attendeeId, bool $promote): DataResponse { try { $targetParticipant = $this->participantService->getParticipantByAttendeeId($this->room, $attendeeId); } catch (ParticipantNotFoundException $e) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(null, Http::STATUS_NOT_FOUND); } $attendee = $targetParticipant->getAttendee(); if ($attendee->getActorType() === Attendee::ACTOR_USERS && $attendee->getActorId() === MatterbridgeManager::BRIDGE_BOT_USERID) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(null, Http::STATUS_NOT_FOUND); } // Prevent users/moderators modifying themselves if ($attendee->getActorType() === $this->participant->getAttendee()->getActorType()) { if ($attendee->getActorId() === $this->participant->getAttendee()->getActorId()) { - return new DataResponse([], Http::STATUS_FORBIDDEN); + return new DataResponse(null, Http::STATUS_FORBIDDEN); } } elseif ($attendee->getActorType() === Attendee::ACTOR_GROUPS) { // Can not promote/demote groups - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(null, Http::STATUS_BAD_REQUEST); } if ($promote === $targetParticipant->hasModeratorPermissions()) { // Prevent concurrent changes - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(null, Http::STATUS_BAD_REQUEST); } if ($attendee->getParticipantType() === Participant::USER) { @@ -2181,12 +2189,12 @@ protected function changeParticipantType(int $attendeeId, bool $promote): DataRe } elseif ($attendee->getParticipantType() === Participant::GUEST_MODERATOR) { $newType = Participant::GUEST; } else { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse(null, Http::STATUS_BAD_REQUEST); } $this->participantService->updateParticipantType($this->room, $targetParticipant, $newType); - return new DataResponse(); + return new DataResponse(null); } /** @@ -2224,7 +2232,7 @@ public function setPermissions(string $mode, int $permissions): DataResponse { * @param 'set'|'remove'|'add' $method Method of updating permissions ('set', 'remove', 'add') * @param int<0, 255> $permissions New permissions * @psalm-param int-mask-of $permissions - * @return DataResponse, array{}> + * @return DataResponse, array{X-Nextcloud-Has-User-Statuses?: true}>|DataResponse * * 200: Permissions updated successfully * 400: Updating permissions is not possible @@ -2237,20 +2245,19 @@ public function setAttendeePermissions(int $attendeeId, string $method, int $per try { $targetParticipant = $this->participantService->getParticipantByAttendeeId($this->room, $attendeeId); } catch (ParticipantNotFoundException $e) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(['error' => 'participant'], Http::STATUS_NOT_FOUND); } try { - $result = $this->participantService->updatePermissions($this->room, $targetParticipant, $method, $permissions); - } catch (ForbiddenException $e) { - return new DataResponse([], Http::STATUS_FORBIDDEN); - } - - if (!$result) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); + $this->participantService->updatePermissions($this->room, $targetParticipant, $method, $permissions); + } catch (PermissionsException $e) { + if ($e->getReason() === PermissionsException::REASON_MODERATOR) { + return new DataResponse(['error' => $e->getReason()], Http::STATUS_FORBIDDEN); + } + return new DataResponse(['error' => $e->getReason()], Http::STATUS_BAD_REQUEST); } - return new DataResponse(); + return $this->formatParticipantList([$targetParticipant], true); } /** @@ -2260,7 +2267,7 @@ public function setAttendeePermissions(int $attendeeId, string $method, int $per * @psalm-param Attendee::PERMISSIONS_MODIFY_* $method * @param int<0, 255> $permissions New permissions * @psalm-param int-mask-of $permissions - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse * @deprecated Call permissions have been removed * * 200: Permissions updated successfully @@ -2269,11 +2276,7 @@ public function setAttendeePermissions(int $attendeeId, string $method, int $per #[PublicPage] #[RequireModeratorParticipant] public function setAllAttendeesPermissions(string $method, int $permissions): DataResponse { - if (!$this->roomService->setPermissions($this->room, 'call', $method, $permissions, false)) { - return new DataResponse([], Http::STATUS_BAD_REQUEST); - } - - return new DataResponse($this->formatRoom($this->room, $this->participant)); + return new DataResponse(null, Http::STATUS_BAD_REQUEST); } /** @@ -2331,7 +2334,7 @@ public function setLobby(int $state, ?int $timer = null): DataResponse { * * @param 0|1|2 $state New state * @psalm-param Webinary::SIP_* $state - * @return DataResponse|DataResponse, array{}>|DataResponse + * @return DataResponse|DataResponse|DataResponse * * 200: SIP enabled state updated successfully * 400: Updating SIP enabled state is not possible @@ -2344,15 +2347,15 @@ public function setLobby(int $state, ?int $timer = null): DataResponse { public function setSIPEnabled(int $state): DataResponse { $user = $this->userManager->get($this->userId); if (!$user instanceof IUser) { - return new DataResponse([], Http::STATUS_UNAUTHORIZED); + return new DataResponse(['error' => 'config'], Http::STATUS_UNAUTHORIZED); } if (!$this->talkConfig->canUserEnableSIP($user)) { - return new DataResponse([], Http::STATUS_FORBIDDEN); + return new DataResponse(['error' => 'config'], Http::STATUS_FORBIDDEN); } if (!$this->talkConfig->isSIPConfigured()) { - return new DataResponse([], Http::STATUS_PRECONDITION_FAILED); + return new DataResponse(['error' => 'config'], Http::STATUS_PRECONDITION_FAILED); } try { @@ -2370,7 +2373,7 @@ public function setSIPEnabled(int $state): DataResponse { * @param int $recordingConsent New consent setting for the conversation * (Only {@see RecordingService::CONSENT_REQUIRED_NO} and {@see RecordingService::CONSENT_REQUIRED_YES} are allowed here.) * @psalm-param RecordingService::CONSENT_REQUIRED_NO|RecordingService::CONSENT_REQUIRED_YES $recordingConsent - * @return DataResponse|DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse|DataResponse * * 200: Recording consent requirement set successfully * 400: Setting recording consent requirement is not possible @@ -2380,7 +2383,7 @@ public function setSIPEnabled(int $state): DataResponse { #[RequireLoggedInModeratorParticipant] public function setRecordingConsent(int $recordingConsent): DataResponse { if (!$this->talkConfig->isRecordingEnabled()) { - return new DataResponse([], Http::STATUS_PRECONDITION_FAILED); + return new DataResponse(['error' => 'config'], Http::STATUS_PRECONDITION_FAILED); } try { @@ -2397,7 +2400,7 @@ public function setRecordingConsent(int $recordingConsent): DataResponse { * * @param int|null $attendeeId ID of the attendee * @psalm-param non-negative-int|null $attendeeId - * @return DataResponse, array{}> + * @return DataResponse * * 200: Invitation resent successfully * 404: Attendee not found @@ -2413,7 +2416,7 @@ public function resendInvitations(?int $attendeeId): DataResponse { try { $participants[] = $this->participantService->getParticipantByAttendeeId($this->room, $attendeeId); } catch (ParticipantNotFoundException $e) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(null, Http::STATUS_NOT_FOUND); } } else { $participants = $this->participantService->getParticipantsByActorType($this->room, Attendee::ACTOR_EMAILS); @@ -2426,7 +2429,7 @@ public function resendInvitations(?int $attendeeId): DataResponse { $this->guestManager->sendEmailInvitation($this->room, $participant); } } - return new DataResponse(); + return new DataResponse(null); } /** @@ -2434,7 +2437,7 @@ public function resendInvitations(?int $attendeeId): DataResponse { * * @param int $seconds New time * @psalm-param non-negative-int $seconds - * @return DataResponse, array{}>|DataResponse + * @return DataResponse|DataResponse * * 200: Message expiration time updated successfully * 400: Updating message expiration time is not possible @@ -2448,7 +2451,7 @@ public function setMessageExpiration(int $seconds): DataResponse { return new DataResponse(['error' => $e->getReason()], Http::STATUS_BAD_REQUEST); } - return new DataResponse(); + return new DataResponse($this->formatRoom($this->room, $this->participant)); } /** @@ -2499,7 +2502,7 @@ public function importEmailsAsParticipants(bool $testRun = false): DataResponse * See "Capability handling in federated conversations" in https://github.com/nextcloud/spreed/issues/10680 * to learn which capabilities should be considered from the local server or from the remote server. * - * @return DataResponse, array{X-Nextcloud-Talk-Hash?: string, X-Nextcloud-Talk-Proxy-Hash?: string}> + * @return DataResponse * * 200: Get capabilities successfully */ @@ -2538,9 +2541,12 @@ public function getCapabilities(): DataResponse { if ($response->getHeaders()['X-Nextcloud-Talk-Hash']) { $headers['X-Nextcloud-Talk-Proxy-Hash'] = $response->getHeaders()['X-Nextcloud-Talk-Hash']; } + + /** @var TalkCapabilities|\stdClass $data */ + $data = !empty($data) ? $data : new \stdClass(); } else { $capabilities = $this->capabilities->getCapabilities(); - $data = $capabilities['spreed'] ?? []; + $data = $capabilities['spreed'] ?? new \stdClass(); $headers['X-Nextcloud-Talk-Hash'] = sha1(json_encode($capabilities)); } diff --git a/lib/Exceptions/FederationRestrictionException.php b/lib/Exceptions/FederationRestrictionException.php new file mode 100644 index 00000000000..8588f44db2e --- /dev/null +++ b/lib/Exceptions/FederationRestrictionException.php @@ -0,0 +1,33 @@ +reason); + } + + /** + * @return self::REASON_* + */ + public function getReason(): string { + return $this->reason; + } +} diff --git a/lib/Exceptions/ParticipantProperty/PermissionsException.php b/lib/Exceptions/ParticipantProperty/PermissionsException.php new file mode 100644 index 00000000000..8b00a691aa6 --- /dev/null +++ b/lib/Exceptions/ParticipantProperty/PermissionsException.php @@ -0,0 +1,33 @@ +reason; + } +} diff --git a/lib/Federation/FederationManager.php b/lib/Federation/FederationManager.php index 685dcfacea1..c5d06af5755 100644 --- a/lib/Federation/FederationManager.php +++ b/lib/Federation/FederationManager.php @@ -10,6 +10,7 @@ use OCA\Talk\AppInfo\Application; use OCA\Talk\Exceptions\CannotReachRemoteException; +use OCA\Talk\Exceptions\FederationRestrictionException; use OCA\Talk\Exceptions\ParticipantNotFoundException; use OCA\Talk\Exceptions\RoomNotFoundException; use OCA\Talk\Exceptions\UnauthorizedException; @@ -64,7 +65,7 @@ public function __construct( /** * Check if $sharedBy is allowed to invite $shareWith * - * @throws \InvalidArgumentException + * @throws FederationRestrictionException */ public function isAllowedToInvite( IUser $user, diff --git a/lib/Federation/Proxy/TalkV1/Controller/ChatController.php b/lib/Federation/Proxy/TalkV1/Controller/ChatController.php index b1c3dfb245f..ec9fcec4921 100644 --- a/lib/Federation/Proxy/TalkV1/Controller/ChatController.php +++ b/lib/Federation/Proxy/TalkV1/Controller/ChatController.php @@ -47,7 +47,7 @@ public function __construct( /** * @see \OCA\Talk\Controller\ChatController::sendMessage() * - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse * @throws CannotReachRemoteException * * 201: Message sent successfully @@ -80,7 +80,9 @@ public function sendMessage(Room $room, Participant $participant, string $messag ], true)) { $statusCode = $this->proxy->logUnexpectedStatusCode(__METHOD__, $statusCode); } - return new DataResponse([], $statusCode); + /** @var array{error: string} $data */ + $data = $this->proxy->getOCSData($proxy, [Http::STATUS_CREATED]); + return new DataResponse($data, $statusCode); } /** @var ?TalkChatMessageWithParent $data */ @@ -104,7 +106,7 @@ public function sendMessage(Room $room, Participant $participant, string $messag } /** - * @return DataResponse|DataResponse, array> + * @return DataResponse, array{'X-Chat-Last-Common-Read'?: numeric-string, X-Chat-Last-Given?: numeric-string}>|DataResponse * @throws CannotReachRemoteException * * 200: Messages returned @@ -180,7 +182,7 @@ public function receiveMessages( $this->proxyCacheMessages->set($cacheKey, $lastKnownMessageId, 300); } } - return new DataResponse([], Http::STATUS_NOT_MODIFIED); + return new DataResponse(null, Http::STATUS_NOT_MODIFIED); } $headers = []; @@ -197,16 +199,16 @@ public function receiveMessages( } } - /** @var TalkChatMessageWithParent[] $data */ + /** @var list $data */ $data = $this->proxy->getOCSData($proxy); - /** @var TalkChatMessageWithParent[] $data */ + /** @var list $data */ $data = $this->userConverter->convertMessages($room, $data); return new DataResponse($data, Http::STATUS_OK, $headers); } /** - * @return DataResponse|DataResponse, array> + * @return DataResponse, array{'X-Chat-Last-Common-Read'?: numeric-string, X-Chat-Last-Given?: numeric-string}>|DataResponse * @throws CannotReachRemoteException * * 200: Message context returned @@ -229,7 +231,7 @@ public function getMessageContext(Room $room, Participant $participant, int $mes } if ($proxy->getStatusCode() === Http::STATUS_NOT_MODIFIED) { - return new DataResponse([], Http::STATUS_NOT_MODIFIED); + return new DataResponse(null, Http::STATUS_NOT_MODIFIED); } $headers = []; @@ -240,16 +242,16 @@ public function getMessageContext(Room $room, Participant $participant, int $mes $headers['X-Chat-Last-Given'] = (string)(int)$proxy->getHeader('X-Chat-Last-Given'); } - /** @var TalkChatMessageWithParent[] $data */ + /** @var list $data */ $data = $this->proxy->getOCSData($proxy); - /** @var TalkChatMessageWithParent[] $data */ + /** @var list $data */ $data = $this->userConverter->convertMessages($room, $data); return new DataResponse($data, Http::STATUS_OK, $headers); } /** - * @return DataResponse|DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse|DataResponse * @throws CannotReachRemoteException * * 200: Message edited successfully @@ -308,7 +310,7 @@ public function editMessage(Room $room, Participant $participant, int $messageId } /** - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse * @throws CannotReachRemoteException * * 200: Message deleted successfully @@ -446,7 +448,7 @@ public function markUnread(Room $room, Participant $participant, string $respons /** * @see \OCA\Talk\Controller\ChatController::mentions() * - * @return DataResponse + * @return DataResponse, array{}> * @throws CannotReachRemoteException * * 200: List of mention suggestions returned @@ -463,8 +465,9 @@ public function mentions(Room $room, Participant $participant, string $search, i ], ); - /** @var TalkChatMentionSuggestion[] $data */ + /** @var list $data */ $data = $this->proxy->getOCSData($proxy); + /** @var list $data */ $data = $this->userConverter->convertAttendees($room, $data, 'source', 'id', 'label'); // FIXME post-load status information diff --git a/lib/Federation/Proxy/TalkV1/Controller/PollController.php b/lib/Federation/Proxy/TalkV1/Controller/PollController.php index 7708b020962..8601806ecfa 100644 --- a/lib/Federation/Proxy/TalkV1/Controller/PollController.php +++ b/lib/Federation/Proxy/TalkV1/Controller/PollController.php @@ -62,7 +62,7 @@ public function getDraftsForRoom(Room $room, Participant $participant): DataResp } /** - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse * @throws CannotReachRemoteException * * 200: Poll returned @@ -78,7 +78,9 @@ public function showPoll(Room $room, Participant $participant, int $pollId): Dat ); if ($proxy->getStatusCode() === Http::STATUS_NOT_FOUND) { - return new DataResponse([], Http::STATUS_NOT_FOUND); + /** @var array{error?: string} $data */ + $data = $this->proxy->getOCSData($proxy); + return new DataResponse(['error' => $data['error'] ?? 'poll'], Http::STATUS_NOT_FOUND); } /** @var TalkPoll $data */ @@ -89,7 +91,8 @@ public function showPoll(Room $room, Participant $participant, int $pollId): Dat } /** - * @return DataResponse|DataResponse, array{}> + * @param list $optionIds + * @return DataResponse|DataResponse * @throws CannotReachRemoteException * * 200: Voted successfully @@ -114,7 +117,9 @@ public function votePoll(Room $room, Participant $participant, int $pollId, arra ], true)) { $statusCode = $this->proxy->logUnexpectedStatusCode(__METHOD__, $statusCode); } - return new DataResponse([], $statusCode); + /** @var array{error?: string} $data */ + $data = $this->proxy->getOCSData($proxy); + return new DataResponse(['error' => $data['error'] ?? 'poll'], $statusCode); } /** @var TalkPoll $data */ @@ -166,7 +171,7 @@ public function createPoll(Room $room, Participant $participant, string $questio } /** - * @return DataResponse|DataResponse, array{}> + * @return DataResponse|DataResponse|DataResponse * @throws CannotReachRemoteException * * 200: Poll closed successfully @@ -192,7 +197,9 @@ public function closePoll(Room $room, Participant $participant, int $pollId): Da ], true)) { $statusCode = $this->proxy->logUnexpectedStatusCode(__METHOD__, $statusCode); } - return new DataResponse([], $statusCode); + /** @var array{error?: string} $data */ + $data = $this->proxy->getOCSData($proxy); + return new DataResponse(['error' => $data['error'] ?? 'poll'], $statusCode); } /** @var TalkPoll $data */ diff --git a/lib/Federation/Proxy/TalkV1/Controller/ReactionController.php b/lib/Federation/Proxy/TalkV1/Controller/ReactionController.php index 2812a7591e1..4cb454a7474 100644 --- a/lib/Federation/Proxy/TalkV1/Controller/ReactionController.php +++ b/lib/Federation/Proxy/TalkV1/Controller/ReactionController.php @@ -32,7 +32,7 @@ public function __construct( * @param int $messageId ID of the message * @psalm-param non-negative-int $messageId * @param string $reaction Emoji to add - * @return DataResponse|\stdClass, array{}>|DataResponse, array{}> + * @return DataResponse>|\stdClass, array{}>|DataResponse * * 200: Reaction already existed * 201: Reaction added successfully @@ -59,10 +59,10 @@ public function react(Room $room, Participant $participant, int $messageId, stri ], true)) { $statusCode = $this->proxy->logUnexpectedStatusCode(__METHOD__, $statusCode); } - return new DataResponse([], $statusCode); + return new DataResponse(null, $statusCode); } - /** @var array $data */ + /** @var array> $data */ $data = $this->proxy->getOCSData($proxy, [Http::STATUS_CREATED, Http::STATUS_OK]); $data = $this->userConverter->convertReactionsList($room, $data); @@ -75,7 +75,7 @@ public function react(Room $room, Participant $participant, int $messageId, stri * @param int $messageId ID of the message * @psalm-param non-negative-int $messageId * @param string $reaction Emoji to remove - * @return DataResponse|\stdClass, array{}>|DataResponse, array{}> + * @return DataResponse>|\stdClass, array{}>|DataResponse * * 200: Reaction deleted successfully * 400: Deleting reaction is not possible @@ -101,10 +101,10 @@ public function delete(Room $room, Participant $participant, int $messageId, str ], true)) { $statusCode = $this->proxy->logUnexpectedStatusCode(__METHOD__, $statusCode); } - return new DataResponse([], $statusCode); + return new DataResponse(null, $statusCode); } - /** @var array $data */ + /** @var array> $data */ $data = $this->proxy->getOCSData($proxy); $data = $this->userConverter->convertReactionsList($room, $data); @@ -118,7 +118,7 @@ public function delete(Room $room, Participant $participant, int $messageId, str * @param int $messageId ID of the message * @psalm-param non-negative-int $messageId * @param string|null $reaction Emoji to filter - * @return DataResponse|\stdClass, array{}>|DataResponse, array{}> + * @return DataResponse>|\stdClass, array{}>|DataResponse * * 200: Reactions returned * 404: Message or reaction not found @@ -140,10 +140,10 @@ public function getReactions(Room $room, Participant $participant, int $messageI if ($statusCode !== Http::STATUS_NOT_FOUND) { $this->proxy->logUnexpectedStatusCode(__METHOD__, $statusCode); } - return new DataResponse([], Http::STATUS_NOT_FOUND); + return new DataResponse(null, Http::STATUS_NOT_FOUND); } - /** @var array $data */ + /** @var array> $data */ $data = $this->proxy->getOCSData($proxy); $data = $this->userConverter->convertReactionsList($room, $data); @@ -151,8 +151,8 @@ public function getReactions(Room $room, Participant $participant, int $messageI } /** - * @param array $reactions - * @return array|\stdClass + * @param array> $reactions + * @return array>|\stdClass */ protected function formatReactions(string $format, array $reactions): array|\stdClass { if ($format === 'json' && empty($reactions)) { diff --git a/lib/Federation/Proxy/TalkV1/Controller/RoomController.php b/lib/Federation/Proxy/TalkV1/Controller/RoomController.php index e7e75f7f7f2..4ef045db9ed 100644 --- a/lib/Federation/Proxy/TalkV1/Controller/RoomController.php +++ b/lib/Federation/Proxy/TalkV1/Controller/RoomController.php @@ -33,7 +33,7 @@ public function __construct( /** * @see \OCA\Talk\Controller\RoomController::getParticipants() * - * @return DataResponse + * @return DataResponse, array{X-Nextcloud-Has-User-Statuses?: bool}> * @throws CannotReachRemoteException * * 200: Participants returned @@ -46,10 +46,10 @@ public function getParticipants(Room $room, Participant $participant): DataRespo $room->getRemoteServer() . '/ocs/v2.php/apps/spreed/api/v4/room/' . $room->getRemoteToken() . '/participants', ); - /** @var TalkParticipant[] $data */ + /** @var list $data */ $data = $this->proxy->getOCSData($proxy); - /** @var TalkParticipant[] $data */ + /** @var list $data */ $data = $this->userConverter->convertAttendees($room, $data, 'actorType', 'actorId', 'displayName'); $headers = []; if ($proxy->getHeader('X-Nextcloud-Has-User-Statuses')) { @@ -157,4 +157,13 @@ public function getCapabilities(Room $room, Participant $participant): DataRespo return new DataResponse($data, Http::STATUS_OK, $headers); } + + /** + * @return array|\stdClass + */ + protected function emptyArray(): array|\stdClass { + // Cheating here to make sure the array is always a + // JSON object on the API, even when there is no entry at all. + return new \stdClass(); + } } diff --git a/lib/Federation/RestrictionValidator.php b/lib/Federation/RestrictionValidator.php index 506ff5cd1e2..ca9c0bbe20c 100644 --- a/lib/Federation/RestrictionValidator.php +++ b/lib/Federation/RestrictionValidator.php @@ -11,6 +11,7 @@ use OCA\FederatedFileSharing\AddressHandler; use OCA\Federation\TrustedServers; use OCA\Talk\Config; +use OCA\Talk\Exceptions\FederationRestrictionException; use OCP\App\IAppManager; use OCP\AppFramework\Services\IAppConfig; use OCP\Federation\ICloudId; @@ -31,7 +32,7 @@ public function __construct( /** * Check if $sharedBy is allowed to invite $shareWith * - * @throws \InvalidArgumentException + * @throws FederationRestrictionException */ public function isAllowedToInvite( IUser $user, @@ -39,23 +40,23 @@ public function isAllowedToInvite( ): void { if (!($cloudIdToInvite->getUser() && $cloudIdToInvite->getRemote())) { $this->logger->debug('Could not share conversation as the recipient is invalid: ' . $cloudIdToInvite->getId()); - throw new \InvalidArgumentException('cloudId'); + throw new FederationRestrictionException(FederationRestrictionException::REASON_CLOUD_ID); } if (!$this->appConfig->getAppValueBool('federation_outgoing_enabled', true)) { $this->logger->debug('Could not share conversation as outgoing federation is disabled'); - throw new \InvalidArgumentException('outgoing'); + throw new FederationRestrictionException(FederationRestrictionException::REASON_OUTGOING); } if (!$this->talkConfig->isFederationEnabledForUserId($user)) { $this->logger->debug('Talk federation not allowed for user ' . $user->getUID()); - throw new \InvalidArgumentException('federation'); + throw new FederationRestrictionException(FederationRestrictionException::REASON_FEDERATION); } if ($this->appConfig->getAppValueBool('federation_only_trusted_servers')) { if (!$this->appManager->isEnabledForUser('federation')) { $this->logger->error('Federation is limited to trusted servers but the "federation" app is disabled'); - throw new \InvalidArgumentException('trusted_servers'); + throw new FederationRestrictionException(FederationRestrictionException::REASON_TRUSTED_SERVERS); } $trustedServers = Server::get(TrustedServers::class); @@ -65,7 +66,7 @@ public function isAllowedToInvite( 'Tried to send Talk federation invite to untrusted server {serverUrl}', ['serverUrl' => $serverUrl] ); - throw new \InvalidArgumentException('trusted_servers'); + throw new FederationRestrictionException(FederationRestrictionException::REASON_TRUSTED_SERVERS); } } } diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php index ca5b7a827ce..60da06cf6cb 100644 --- a/lib/ResponseDefinitions.php +++ b/lib/ResponseDefinitions.php @@ -213,9 +213,9 @@ * } * * @psalm-type TalkPoll = TalkPollDraft&array{ - * details?: TalkPollVote[], + * details?: list, * numVoters?: int<0, max>, - * votedSelf?: int[], + * votedSelf?: list, * votes?: array, * } * diff --git a/lib/Service/ParticipantService.php b/lib/Service/ParticipantService.php index 356c8c0151b..7609404a71b 100644 --- a/lib/Service/ParticipantService.php +++ b/lib/Service/ParticipantService.php @@ -38,9 +38,9 @@ use OCA\Talk\Events\UserJoinedRoomEvent; use OCA\Talk\Exceptions\CannotReachRemoteException; use OCA\Talk\Exceptions\DialOutFailedException; -use OCA\Talk\Exceptions\ForbiddenException; use OCA\Talk\Exceptions\InvalidPasswordException; use OCA\Talk\Exceptions\ParticipantNotFoundException; +use OCA\Talk\Exceptions\ParticipantProperty\PermissionsException; use OCA\Talk\Exceptions\UnauthorizedException; use OCA\Talk\Federation\BackendNotifier; use OCA\Talk\Federation\FederationManager; @@ -183,23 +183,26 @@ public function updateParticipantType(Room $room, Participant $participant, int } /** - * @throws Exception - * @throws ForbiddenException + * @throws PermissionsException */ - public function updatePermissions(Room $room, Participant $participant, string $method, int $newPermissions): bool { + public function updatePermissions(Room $room, Participant $participant, string $method, int $newPermissions): void { if ($room->getType() === Room::TYPE_ONE_TO_ONE || $room->getType() === Room::TYPE_ONE_TO_ONE_FORMER) { - return false; + throw new PermissionsException(PermissionsException::REASON_ROOM_TYPE); } if ($participant->hasModeratorPermissions()) { - throw new ForbiddenException(); + throw new PermissionsException(PermissionsException::REASON_MODERATOR); } $attendee = $participant->getAttendee(); if ($attendee->getActorType() === Attendee::ACTOR_GROUPS || $attendee->getActorType() === Attendee::ACTOR_CIRCLES) { // Can not set publishing permissions for those actor types - return false; + throw new PermissionsException(PermissionsException::REASON_TYPE); + } + + if ($newPermissions < Attendee::PERMISSIONS_DEFAULT || $newPermissions > Attendee::PERMISSIONS_MAX_CUSTOM) { + throw new PermissionsException(PermissionsException::REASON_VALUE); } $oldPermissions = $participant->getPermissions(); @@ -213,7 +216,7 @@ public function updatePermissions(Room $room, Participant $participant, string $ } elseif ($method === Attendee::PERMISSIONS_MODIFY_REMOVE) { $newPermissions = $oldPermissions & ~$newPermissions; } else { - return false; + throw new PermissionsException(PermissionsException::REASON_METHOD); } $event = new BeforeParticipantModifiedEvent($room, $participant, AParticipantModifiedEvent::PROPERTY_PERMISSIONS, $newPermissions, $oldPermissions); @@ -228,8 +231,6 @@ public function updatePermissions(Room $room, Participant $participant, string $ $event = new ParticipantModifiedEvent($room, $participant, AParticipantModifiedEvent::PROPERTY_PERMISSIONS, $newPermissions, $oldPermissions); $this->dispatcher->dispatchTyped($event); - - return true; } public function updateAllPermissions(Room $room, string $method, int $newState): void { @@ -271,7 +272,7 @@ public function updateNotificationLevel(Participant $participant, int $level): v Participant::NOTIFY_MENTION, Participant::NOTIFY_NEVER ], true)) { - throw new \InvalidArgumentException('Invalid notification level'); + throw new \InvalidArgumentException('level'); } $attendee = $participant->getAttendee(); @@ -283,13 +284,14 @@ public function updateNotificationLevel(Participant $participant, int $level): v /** * @param Participant $participant * @param int $level + * @throws \InvalidArgumentException */ public function updateNotificationCalls(Participant $participant, int $level): void { if (!\in_array($level, [ Participant::NOTIFY_CALLS_OFF, Participant::NOTIFY_CALLS_ON, ], true)) { - throw new \InvalidArgumentException('Invalid notification level'); + throw new \InvalidArgumentException('level'); } $attendee = $participant->getAttendee(); diff --git a/lib/Service/PollService.php b/lib/Service/PollService.php index 3048a2ed9fa..0deeab56217 100644 --- a/lib/Service/PollService.php +++ b/lib/Service/PollService.php @@ -17,7 +17,6 @@ use OCA\Talk\Participant; use OCP\AppFramework\Db\DoesNotExistException; use OCP\Comments\ICommentsManager; -use OCP\DB\Exception; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; @@ -119,7 +118,6 @@ public function getPoll(int $roomId, int $pollId): Poll { * @param Participant $participant * @param Poll $poll * @throws WrongPermissionsException - * @throws Exception */ public function updatePoll(Participant $participant, Poll $poll): void { if (!$participant->hasModeratorPermissions() diff --git a/lib/Service/RoomService.php b/lib/Service/RoomService.php index 567aa82d3ee..9d0632c6902 100644 --- a/lib/Service/RoomService.php +++ b/lib/Service/RoomService.php @@ -93,7 +93,7 @@ public function __construct( */ public function createOneToOneConversation(IUser $actor, IUser $targetUser): Room { if ($actor->getUID() === $targetUser->getUID()) { - throw new InvalidArgumentException('invalid_invitee'); + throw new InvalidArgumentException('invite'); } try { diff --git a/openapi-administration.json b/openapi-administration.json index 2fa3374a685..82336b43982 100644 --- a/openapi-administration.json +++ b/openapi-administration.json @@ -340,23 +340,12 @@ } }, "PublicCapabilities": { - "oneOf": [ - { - "type": "object", - "required": [ - "spreed" - ], - "properties": { - "spreed": { - "$ref": "#/components/schemas/Capabilities" - } - } - }, - { - "type": "array", - "maxItems": 0 + "type": "object", + "properties": { + "spreed": { + "$ref": "#/components/schemas/Capabilities" } - ] + } } } }, diff --git a/openapi-backend-recording.json b/openapi-backend-recording.json index 25359a023df..d89ba139d1c 100644 --- a/openapi-backend-recording.json +++ b/openapi-backend-recording.json @@ -273,23 +273,12 @@ } }, "PublicCapabilities": { - "oneOf": [ - { - "type": "object", - "required": [ - "spreed" - ], - "properties": { - "spreed": { - "$ref": "#/components/schemas/Capabilities" - } - } - }, - { - "type": "array", - "maxItems": 0 + "type": "object", + "properties": { + "spreed": { + "$ref": "#/components/schemas/Capabilities" } - ] + } } } }, diff --git a/openapi-backend-signaling.json b/openapi-backend-signaling.json index 9b2c9fc6b64..80d66c8f466 100644 --- a/openapi-backend-signaling.json +++ b/openapi-backend-signaling.json @@ -273,23 +273,12 @@ } }, "PublicCapabilities": { - "oneOf": [ - { - "type": "object", - "required": [ - "spreed" - ], - "properties": { - "spreed": { - "$ref": "#/components/schemas/Capabilities" - } - } - }, - { - "type": "array", - "maxItems": 0 + "type": "object", + "properties": { + "spreed": { + "$ref": "#/components/schemas/Capabilities" } - ] + } } } }, diff --git a/openapi-backend-sipbridge.json b/openapi-backend-sipbridge.json index 570e6a185dc..317475a72b4 100644 --- a/openapi-backend-sipbridge.json +++ b/openapi-backend-sipbridge.json @@ -395,23 +395,12 @@ } }, "PublicCapabilities": { - "oneOf": [ - { - "type": "object", - "required": [ - "spreed" - ], - "properties": { - "spreed": { - "$ref": "#/components/schemas/Capabilities" - } - } - }, - { - "type": "array", - "maxItems": 0 + "type": "object", + "properties": { + "spreed": { + "$ref": "#/components/schemas/Capabilities" } - ] + } }, "RichObjectParameter": { "type": "object", @@ -1067,7 +1056,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -1095,7 +1086,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -1123,7 +1116,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -1253,7 +1248,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -1281,7 +1278,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -1309,7 +1308,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -1456,7 +1457,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -1484,7 +1487,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -1512,7 +1517,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -1540,7 +1547,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -1651,7 +1660,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -1679,7 +1690,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -1777,7 +1790,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -1805,7 +1820,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -1833,7 +1850,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -1861,7 +1880,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -1889,7 +1910,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } diff --git a/openapi-bots.json b/openapi-bots.json index 0749a6e6f11..2989979159d 100644 --- a/openapi-bots.json +++ b/openapi-bots.json @@ -273,23 +273,12 @@ } }, "PublicCapabilities": { - "oneOf": [ - { - "type": "object", - "required": [ - "spreed" - ], - "properties": { - "spreed": { - "$ref": "#/components/schemas/Capabilities" - } - } - }, - { - "type": "array", - "maxItems": 0 + "type": "object", + "properties": { + "spreed": { + "$ref": "#/components/schemas/Capabilities" } - ] + } } } }, diff --git a/openapi-federation.json b/openapi-federation.json index 24d43cfc44a..a4b1c7f5fc2 100644 --- a/openapi-federation.json +++ b/openapi-federation.json @@ -449,23 +449,12 @@ } }, "PublicCapabilities": { - "oneOf": [ - { - "type": "object", - "required": [ - "spreed" - ], - "properties": { - "spreed": { - "$ref": "#/components/schemas/Capabilities" - } - } - }, - { - "type": "array", - "maxItems": 0 + "type": "object", + "properties": { + "spreed": { + "$ref": "#/components/schemas/Capabilities" } - ] + } }, "RichObjectParameter": { "type": "object", @@ -1866,7 +1855,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } diff --git a/openapi-full.json b/openapi-full.json index 985cdd01c2f..f78c358fc77 100644 --- a/openapi-full.json +++ b/openapi-full.json @@ -1002,23 +1002,12 @@ } }, "PublicCapabilities": { - "oneOf": [ - { - "type": "object", - "required": [ - "spreed" - ], - "properties": { - "spreed": { - "$ref": "#/components/schemas/Capabilities" - } - } - }, - { - "type": "array", - "maxItems": 0 + "type": "object", + "properties": { + "spreed": { + "$ref": "#/components/schemas/Capabilities" } - ] + } }, "Reaction": { "type": "object", @@ -5853,7 +5842,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -5881,7 +5880,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -5909,7 +5918,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -5937,7 +5956,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -6033,7 +6062,7 @@ } }, "202": { - "description": "History cleared successfully, but Matterbridge is configured, so the information can be replicated elsewhere", + "description": "History cleared successfully, but Federation or Matterbridge is configured, so the information can be replicated elsewhere", "headers": { "X-Chat-Last-Common-Read": { "schema": { @@ -6089,7 +6118,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -6428,7 +6459,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -6456,7 +6497,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -6484,7 +6535,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -6512,7 +6573,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -6733,7 +6804,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -6761,7 +6842,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -6789,7 +6880,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -6817,7 +6918,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -7821,7 +7932,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -7849,7 +7970,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -7877,7 +8008,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -7996,8 +8137,8 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "type": "array", - "items": { + "type": "object", + "additionalProperties": { "$ref": "#/components/schemas/ChatMessage" } } @@ -9468,7 +9609,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -9609,7 +9760,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -9637,7 +9798,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -9757,7 +9928,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -9785,7 +9958,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -9813,8 +9996,18 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} - } + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } + } } } } @@ -9841,35 +10034,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} - } - } - } - } - } - } - }, - "500": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -10007,7 +10182,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -10190,7 +10367,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -10218,7 +10397,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -10353,7 +10534,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -10381,7 +10564,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -10516,7 +10701,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -11365,9 +11552,21 @@ }, "data": { "type": "object", + "required": [ + "error" + ], "properties": { "error": { - "type": "string" + "type": "string", + "enum": [ + "invite", + "mode", + "object", + "password", + "permissions", + "room", + "type" + ] }, "message": { "type": "string" @@ -11401,7 +11600,29 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "invite", + "mode", + "object", + "password", + "permissions", + "room", + "type" + ] + }, + "message": { + "type": "string" + } + } + } } } } @@ -11429,7 +11650,29 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "invite", + "mode", + "object", + "password", + "permissions", + "room", + "type" + ] + }, + "message": { + "type": "string" + } + } + } } } } @@ -11968,7 +12211,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -12012,8 +12257,7 @@ ] }, "message": { - "type": "string", - "nullable": true + "type": "string" } } } @@ -12094,7 +12338,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -12237,7 +12483,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -12383,7 +12631,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -12530,7 +12780,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -12673,7 +12925,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -13016,7 +13270,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -13127,24 +13383,13 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "oneOf": [ - { - "type": "object", - "required": [ - "type" - ], - "properties": { - "type": { - "type": "integer", - "format": "int64" - } - } - }, - { - "type": "array", - "maxItems": 0 + "type": "object", + "properties": { + "type": { + "type": "integer", + "format": "int64" } - ] + } } } } @@ -13153,8 +13398,8 @@ } } }, - "404": { - "description": "User, group or other target to invite was not found", + "400": { + "description": "Adding participant is not possible, e.g. when the user is banned (check error attribute of response for detail key)", "content": { "application/json": { "schema": { @@ -13173,7 +13418,30 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "ban", + "cloud-id", + "federation", + "moderator", + "new-participant", + "outgoing", + "reach-remote", + "room-type", + "sip", + "source", + "trusted-servers" + ] + } + } + } } } } @@ -13181,8 +13449,8 @@ } } }, - "501": { - "description": "SIP dial-out is not configured", + "404": { + "description": "User, group or other target to invite was not found", "content": { "application/json": { "schema": { @@ -13201,7 +13469,30 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "ban", + "cloud-id", + "federation", + "moderator", + "new-participant", + "outgoing", + "reach-remote", + "room-type", + "sip", + "source", + "trusted-servers" + ] + } + } + } } } } @@ -13209,8 +13500,8 @@ } } }, - "400": { - "description": "Adding participant is not possible, e.g. when the user is banned (check error attribute of response for detail key)", + "501": { + "description": "SIP dial-out is not configured", "content": { "application/json": { "schema": { @@ -13231,9 +13522,25 @@ }, "data": { "type": "object", + "required": [ + "error" + ], "properties": { "error": { - "type": "string" + "type": "string", + "enum": [ + "ban", + "cloud-id", + "federation", + "moderator", + "new-participant", + "outgoing", + "reach-remote", + "room-type", + "sip", + "source", + "trusted-servers" + ] } } } @@ -13408,7 +13715,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -13488,7 +13797,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -13516,7 +13827,21 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "last-moderator", + "participant" + ] + } + } + } } } } @@ -13544,7 +13869,21 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "last-moderator", + "participant" + ] + } + } + } } } } @@ -13636,7 +13975,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -13664,7 +14005,23 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "last-moderator", + "owner", + "participant", + "room-type" + ] + } + } + } } } } @@ -13692,7 +14049,23 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "last-moderator", + "owner", + "participant", + "room-type" + ] + } + } + } } } } @@ -13720,7 +14093,23 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "last-moderator", + "owner", + "participant", + "room-type" + ] + } + } + } } } } @@ -13822,6 +14211,16 @@ "responses": { "200": { "description": "Permissions updated successfully", + "headers": { + "X-Nextcloud-Has-User-Statuses": { + "schema": { + "type": "boolean", + "enum": [ + true + ] + } + } + }, "content": { "application/json": { "schema": { @@ -13840,7 +14239,12 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Participant" + } + } } } } @@ -13868,7 +14272,25 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "participant", + "method", + "moderator", + "room-type", + "type", + "value" + ] + } + } + } } } } @@ -13896,7 +14318,25 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "participant", + "method", + "moderator", + "room-type", + "type", + "value" + ] + } + } + } } } } @@ -13924,7 +14364,25 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "participant", + "method", + "moderator", + "room-type", + "type", + "value" + ] + } + } + } } } } @@ -14068,7 +14526,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14251,7 +14711,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14379,7 +14841,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14478,7 +14942,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14506,7 +14972,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14641,7 +15109,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14669,7 +15139,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14771,7 +15243,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14799,7 +15273,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14827,7 +15303,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14855,7 +15333,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14945,7 +15425,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14973,7 +15455,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -15001,7 +15485,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -15029,7 +15515,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -15109,7 +15597,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -15187,7 +15677,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -15287,7 +15779,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -15315,7 +15809,20 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "level" + ] + } + } + } } } } @@ -15415,7 +15922,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -15443,7 +15952,20 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "level" + ] + } + } + } } } } @@ -15731,7 +16253,20 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "config" + ] + } + } + } } } } @@ -15759,7 +16294,20 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "config" + ] + } + } + } } } } @@ -15787,7 +16335,20 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "config" + ] + } + } + } } } } @@ -16004,7 +16565,20 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "config" + ] + } + } + } } } } @@ -16106,7 +16680,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -16249,8 +16825,8 @@ "$ref": "#/components/schemas/Capabilities" }, { - "type": "array", - "maxItems": 0 + "type": "object", + "additionalProperties": true } ] } @@ -18659,7 +19235,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -21052,7 +21630,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -21080,7 +21660,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -21108,7 +21690,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -21238,7 +21822,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -21266,7 +21852,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -21294,7 +21882,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -21441,7 +22031,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -21469,7 +22061,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -21497,7 +22091,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -21525,7 +22121,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -21636,7 +22234,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -21664,7 +22264,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -21762,7 +22364,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -21790,7 +22394,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -21818,7 +22424,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -21846,7 +22454,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -21874,7 +22484,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } diff --git a/openapi.json b/openapi.json index 59fd16106e1..789b60e815c 100644 --- a/openapi.json +++ b/openapi.json @@ -889,23 +889,12 @@ } }, "PublicCapabilities": { - "oneOf": [ - { - "type": "object", - "required": [ - "spreed" - ], - "properties": { - "spreed": { - "$ref": "#/components/schemas/Capabilities" - } - } - }, - { - "type": "array", - "maxItems": 0 + "type": "object", + "properties": { + "spreed": { + "$ref": "#/components/schemas/Capabilities" } - ] + } }, "Reaction": { "type": "object", @@ -5740,7 +5729,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -5768,7 +5767,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -5796,7 +5805,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -5824,7 +5843,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -5920,7 +5949,7 @@ } }, "202": { - "description": "History cleared successfully, but Matterbridge is configured, so the information can be replicated elsewhere", + "description": "History cleared successfully, but Federation or Matterbridge is configured, so the information can be replicated elsewhere", "headers": { "X-Chat-Last-Common-Read": { "schema": { @@ -5976,7 +6005,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -6315,7 +6346,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -6343,7 +6384,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -6371,7 +6422,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -6399,7 +6460,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -6620,7 +6691,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -6648,7 +6729,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -6676,7 +6767,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -6704,7 +6805,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -7708,7 +7819,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -7736,7 +7857,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -7764,7 +7895,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -7883,8 +8024,8 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "type": "array", - "items": { + "type": "object", + "additionalProperties": { "$ref": "#/components/schemas/ChatMessage" } } @@ -9355,7 +9496,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -9496,7 +9647,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -9524,7 +9685,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -9644,7 +9815,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -9672,7 +9845,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -9700,8 +9883,18 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} - } + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } + } } } } @@ -9728,35 +9921,17 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} - } - } - } - } - } - } - }, - "500": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } } } } @@ -9894,7 +10069,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -10077,7 +10254,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -10105,7 +10284,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -10240,7 +10421,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -10268,7 +10451,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -10403,7 +10588,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -11252,9 +11439,21 @@ }, "data": { "type": "object", + "required": [ + "error" + ], "properties": { "error": { - "type": "string" + "type": "string", + "enum": [ + "invite", + "mode", + "object", + "password", + "permissions", + "room", + "type" + ] }, "message": { "type": "string" @@ -11288,7 +11487,29 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "invite", + "mode", + "object", + "password", + "permissions", + "room", + "type" + ] + }, + "message": { + "type": "string" + } + } + } } } } @@ -11316,7 +11537,29 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "invite", + "mode", + "object", + "password", + "permissions", + "room", + "type" + ] + }, + "message": { + "type": "string" + } + } + } } } } @@ -11731,7 +11974,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -11852,7 +12097,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -11880,7 +12127,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -12102,7 +12351,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -12146,8 +12397,7 @@ ] }, "message": { - "type": "string", - "nullable": true + "type": "string" } } } @@ -12228,7 +12478,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -12371,7 +12623,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -12517,7 +12771,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -12664,7 +12920,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -12807,7 +13065,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -13150,7 +13410,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -13261,24 +13523,13 @@ "$ref": "#/components/schemas/OCSMeta" }, "data": { - "oneOf": [ - { - "type": "object", - "required": [ - "type" - ], - "properties": { - "type": { - "type": "integer", - "format": "int64" - } - } - }, - { - "type": "array", - "maxItems": 0 + "type": "object", + "properties": { + "type": { + "type": "integer", + "format": "int64" } - ] + } } } } @@ -13287,8 +13538,8 @@ } } }, - "404": { - "description": "User, group or other target to invite was not found", + "400": { + "description": "Adding participant is not possible, e.g. when the user is banned (check error attribute of response for detail key)", "content": { "application/json": { "schema": { @@ -13307,7 +13558,30 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "ban", + "cloud-id", + "federation", + "moderator", + "new-participant", + "outgoing", + "reach-remote", + "room-type", + "sip", + "source", + "trusted-servers" + ] + } + } + } } } } @@ -13315,8 +13589,8 @@ } } }, - "501": { - "description": "SIP dial-out is not configured", + "404": { + "description": "User, group or other target to invite was not found", "content": { "application/json": { "schema": { @@ -13335,7 +13609,30 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "ban", + "cloud-id", + "federation", + "moderator", + "new-participant", + "outgoing", + "reach-remote", + "room-type", + "sip", + "source", + "trusted-servers" + ] + } + } + } } } } @@ -13343,8 +13640,8 @@ } } }, - "400": { - "description": "Adding participant is not possible, e.g. when the user is banned (check error attribute of response for detail key)", + "501": { + "description": "SIP dial-out is not configured", "content": { "application/json": { "schema": { @@ -13365,9 +13662,25 @@ }, "data": { "type": "object", + "required": [ + "error" + ], "properties": { "error": { - "type": "string" + "type": "string", + "enum": [ + "ban", + "cloud-id", + "federation", + "moderator", + "new-participant", + "outgoing", + "reach-remote", + "room-type", + "sip", + "source", + "trusted-servers" + ] } } } @@ -13542,7 +13855,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -13622,7 +13937,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -13650,16 +13967,30 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} - } - } - } - } - } - } - }, - "404": { - "description": "Participant not found", + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "last-moderator", + "participant" + ] + } + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Participant not found", "content": { "application/json": { "schema": { @@ -13678,7 +14009,21 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "last-moderator", + "participant" + ] + } + } + } } } } @@ -13770,7 +14115,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -13798,7 +14145,23 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "last-moderator", + "owner", + "participant", + "room-type" + ] + } + } + } } } } @@ -13826,7 +14189,23 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "last-moderator", + "owner", + "participant", + "room-type" + ] + } + } + } } } } @@ -13854,7 +14233,23 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "last-moderator", + "owner", + "participant", + "room-type" + ] + } + } + } } } } @@ -13956,6 +14351,16 @@ "responses": { "200": { "description": "Permissions updated successfully", + "headers": { + "X-Nextcloud-Has-User-Statuses": { + "schema": { + "type": "boolean", + "enum": [ + true + ] + } + } + }, "content": { "application/json": { "schema": { @@ -13974,7 +14379,12 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Participant" + } + } } } } @@ -14002,7 +14412,25 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "participant", + "method", + "moderator", + "room-type", + "type", + "value" + ] + } + } + } } } } @@ -14030,7 +14458,25 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "participant", + "method", + "moderator", + "room-type", + "type", + "value" + ] + } + } + } } } } @@ -14058,7 +14504,25 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "participant", + "method", + "moderator", + "room-type", + "type", + "value" + ] + } + } + } } } } @@ -14202,7 +14666,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14385,7 +14851,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14513,7 +14981,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14612,7 +15082,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14640,7 +15112,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14775,7 +15249,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14803,7 +15279,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14905,7 +15383,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14933,7 +15413,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14961,7 +15443,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -14989,7 +15473,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -15079,7 +15565,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -15107,7 +15595,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -15135,7 +15625,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -15163,7 +15655,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "nullable": true + } } } } @@ -15243,7 +15737,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -15321,7 +15817,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -15421,7 +15919,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -15449,7 +15949,20 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "level" + ] + } + } + } } } } @@ -15549,7 +16062,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -15577,7 +16092,20 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "level" + ] + } + } + } } } } @@ -15865,7 +16393,20 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "config" + ] + } + } + } } } } @@ -15893,7 +16434,20 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "config" + ] + } + } + } } } } @@ -15921,7 +16475,20 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "config" + ] + } + } + } } } } @@ -16138,7 +16705,20 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string", + "enum": [ + "config" + ] + } + } + } } } } @@ -16240,7 +16820,9 @@ "meta": { "$ref": "#/components/schemas/OCSMeta" }, - "data": {} + "data": { + "$ref": "#/components/schemas/Room" + } } } } @@ -16383,8 +16965,8 @@ "$ref": "#/components/schemas/Capabilities" }, { - "type": "array", - "maxItems": 0 + "type": "object", + "additionalProperties": true } ] } diff --git a/src/services/CapabilitiesManager.ts b/src/services/CapabilitiesManager.ts index dc17a79e587..97e500e8093 100644 --- a/src/services/CapabilitiesManager.ts +++ b/src/services/CapabilitiesManager.ts @@ -125,12 +125,12 @@ export async function setRemoteCapabilities(joinRoomResponse: JoinRoomFullRespon talkHashStore.setTalkProxyHashDirty(token) const response = await getRemoteCapabilities(token) - if (Array.isArray(response.data.ocs.data)) { - // unknown[] received from server, nothing to update with + if (!Object.keys(response.data.ocs.data).length) { + // data: {} received from server, nothing to update with return } - remoteCapabilities[remoteServer] = { spreed: response.data.ocs.data } + remoteCapabilities[remoteServer] = { spreed: (response.data.ocs.data as Capabilities['spreed']) } remoteCapabilities[remoteServer].hash = joinRoomResponse.headers['x-nextcloud-talk-proxy-hash'] BrowserStorage.setItem('remoteCapabilities', JSON.stringify(remoteCapabilities)) patchTokenMap(joinRoomResponse.data.ocs.data) diff --git a/src/services/__tests__/CapabilitiesManager.spec.js b/src/services/__tests__/CapabilitiesManager.spec.js index 9277b92bfbb..6533bf43cf5 100644 --- a/src/services/__tests__/CapabilitiesManager.spec.js +++ b/src/services/__tests__/CapabilitiesManager.spec.js @@ -139,7 +139,7 @@ describe('CapabilitiesManager', () => { headers: { 'x-nextcloud-talk-proxy-hash': `${remoteCapabilities.hash}001` }, payload: { token, remoteServer }, }) - const responseMock = generateOCSResponse({ payload: [] }) + const responseMock = generateOCSResponse({ payload: {} }) getRemoteCapabilities.mockReturnValue(responseMock) await setRemoteCapabilities(joinRoomResponseMock) expect(talkHashStore.isNextcloudTalkProxyHashDirty[token]).toBeTruthy() diff --git a/src/types/openapi/openapi-administration.ts b/src/types/openapi/openapi-administration.ts index ca9292a0318..679689cb062 100644 --- a/src/types/openapi/openapi-administration.ts +++ b/src/types/openapi/openapi-administration.ts @@ -277,8 +277,8 @@ export type components = { itemsperpage?: string; }; PublicCapabilities: { - spreed: components["schemas"]["Capabilities"]; - } | unknown[]; + spreed?: components["schemas"]["Capabilities"]; + }; }; responses: never; parameters: never; diff --git a/src/types/openapi/openapi-backend-recording.ts b/src/types/openapi/openapi-backend-recording.ts index df314564d04..4ca4a529557 100644 --- a/src/types/openapi/openapi-backend-recording.ts +++ b/src/types/openapi/openapi-backend-recording.ts @@ -111,8 +111,8 @@ export type components = { itemsperpage?: string; }; PublicCapabilities: { - spreed: components["schemas"]["Capabilities"]; - } | unknown[]; + spreed?: components["schemas"]["Capabilities"]; + }; }; responses: never; parameters: never; diff --git a/src/types/openapi/openapi-backend-signaling.ts b/src/types/openapi/openapi-backend-signaling.ts index 4ec2f7721e1..a7bd86951ca 100644 --- a/src/types/openapi/openapi-backend-signaling.ts +++ b/src/types/openapi/openapi-backend-signaling.ts @@ -97,8 +97,8 @@ export type components = { itemsperpage?: string; }; PublicCapabilities: { - spreed: components["schemas"]["Capabilities"]; - } | unknown[]; + spreed?: components["schemas"]["Capabilities"]; + }; }; responses: never; parameters: never; diff --git a/src/types/openapi/openapi-backend-sipbridge.ts b/src/types/openapi/openapi-backend-sipbridge.ts index 4189947bcc0..e85a92d06d5 100644 --- a/src/types/openapi/openapi-backend-sipbridge.ts +++ b/src/types/openapi/openapi-backend-sipbridge.ts @@ -215,8 +215,8 @@ export type components = { itemsperpage?: string; }; PublicCapabilities: { - spreed: components["schemas"]["Capabilities"]; - } | unknown[]; + spreed?: components["schemas"]["Capabilities"]; + }; RichObjectParameter: { type: string; id: string; diff --git a/src/types/openapi/openapi-bots.ts b/src/types/openapi/openapi-bots.ts index 9be4e8d8a3f..389f124c257 100644 --- a/src/types/openapi/openapi-bots.ts +++ b/src/types/openapi/openapi-bots.ts @@ -115,8 +115,8 @@ export type components = { itemsperpage?: string; }; PublicCapabilities: { - spreed: components["schemas"]["Capabilities"]; - } | unknown[]; + spreed?: components["schemas"]["Capabilities"]; + }; }; responses: never; parameters: never; diff --git a/src/types/openapi/openapi-federation.ts b/src/types/openapi/openapi-federation.ts index 04ae262c943..2e1e14c8589 100644 --- a/src/types/openapi/openapi-federation.ts +++ b/src/types/openapi/openapi-federation.ts @@ -262,8 +262,8 @@ export type components = { itemsperpage?: string; }; PublicCapabilities: { - spreed: components["schemas"]["Capabilities"]; - } | unknown[]; + spreed?: components["schemas"]["Capabilities"]; + }; RichObjectParameter: { type: string; id: string; diff --git a/src/types/openapi/openapi-full.ts b/src/types/openapi/openapi-full.ts index a675fd8d073..b4e9fc3a280 100644 --- a/src/types/openapi/openapi-full.ts +++ b/src/types/openapi/openapi-full.ts @@ -2170,8 +2170,8 @@ export type components = { optionId: number; }; PublicCapabilities: { - spreed: components["schemas"]["Capabilities"]; - } | unknown[]; + spreed?: components["schemas"]["Capabilities"]; + }; Reaction: { actorDisplayName: string; actorId: string; @@ -4023,7 +4023,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4037,7 +4039,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4051,7 +4055,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4065,7 +4071,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4102,7 +4110,7 @@ export interface operations { }; }; }; - /** @description History cleared successfully, but Matterbridge is configured, so the information can be replicated elsewhere */ + /** @description History cleared successfully, but Federation or Matterbridge is configured, so the information can be replicated elsewhere */ 202: { headers: { "X-Chat-Last-Common-Read"?: string; @@ -4290,7 +4298,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4304,7 +4314,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4318,7 +4330,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4332,7 +4346,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4395,7 +4411,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4409,7 +4427,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4423,7 +4443,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4437,7 +4459,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4792,7 +4816,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: components["schemas"]["ChatMessage"][]; + data: { + [key: string]: components["schemas"]["ChatMessage"]; + }; }; }; }; @@ -4862,7 +4888,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4876,7 +4904,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4890,7 +4920,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -5479,7 +5511,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -5536,7 +5570,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -5550,7 +5586,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -5611,7 +5649,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -5625,7 +5665,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -5639,20 +5681,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; - }; - }; - }; - }; - 500: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - ocs: { - meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -6266,7 +6297,8 @@ export interface operations { ocs: { meta: components["schemas"]["OCSMeta"]; data: { - error?: string; + /** @enum {string} */ + error: "invite" | "mode" | "object" | "password" | "permissions" | "room" | "type"; message?: string; }; }; @@ -6282,7 +6314,11 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "invite" | "mode" | "object" | "password" | "permissions" | "room" | "type"; + message?: string; + }; }; }; }; @@ -6296,7 +6332,11 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "invite" | "mode" | "object" | "password" | "permissions" | "room" | "type"; + message?: string; + }; }; }; }; @@ -6509,7 +6549,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -6526,7 +6566,7 @@ export interface operations { data: { /** @enum {string} */ error: "breakout-room" | "type" | "value" | "password"; - message?: string | null; + message?: string; }; }; }; @@ -6558,7 +6598,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -6613,7 +6653,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -6672,7 +6712,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -6731,7 +6771,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -6786,7 +6826,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -6959,8 +6999,8 @@ export interface operations { meta: components["schemas"]["OCSMeta"]; data: { /** Format: int64 */ - type: number; - } | unknown[]; + type?: number; + }; }; }; }; @@ -6975,7 +7015,8 @@ export interface operations { ocs: { meta: components["schemas"]["OCSMeta"]; data: { - error?: string; + /** @enum {string} */ + error: "ban" | "cloud-id" | "federation" | "moderator" | "new-participant" | "outgoing" | "reach-remote" | "room-type" | "sip" | "source" | "trusted-servers"; }; }; }; @@ -6990,7 +7031,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "ban" | "cloud-id" | "federation" | "moderator" | "new-participant" | "outgoing" | "reach-remote" | "room-type" | "sip" | "source" | "trusted-servers"; + }; }; }; }; @@ -7004,7 +7048,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "ban" | "cloud-id" | "federation" | "moderator" | "new-participant" | "outgoing" | "reach-remote" | "room-type" | "sip" | "source" | "trusted-servers"; + }; }; }; }; @@ -7114,7 +7161,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "last-moderator" | "participant"; + }; }; }; }; @@ -7128,7 +7178,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "last-moderator" | "participant"; + }; }; }; }; @@ -7176,7 +7229,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "last-moderator" | "owner" | "participant" | "room-type"; + }; }; }; }; @@ -7190,7 +7246,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "last-moderator" | "owner" | "participant" | "room-type"; + }; }; }; }; @@ -7204,7 +7263,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "last-moderator" | "owner" | "participant" | "room-type"; + }; }; }; }; @@ -7249,13 +7311,14 @@ export interface operations { /** @description Permissions updated successfully */ 200: { headers: { + "X-Nextcloud-Has-User-Statuses"?: true; [name: string]: unknown; }; content: { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Participant"][]; }; }; }; @@ -7269,7 +7332,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "participant" | "method" | "moderator" | "room-type" | "type" | "value"; + }; }; }; }; @@ -7283,7 +7349,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "participant" | "method" | "moderator" | "room-type" | "type" | "value"; + }; }; }; }; @@ -7297,7 +7366,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "participant" | "method" | "moderator" | "room-type" | "type" | "value"; + }; }; }; }; @@ -7803,7 +7875,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -7834,7 +7906,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -7875,7 +7947,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -7889,7 +7961,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "level"; + }; }; }; }; @@ -7930,7 +8005,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -7944,7 +8019,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "level"; + }; }; }; }; @@ -8080,7 +8158,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "config"; + }; }; }; }; @@ -8094,7 +8175,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "config"; + }; }; }; }; @@ -8108,7 +8192,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "config"; + }; }; }; }; @@ -8180,7 +8267,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "config"; + }; }; }; }; @@ -8221,7 +8311,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -8271,7 +8361,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: components["schemas"]["Capabilities"] | unknown[]; + data: components["schemas"]["Capabilities"] | { + [key: string]: unknown; + }; }; }; }; diff --git a/src/types/openapi/openapi.ts b/src/types/openapi/openapi.ts index a17fd174c6a..9ea5f5874e8 100644 --- a/src/types/openapi/openapi.ts +++ b/src/types/openapi/openapi.ts @@ -1651,8 +1651,8 @@ export type components = { optionId: number; }; PublicCapabilities: { - spreed: components["schemas"]["Capabilities"]; - } | unknown[]; + spreed?: components["schemas"]["Capabilities"]; + }; Reaction: { actorDisplayName: string; actorId: string; @@ -3504,7 +3504,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -3518,7 +3520,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -3532,7 +3536,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -3546,7 +3552,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -3583,7 +3591,7 @@ export interface operations { }; }; }; - /** @description History cleared successfully, but Matterbridge is configured, so the information can be replicated elsewhere */ + /** @description History cleared successfully, but Federation or Matterbridge is configured, so the information can be replicated elsewhere */ 202: { headers: { "X-Chat-Last-Common-Read"?: string; @@ -3771,7 +3779,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -3785,7 +3795,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -3799,7 +3811,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -3813,7 +3827,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -3876,7 +3892,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -3890,7 +3908,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -3904,7 +3924,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -3918,7 +3940,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4273,7 +4297,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: components["schemas"]["ChatMessage"][]; + data: { + [key: string]: components["schemas"]["ChatMessage"]; + }; }; }; }; @@ -4343,7 +4369,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4357,7 +4385,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4371,7 +4401,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -4960,7 +4992,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -5017,7 +5051,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -5031,7 +5067,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -5092,7 +5130,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -5106,7 +5146,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -5120,20 +5162,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; - }; - }; - }; - }; - 500: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - ocs: { - meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + error: string; + }; }; }; }; @@ -5747,7 +5778,8 @@ export interface operations { ocs: { meta: components["schemas"]["OCSMeta"]; data: { - error?: string; + /** @enum {string} */ + error: "invite" | "mode" | "object" | "password" | "permissions" | "room" | "type"; message?: string; }; }; @@ -5763,7 +5795,11 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "invite" | "mode" | "object" | "password" | "permissions" | "room" | "type"; + message?: string; + }; }; }; }; @@ -5777,7 +5813,11 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "invite" | "mode" | "object" | "password" | "permissions" | "room" | "type"; + message?: string; + }; }; }; }; @@ -5940,7 +5980,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -6090,7 +6130,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -6107,7 +6147,7 @@ export interface operations { data: { /** @enum {string} */ error: "breakout-room" | "type" | "value" | "password"; - message?: string | null; + message?: string; }; }; }; @@ -6139,7 +6179,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -6194,7 +6234,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -6253,7 +6293,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -6312,7 +6352,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -6367,7 +6407,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -6540,8 +6580,8 @@ export interface operations { meta: components["schemas"]["OCSMeta"]; data: { /** Format: int64 */ - type: number; - } | unknown[]; + type?: number; + }; }; }; }; @@ -6556,7 +6596,8 @@ export interface operations { ocs: { meta: components["schemas"]["OCSMeta"]; data: { - error?: string; + /** @enum {string} */ + error: "ban" | "cloud-id" | "federation" | "moderator" | "new-participant" | "outgoing" | "reach-remote" | "room-type" | "sip" | "source" | "trusted-servers"; }; }; }; @@ -6571,7 +6612,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "ban" | "cloud-id" | "federation" | "moderator" | "new-participant" | "outgoing" | "reach-remote" | "room-type" | "sip" | "source" | "trusted-servers"; + }; }; }; }; @@ -6585,7 +6629,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "ban" | "cloud-id" | "federation" | "moderator" | "new-participant" | "outgoing" | "reach-remote" | "room-type" | "sip" | "source" | "trusted-servers"; + }; }; }; }; @@ -6695,7 +6742,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "last-moderator" | "participant"; + }; }; }; }; @@ -6709,7 +6759,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "last-moderator" | "participant"; + }; }; }; }; @@ -6757,7 +6810,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "last-moderator" | "owner" | "participant" | "room-type"; + }; }; }; }; @@ -6771,7 +6827,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "last-moderator" | "owner" | "participant" | "room-type"; + }; }; }; }; @@ -6785,7 +6844,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "last-moderator" | "owner" | "participant" | "room-type"; + }; }; }; }; @@ -6830,13 +6892,14 @@ export interface operations { /** @description Permissions updated successfully */ 200: { headers: { + "X-Nextcloud-Has-User-Statuses"?: true; [name: string]: unknown; }; content: { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Participant"][]; }; }; }; @@ -6850,7 +6913,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "participant" | "method" | "moderator" | "room-type" | "type" | "value"; + }; }; }; }; @@ -6864,7 +6930,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "participant" | "method" | "moderator" | "room-type" | "type" | "value"; + }; }; }; }; @@ -6878,7 +6947,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "participant" | "method" | "moderator" | "room-type" | "type" | "value"; + }; }; }; }; @@ -7384,7 +7456,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -7415,7 +7487,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -7456,7 +7528,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -7470,7 +7542,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "level"; + }; }; }; }; @@ -7511,7 +7586,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -7525,7 +7600,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "level"; + }; }; }; }; @@ -7661,7 +7739,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "config"; + }; }; }; }; @@ -7675,7 +7756,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "config"; + }; }; }; }; @@ -7689,7 +7773,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "config"; + }; }; }; }; @@ -7761,7 +7848,10 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: { + /** @enum {string} */ + error: "config"; + }; }; }; }; @@ -7802,7 +7892,7 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: unknown; + data: components["schemas"]["Room"]; }; }; }; @@ -7852,7 +7942,9 @@ export interface operations { "application/json": { ocs: { meta: components["schemas"]["OCSMeta"]; - data: components["schemas"]["Capabilities"] | unknown[]; + data: components["schemas"]["Capabilities"] | { + [key: string]: unknown; + }; }; }; }; diff --git a/tests/php/Controller/ChatControllerTest.php b/tests/php/Controller/ChatControllerTest.php index 3ceaf0e081f..1e0897770e8 100644 --- a/tests/php/Controller/ChatControllerTest.php +++ b/tests/php/Controller/ChatControllerTest.php @@ -498,7 +498,7 @@ public function testSendReplyByUserToNotReplyable(): void { $this->controller->setRoom($this->room); $this->controller->setParticipant($participant); $response = $this->controller->sendMessage('testMessage', '', '', 23); - $expected = new DataResponse([], Http::STATUS_BAD_REQUEST); + $expected = new DataResponse(['error' => 'reply-to'], Http::STATUS_BAD_REQUEST); $this->assertEquals($expected, $response); } @@ -1060,7 +1060,7 @@ public function testWaitForNewMessagesTimeoutExpired(): void { $this->controller->setRoom($this->room); $this->controller->setParticipant($participant); $response = $this->controller->receiveMessages(1, $limit, $offset, 0, $timeout); - $expected = new DataResponse([], Http::STATUS_NOT_MODIFIED); + $expected = new DataResponse(null, Http::STATUS_NOT_MODIFIED); $this->assertEquals($expected, $response); } @@ -1089,7 +1089,7 @@ public function testWaitForNewMessagesTimeoutTooLarge(): void { $this->controller->setRoom($this->room); $this->controller->setParticipant($participant); $response = $this->controller->receiveMessages(1, $limit, $offset, $timeout); - $expected = new DataResponse([], Http::STATUS_NOT_MODIFIED); + $expected = new DataResponse(null, Http::STATUS_NOT_MODIFIED); $this->assertEquals($expected, $response); } diff --git a/tests/php/Service/RoomServiceTest.php b/tests/php/Service/RoomServiceTest.php index a24e01bbbd9..4a315f87035 100644 --- a/tests/php/Service/RoomServiceTest.php +++ b/tests/php/Service/RoomServiceTest.php @@ -84,7 +84,7 @@ public function testCreateOneToOneConversationWithSameUser(): void { ->willReturn('uid'); $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('invalid_invitee'); + $this->expectExceptionMessage('invite'); $this->service->createOneToOneConversation($user, $user); }