From d19361b67d7b177e1c56bf5d1643b4431af3e1dc Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 23 Jul 2024 16:15:59 +0200 Subject: [PATCH 1/2] feat(openapi): Add known limitations to some type, int and string fields Signed-off-by: Joas Schilling --- lib/Chat/ChatManager.php | 6 +- lib/Chat/MessageParser.php | 6 +- lib/Chat/Parser/Changelog.php | 4 +- lib/Chat/Parser/SystemMessage.php | 8 +- lib/Chat/SystemMessage/Listener.php | 4 +- lib/Controller/BotController.php | 6 +- lib/Model/Attendee.php | 9 +- lib/Model/BotServer.php | 12 +- lib/Model/Poll.php | 10 + lib/Model/Reminder.php | 5 +- lib/Model/Session.php | 3 + lib/Notification/Notifier.php | 2 +- lib/ResponseDefinitions.php | 354 ++++++++++++++-------------- lib/Room.php | 3 + lib/Service/BotService.php | 4 +- lib/Service/RoomService.php | 3 + 16 files changed, 238 insertions(+), 201 deletions(-) diff --git a/lib/Chat/ChatManager.php b/lib/Chat/ChatManager.php index 9843720dd65..c075bc76582 100644 --- a/lib/Chat/ChatManager.php +++ b/lib/Chat/ChatManager.php @@ -245,7 +245,7 @@ public function addSystemMessage( * @return IComment */ public function addChangelogMessage(Room $chat, string $message): IComment { - $comment = $this->commentsManager->create(Attendee::ACTOR_GUESTS, Attendee::ACTOR_ID_CHANGELOG, 'chat', (string)$chat->getId()); + $comment = $this->commentsManager->create(Attendee::ACTOR_GUESTS, Attendee::CHANGELOG_ACTOR_ID, 'chat', (string)$chat->getId()); $comment->setMessage($message, self::MAX_CHAT_LENGTH); $comment->setCreationDateTime($this->timeFactory->getDateTime()); @@ -345,8 +345,8 @@ public function sendMessage( // Update last_message if ($comment->getActorType() !== Attendee::ACTOR_BOTS - || $comment->getActorId() === Attendee::ACTOR_ID_CHANGELOG - || str_starts_with($comment->getActorId(), Attendee::ACTOR_BOT_PREFIX)) { + || $comment->getActorId() === Attendee::CHANGELOG_ACTOR_ID + || str_starts_with($comment->getActorId(), Attendee::BOT_ACTOR_PREFIX)) { $this->roomService->setLastMessage($chat, $comment); $this->unreadCountCache->clear($chat->getId() . '-'); } else { diff --git a/lib/Chat/MessageParser.php b/lib/Chat/MessageParser.php index 422fcf15195..d777fbb1a7d 100644 --- a/lib/Chat/MessageParser.php +++ b/lib/Chat/MessageParser.php @@ -137,7 +137,7 @@ protected function getActorInformation(Message $message, string $actorType, stri $displayName = $actorId; $actorId = MatterbridgeManager::BRIDGE_BOT_USERID; } elseif ($actorType === Attendee::ACTOR_GUESTS - && !in_array($actorId, [Attendee::ACTOR_ID_CLI, Attendee::ACTOR_ID_CHANGELOG], true)) { + && !in_array($actorId, [Attendee::CLI_ACTOR_ID, Attendee::CHANGELOG_ACTOR_ID], true)) { if (isset($this->guestNames[$actorId])) { $displayName = $this->guestNames[$actorId]; } else { @@ -151,8 +151,8 @@ protected function getActorInformation(Message $message, string $actorType, stri } elseif ($actorType === Attendee::ACTOR_BOTS) { $displayName = $actorId . '-bot'; $token = $message->getRoom()->getToken(); - if (str_starts_with($actorId, Attendee::ACTOR_BOT_PREFIX)) { - $urlHash = substr($actorId, strlen(Attendee::ACTOR_BOT_PREFIX)); + if (str_starts_with($actorId, Attendee::BOT_ACTOR_PREFIX)) { + $urlHash = substr($actorId, strlen(Attendee::BOT_ACTOR_PREFIX)); $botName = $this->getBotNameByUrlHashForConversation($token, $urlHash); if ($botName) { $displayName = $botName . ' (Bot)'; diff --git a/lib/Chat/Parser/Changelog.php b/lib/Chat/Parser/Changelog.php index a695cb83c3e..b3cfdbd29c0 100644 --- a/lib/Chat/Parser/Changelog.php +++ b/lib/Chat/Parser/Changelog.php @@ -29,12 +29,12 @@ public function handle(Event $event): void { } if ($chatMessage->getActorType() !== Attendee::ACTOR_GUESTS || - $chatMessage->getActorId() !== Attendee::ACTOR_ID_CHANGELOG) { + $chatMessage->getActorId() !== Attendee::CHANGELOG_ACTOR_ID) { return; } $l = $chatMessage->getL10n(); - $chatMessage->setActor(Attendee::ACTOR_BOTS, Attendee::ACTOR_ID_CHANGELOG, $l->t('Talk updates ✅')); + $chatMessage->setActor(Attendee::ACTOR_BOTS, Attendee::CHANGELOG_ACTOR_ID, $l->t('Talk updates ✅')); $event->stopPropagation(); } } diff --git a/lib/Chat/Parser/SystemMessage.php b/lib/Chat/Parser/SystemMessage.php index 558144f7ac2..a65b5e5ab80 100644 --- a/lib/Chat/Parser/SystemMessage.php +++ b/lib/Chat/Parser/SystemMessage.php @@ -156,11 +156,11 @@ protected function parseMessage(Message $chatMessage): void { $participant->getAttendee()->getActorId() === $parsedParameters['actor']['id']; } $cliIsActor = $parsedParameters['actor']['type'] === 'guest' && - 'guest/' . Attendee::ACTOR_ID_CLI === $parsedParameters['actor']['id']; + 'guest/' . Attendee::CLI_ACTOR_ID === $parsedParameters['actor']['id']; if ($message === 'conversation_created') { $systemIsActor = $parsedParameters['actor']['type'] === 'guest' && - 'guest/' . Attendee::ACTOR_ID_SYSTEM === $parsedParameters['actor']['id']; + 'guest/' . Attendee::SYSTEM_ACTOR_ID === $parsedParameters['actor']['id']; $parsedMessage = $this->l->t('{actor} created the conversation'); if ($currentUserIsActor) { @@ -654,7 +654,7 @@ protected function parseMessage(Message $chatMessage): void { $parsedMessage = $this->l->t('Someone voted on the poll {poll}'); unset($parsedParameters['actor']); - $chatMessage->setActor(Attendee::ACTOR_GUESTS, Attendee::ACTOR_ID_SYSTEM, ''); + $chatMessage->setActor(Attendee::ACTOR_GUESTS, Attendee::SYSTEM_ACTOR_ID, ''); } else { throw new \OutOfBoundsException('Unknown subject'); } @@ -1024,7 +1024,7 @@ protected function getGuest(Room $room, string $actorType, string $actorId): arr } protected function getGuestName(Room $room, string $actorType, string $actorId): string { - if ($actorId === Attendee::ACTOR_ID_CLI) { + if ($actorId === Attendee::CLI_ACTOR_ID) { return $this->l->t('Guest'); } diff --git a/lib/Chat/SystemMessage/Listener.php b/lib/Chat/SystemMessage/Listener.php index 702ab950ac5..50a6881ef83 100644 --- a/lib/Chat/SystemMessage/Listener.php +++ b/lib/Chat/SystemMessage/Listener.php @@ -428,7 +428,7 @@ protected function sendSystemMessage(Room $room, string $message, array $paramet $actorId = $participant->getAttendee()->getActorId(); } elseif ($forceSystemAsActor) { $actorType = Attendee::ACTOR_GUESTS; - $actorId = Attendee::ACTOR_ID_SYSTEM; + $actorId = Attendee::SYSTEM_ACTOR_ID; } else { $user = $this->userSession->getUser(); if ($user instanceof IUser) { @@ -436,7 +436,7 @@ protected function sendSystemMessage(Room $room, string $message, array $paramet $actorId = $user->getUID(); } elseif (\OC::$CLI || $this->session->exists('talk-overwrite-actor-cli')) { $actorType = Attendee::ACTOR_GUESTS; - $actorId = Attendee::ACTOR_ID_CLI; + $actorId = Attendee::CLI_ACTOR_ID; } elseif ($this->session->exists('talk-overwrite-actor-type')) { $actorType = $this->session->get('talk-overwrite-actor-type'); $actorId = $this->session->get('talk-overwrite-actor-id'); diff --git a/lib/Controller/BotController.php b/lib/Controller/BotController.php index 0b8cf9797e0..e434e0df33b 100644 --- a/lib/Controller/BotController.php +++ b/lib/Controller/BotController.php @@ -151,7 +151,7 @@ public function sendMessage(string $token, string $message, string $referenceId $room = $this->manager->getRoomByToken($token); $actorType = Attendee::ACTOR_BOTS; - $actorId = Attendee::ACTOR_BOT_PREFIX . $bot->getBotServer()->getUrlHash(); + $actorId = Attendee::BOT_ACTOR_PREFIX . $bot->getBotServer()->getUrlHash(); $parent = null; if ($replyTo !== 0) { @@ -210,7 +210,7 @@ public function react(string $token, int $messageId, string $reaction): DataResp $room = $this->manager->getRoomByToken($token); $actorType = Attendee::ACTOR_BOTS; - $actorId = Attendee::ACTOR_BOT_PREFIX . $bot->getBotServer()->getUrlHash(); + $actorId = Attendee::BOT_ACTOR_PREFIX . $bot->getBotServer()->getUrlHash(); try { $this->reactionManager->addReactionMessage( @@ -263,7 +263,7 @@ public function deleteReaction(string $token, int $messageId, string $reaction): $room = $this->manager->getRoomByToken($token); $actorType = Attendee::ACTOR_BOTS; - $actorId = Attendee::ACTOR_BOT_PREFIX . $bot->getBotServer()->getUrlHash(); + $actorId = Attendee::BOT_ACTOR_PREFIX . $bot->getBotServer()->getUrlHash(); try { $this->reactionManager->deleteReactionMessage( diff --git a/lib/Model/Attendee.php b/lib/Model/Attendee.php index 2682c9b44f9..6f789798944 100644 --- a/lib/Model/Attendee.php +++ b/lib/Model/Attendee.php @@ -60,6 +60,7 @@ */ class Attendee extends Entity { public const ACTOR_USERS = 'users'; + public const ACTOR_GROUPS = 'groups'; public const ACTOR_GUESTS = 'guests'; public const ACTOR_EMAILS = 'emails'; @@ -70,10 +71,10 @@ class Attendee extends Entity { public const ACTOR_PHONES = 'phones'; // Special actor IDs - public const ACTOR_BOT_PREFIX = 'bot-'; - public const ACTOR_ID_CLI = 'cli'; - public const ACTOR_ID_SYSTEM = 'system'; - public const ACTOR_ID_CHANGELOG = 'changelog'; + public const BOT_ACTOR_PREFIX = 'bot-'; + public const CLI_ACTOR_ID = 'cli'; + public const SYSTEM_ACTOR_ID = 'system'; + public const CHANGELOG_ACTOR_ID = 'changelog'; public const PERMISSIONS_DEFAULT = 0; public const PERMISSIONS_CUSTOM = 1; diff --git a/lib/Model/BotServer.php b/lib/Model/BotServer.php index dd57fa6512e..0f6a3cd26bb 100644 --- a/lib/Model/BotServer.php +++ b/lib/Model/BotServer.php @@ -12,26 +12,34 @@ use OCP\AppFramework\Db\Entity; /** + * @psalm-method int<1, max> getId() * @method void setName(string $name) * @method string getName() + * @psalm-method non-empty-string getName() * @method void setUrl(string $url) * @method string getUrl() + * @psalm-method non-empty-string getUrl() * @method void setUrlHash(string $urlHash) * @method string getUrlHash() + * @psalm-method non-empty-string getUrlHash() * @method void setDescription(?string $description) * @method null|string getDescription() * @method void setSecret(string $secret) * @method string getSecret() + * @psalm-method non-empty-string getSecret() * @method void setErrorCount(int $errorCount) * @method int getErrorCount() + * @psalm-method int<0, max> getErrorCount() * @method void setLastErrorDate(?\DateTimeImmutable $lastErrorDate) - * @method ?\DateTimeImmutable getLastErrorDate() + * @method null|\DateTimeImmutable getLastErrorDate() * @method void setLastErrorMessage(string $lastErrorMessage) * @method string getLastErrorMessage() * @method void setState(int $state) * @method int getState() + * @psalm-method Bot::STATE_* getState() * @method void setFeatures(int $features) * @method int getFeatures() + * @psalm-method int-mask<1, 2> getFeatures() * * @psalm-import-type TalkBotWithDetailsAndSecret from ResponseDefinitions */ @@ -72,7 +80,7 @@ public function jsonSerialize(): array { 'description' => $this->getDescription(), 'secret' => $this->getSecret(), 'error_count' => $this->getErrorCount(), - 'last_error_date' => $this->getLastErrorDate() ? $this->getLastErrorDate()->getTimestamp() : 0, + 'last_error_date' => $this->getLastErrorDate() ? max(0, $this->getLastErrorDate()->getTimestamp()) : 0, 'last_error_message' => $this->getLastErrorMessage(), 'state' => $this->getState(), 'features' => $this->getFeatures(), diff --git a/lib/Model/Poll.php b/lib/Model/Poll.php index 9682dea6c72..eaba38c61a1 100644 --- a/lib/Model/Poll.php +++ b/lib/Model/Poll.php @@ -13,28 +13,37 @@ use OCP\AppFramework\Db\Entity; /** + * @psalm-method int<1, max> getId() * @method void setRoomId(int $roomId) * @method int getRoomId() * @method void setQuestion(string $question) * @method string getQuestion() + * @psalm-method non-empty-string getQuestion() * @method void setOptions(string $options) * @method string getOptions() * @method void setVotes(string $votes) * @method string getVotes() * @method void setNumVoters(int $numVoters) * @method int getNumVoters() + * @psalm-method int<0, max> getNumVoters() * @method void setActorType(string $actorType) * @method string getActorType() + * @psalm-method Attendee::ACTOR_* getActorType() * @method void setActorId(string $actorId) * @method string getActorId() + * @psalm-method non-empty-string getActorId() * @method void setDisplayName(string $displayName) * @method string getDisplayName() + * @psalm-method non-empty-string getDisplayName() * @method void setStatus(int $status) * @method int getStatus() + * @psalm-method self::STATUS_* getStatus() * @method void setResultMode(int $resultMode) * @method int getResultMode() + * @psalm-method self::MODE_* getResultMode() * @method void setMaxVotes(int $maxVotes) * @method int getMaxVotes() + * @psalm-method int<0, max> getMaxVotes() * * @psalm-import-type TalkPoll from ResponseDefinitions */ @@ -80,6 +89,7 @@ public function asArray(): array { // Because PHP is turning arrays with sequent numeric keys "{"0":x,"1":y,"2":z}" into "[x,y,z]" // when json_encode() is used we have to prefix the keys with a string, // to prevent breaking in the mobile apps. + /** @var array> $prefixedVotes */ $prefixedVotes = []; foreach ($votes as $option => $count) { $prefixedVotes['option-' . $option] = $count; diff --git a/lib/Model/Reminder.php b/lib/Model/Reminder.php index f910446316d..a51262e77fd 100644 --- a/lib/Model/Reminder.php +++ b/lib/Model/Reminder.php @@ -14,10 +14,13 @@ /** * @method void setUserId(string $userId) * @method string getUserId() + * @psalm-method non-empty-string getUserId() * @method void setToken(string $token) * @method string getToken() + * @psalm-method non-empty-string getToken() * @method void setMessageId(int $messageId) * @method int getMessageId() + * @psalm-method int<1, max> getMessageId() * @method void setDateTime(\DateTime $dateTime) * @method \DateTime getDateTime() * @@ -44,7 +47,7 @@ public function jsonSerialize(): array { 'userId' => $this->getUserId(), 'token' => $this->getToken(), 'messageId' => $this->getMessageId(), - 'timestamp' => $this->getDateTime()->getTimestamp(), + 'timestamp' => max(0, $this->getDateTime()->getTimestamp()), ]; } } diff --git a/lib/Model/Session.php b/lib/Model/Session.php index f5eb517363a..966f670e156 100644 --- a/lib/Model/Session.php +++ b/lib/Model/Session.php @@ -21,10 +21,13 @@ * @method string getSessionId() * @method void setInCall(int $inCall) * @method int getInCall() + * @psalm-method int-mask<1, 2, 4, 8> getInCall() * @method void setLastPing(int $lastPing) * @method int getLastPing() + * @psalm-method int<0, max> getLastPing() * @method void setState(int $state) * @method int getState() + * @psalm-method self::STATE_* getState() */ class Session extends Entity { public const STATE_INACTIVE = 0; diff --git a/lib/Notification/Notifier.php b/lib/Notification/Notifier.php index 198a4c8eb58..328a77afccb 100644 --- a/lib/Notification/Notifier.php +++ b/lib/Notification/Notifier.php @@ -548,7 +548,7 @@ protected function parseChatMessage(INotification $notification, Room $room, Par } elseif ($subjectParameters['userType'] === Attendee::ACTOR_BOTS) { $botId = $subjectParameters['userId']; try { - $bot = $this->botServerMapper->findByUrlHash(substr($botId, strlen(Attendee::ACTOR_BOT_PREFIX))); + $bot = $this->botServerMapper->findByUrlHash(substr($botId, strlen(Attendee::BOT_ACTOR_PREFIX))); $richSubjectUser = [ 'type' => 'highlight', 'id' => $botId, diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php index f690e01829e..872a4db6e82 100644 --- a/lib/ResponseDefinitions.php +++ b/lib/ResponseDefinitions.php @@ -10,115 +10,121 @@ namespace OCA\Talk; /** + * @psalm-type TalkActorTypes = 'users'|'groups'|'guests'|'emails'|'circles'|'bridged'|'bots'|'federated_users'|'phones' + * @psalm-type TalkParticipantTypes = 1|2|3|4|5|6 + * @psalm-type TalkRoomTypes = 1|2|3|4|5|6 + * @psalm-type TalkCallFlags = int<0, 15> + * @psalm-type TalkPermissions = int<0, 255> + * * @psalm-type TalkBan = array{ - * id: int, - * moderatorActorType: string, - * moderatorActorId: string, - * moderatorDisplayName: string, - * bannedActorType: string, - * bannedActorId: string, - * bannedDisplayName: string, - * bannedTime: int, + * id: int<1, max>, + * moderatorActorType: TalkActorTypes, + * moderatorActorId: non-empty-string, + * moderatorDisplayName: non-empty-string, + * bannedActorType: 'guests'|'users'|'ip', + * bannedActorId: non-empty-string, + * bannedDisplayName: non-empty-string, + * bannedTime: int<0, max>, * internalNote: string, * } * * @psalm-type TalkBot = array{ * description: ?string, - * id: int, - * name: string, - * state: int, + * id: int<1, max>, + * name: non-empty-string, + * state: 0|1|2, * } * * @psalm-type TalkBotWithDetails = TalkBot&array{ - * error_count: int, - * features: int, - * last_error_date: int, + * error_count: int<0, max>, + * features: 0|1|2|3, + * last_error_date: int<0, max>, * last_error_message: string, - * url: string, - * url_hash: string, + * url: non-empty-string, + * url_hash: non-empty-string, * } * * @psalm-type TalkBotWithDetailsAndSecret = TalkBotWithDetails&array{ - * secret: string, + * secret: non-empty-string, * } * * @psalm-type TalkCallPeer = array{ - * actorId: string, - * actorType: string, - * displayName: string, - * lastPing: int, - * sessionId: string, - * token: string, + * actorId: non-empty-string, + * actorType: TalkActorTypes, + * displayName: non-empty-string, + * lastPing: int<0, max>, + * sessionId: non-empty-string, + * token: non-empty-string, * } * * @psalm-type TalkChatMentionSuggestion = array{ - * id: string, - * label: string, - * source: string, - * mentionId: string, - * details?: string, - * status?: string, - * statusClearAt?: ?int, + * id: non-empty-string, + * label: non-empty-string, + * source: non-empty-string, + * mentionId: non-empty-string, + * details?: non-empty-string, + * status?: 'online'|'away'|'dnd'|'busy'|'offline'|'invisible', + * statusClearAt?: ?int<0, max>, * statusIcon?: ?string, * statusMessage?: ?string, * } * * @psalm-type TalkRichObjectParameter = array{ - * type: string, - * id: string, - * name: string, - * server?: string, - * link?: string, + * type: non-empty-string, + * id: non-empty-string, + * name: non-empty-string, + * server?: non-empty-string, + * link?: non-empty-string, * 'call-type'?: 'one2one'|'group'|'public', - * 'icon-url'?: string, - * 'message-id'?: string, - * boardname?: string, - * stackname?: string, - * size?: string, - * path?: string, - * mimetype?: string, + * 'icon-url'?: non-empty-string, + * 'message-id'?: non-empty-string, + * boardname?: non-empty-string, + * stackname?: non-empty-string, + * size?: non-empty-string, + * path?: non-empty-string, + * mimetype?: non-empty-string, * 'preview-available'?: 'yes'|'no', - * mtime?: string, - * latitude?: string, - * longitude?: string, - * description?: string, - * thumb?: string, - * website?: string, + * mtime?: non-empty-string, + * latitude?: non-empty-string, + * longitude?: non-empty-string, + * description?: non-empty-string, + * thumb?: non-empty-string, + * website?: non-empty-string, * visibility?: '0'|'1', * assignable?: '0'|'1', - * conversation?: string, - * etag?: string, - * permissions?: string, - * width?: string, - * height?: string, - * blurhash?: string, + * conversation?: non-empty-string, + * etag?: non-empty-string, + * permissions?: non-empty-string, + * width?: non-empty-string, + * height?: non-empty-string, + * blurhash?: non-empty-string, * } * * @psalm-type TalkBaseMessage = array{ - * actorDisplayName: string, - * actorId: string, - * actorType: string, - * expirationTimestamp: int, - * message: string, + * actorDisplayName: non-empty-string, + * actorId: non-empty-string, + * actorType: TalkActorTypes, + * expirationTimestamp: int<0, max>, + * message: non-empty-string, * messageParameters: array, * messageType: string, - * systemMessage: string, + * systemMessage: non-empty-string, * } * * @psalm-type TalkChatMessage = TalkBaseMessage&array{ * deleted?: true, - * id: int, + * id: int<1, max>, * isReplyable: bool, * markdown: bool, * reactions: array|\stdClass, - * reactionsSelf?: string[], + * reactionsSelf?: non-empty-string[], * referenceId: string, - * timestamp: int, - * token: string, - * lastEditActorDisplayName?: string, - * lastEditActorId?: string, - * lastEditActorType?: string, - * lastEditTimestamp?: int, + * timestamp: int<0, max>, + * token: non-empty-string, + * lastEditActorDisplayName?: non-empty-string, + * lastEditActorId?: non-empty-string, + * lastEditActorType?: TalkActorTypes, + * lastEditTimestamp?: int<0, max>, * silent?: bool, * } * @@ -134,24 +140,24 @@ * @psalm-type TalkChatMessageWithParent = TalkChatMessage&array{parent?: TalkChatMessage|TalkDeletedChatMessage} * * @psalm-type TalkChatReminder = array{ - * messageId: int, - * timestamp: int, - * token: string, - * userId: string + * messageId: int<1, max>, + * timestamp: int<0, max>, + * token: non-empty-string, + * userId: non-empty-string * } * * @psalm-type TalkFederationInvite = array{ - * id: int, - * state: int, - * localCloudId: string, - * localToken: string, - * remoteAttendeeId: int, - * remoteServerUrl: string, - * remoteToken: string, - * roomName: string, - * userId: string, - * inviterCloudId: string, - * inviterDisplayName: string, + * id: int<1, max>, + * state: 0|1, + * localCloudId: non-empty-string, + * localToken: non-empty-string, + * remoteAttendeeId: int<1, max>, + * remoteServerUrl: non-empty-string, + * remoteToken: non-empty-string, + * roomName: non-empty-string, + * userId: non-empty-string, + * inviterCloudId: non-empty-string, + * inviterDisplayName: non-empty-string, * } * * @psalm-type TalkMatterbridgeConfigFields = array> @@ -159,7 +165,7 @@ * @psalm-type TalkMatterbridge = array{ * enabled: bool, * parts: TalkMatterbridgeConfigFields, - * pid: int, + * pid: int<1, max>, * } * * @psalm-type TalkMatterbridgeProcessState = array{ @@ -170,20 +176,20 @@ * @psalm-type TalkMatterbridgeWithProcessState = TalkMatterbridge&TalkMatterbridgeProcessState * * @psalm-type TalkParticipant = array{ - * actorId: string, - * actorType: string, - * attendeeId: int, - * attendeePermissions: int, + * actorId: non-empty-string, + * actorType: TalkActorTypes, + * attendeeId: int<1, max>, + * attendeePermissions: TalkPermissions, * attendeePin: string, - * displayName: string, - * inCall: int, - * lastPing: int, - * participantType: int, - * permissions: int, - * roomToken: string, + * displayName: non-empty-string, + * inCall: TalkCallFlags, + * lastPing: int<0, max>, + * participantType: TalkParticipantTypes, + * permissions: TalkPermissions, + * roomToken: non-empty-string, * sessionIds: string[], - * status?: string, - * statusClearAt?: ?int, + * status?: 'online'|'away'|'dnd'|'busy'|'offline'|'invisible', + * statusClearAt?: ?int<0, max>, * statusIcon?: ?string, * statusMessage?: ?string, * phoneNumber?: ?string, @@ -191,103 +197,103 @@ * } * * @psalm-type TalkPollVote = array{ - * actorDisplayName: string, - * actorId: string, - * actorType: string, - * optionId: int, + * actorDisplayName: non-empty-string, + * actorId: non-empty-string, + * actorType: TalkActorTypes, + * optionId: int<0, max>, * } * * @psalm-type TalkPoll = array{ - * actorDisplayName: string, - * actorId: string, - * actorType: string, + * actorDisplayName: non-empty-string, + * actorId: non-empty-string, + * actorType: TalkActorTypes, * details?: TalkPollVote[], - * id: int, - * maxVotes: int, - * numVoters?: int, - * options: string[], - * question: string, - * resultMode: int, - * status: int, + * id: int<1, max>, + * maxVotes: int<0, max>, + * numVoters?: int<0, max>, + * options: non-empty-string[], + * question: non-empty-string, + * resultMode: 0|1, + * status: 0|1, * votedSelf?: int[], * votes?: array, * } * * @psalm-type TalkReaction = array{ - * actorDisplayName: string, - * actorId: string, - * actorType: string, - * timestamp: int, + * actorDisplayName: non-empty-string, + * actorId: non-empty-string, + * actorType: TalkActorTypes, + * timestamp: int<0, max>, * } * * @psalm-type TalkRoom = array{ - * actorId: string, - * actorType: string, - * attendeeId: int, - * attendeePermissions: int, + * actorId: non-empty-string, + * actorType: TalkActorTypes, + * attendeeId: int<1, max>, + * attendeePermissions: TalkPermissions, * attendeePin: ?string, * avatarVersion: string, - * breakoutRoomMode: int, - * breakoutRoomStatus: int, - * callFlag: int, - * callPermissions: int, - * callRecording: int, - * callStartTime: int, + * breakoutRoomMode: 0|1|2|3, + * breakoutRoomStatus: 0|1|2, + * callFlag: TalkCallFlags, + * callPermissions: TalkPermissions, + * callRecording: int<0, 5>, + * callStartTime: int<0, max>, * canDeleteConversation: bool, * canEnableSIP: bool, * canLeaveConversation: bool, * canStartCall: bool, - * defaultPermissions: int, + * defaultPermissions: TalkPermissions, * description: string, - * displayName: string, + * displayName: non-empty-string, * hasCall: bool, * hasPassword: bool, - * id: int, + * id: int<1, max>, * isCustomAvatar: bool, * isFavorite: bool, - * lastActivity: int, - * lastCommonReadMessage: int, + * lastActivity: int<0, max>, + * lastCommonReadMessage: int<0, max>, * lastMessage: TalkRoomLastMessage|array, - * lastPing: int, - * lastReadMessage: int, - * listable: int, - * lobbyState: int, - * lobbyTimer: int, - * mentionPermissions: int, - * messageExpiration: int, - * name: string, - * notificationCalls: int, - * notificationLevel: int, + * lastPing: int<0, max>, + * lastReadMessage: int<0, max>, + * listable: 0|1|2, + * lobbyState: 0|1, + * lobbyTimer: int<0, max>, + * mentionPermissions: 0|1, + * messageExpiration: int<0, max>, + * name: non-empty-string, + * notificationCalls: 0|1, + * notificationLevel: 0|1|2|3, * objectId: string, * objectType: string, - * participantFlags: int, - * participantType: int, - * permissions: int, - * readOnly: int, - * recordingConsent: int, - * remoteServer?: string, - * remoteToken?: string, + * participantFlags: TalkCallFlags, + * participantType: TalkParticipantTypes, + * permissions: TalkPermissions, + * readOnly: 0|1, + * recordingConsent: 0|1|2, + * remoteServer?: non-empty-string, + * remoteToken?: non-empty-string, * sessionId: string, - * sipEnabled: int, - * status?: string, - * statusClearAt?: ?int, + * sipEnabled: 0|1|2, + * status?: 'online'|'away'|'dnd'|'busy'|'offline'|'invisible', + * statusClearAt?: ?int<0, max>, * statusIcon?: ?string, * statusMessage?: ?string, - * token: string, - * type: int, + * token: non-empty-string, + * type: TalkRoomTypes, * unreadMention: bool, * unreadMentionDirect: bool, - * unreadMessages: int, + * unreadMessages: int<0, max>, * } * * @psalm-type TalkSignalingSession = array{ - * actorId: string, - * actorType: string, - * inCall: int, - * lastPing: int, - * participantPermissions: int, - * roomId: int, - * sessionId: string, + * actorId: non-empty-string, + * actorType: non-empty-string, + * inCall: TalkCallFlags, + * lastPing: int<0, max>, + * participantPermissions: TalkPermissions, + * roomId: int<1, max>, + * sessionId: non-empty-string, * userId: string, * } * @@ -303,19 +309,19 @@ * helloAuthParams: array{ * "1.0": array{ * userid: ?string, - * ticket: string, + * ticket: non-empty-string, * }, * "2.0": array{ - * token: string, + * token: non-empty-string, * }, * }, * hideWarning: bool, - * server: string, - * signalingMode: string, + * server: non-empty-string, + * signalingMode: 'internal'|'external'|'conversation_cluster', * sipDialinInfo: string, - * stunservers: array{urls: string[]}[], - * ticket: string, - * turnservers: array{urls: string[], username: string, credential: mixed}[], + * stunservers: array{urls: non-empty-string[]}[], + * ticket: non-empty-string, + * turnservers: array{urls: non-empty-string[], username: non-empty-string, credential: mixed}[], * userId: ?string, * } * @@ -331,7 +337,7 @@ * enabled: bool, * breakout-rooms: bool, * recording: bool, - * recording-consent: int, + * recording-consent: 0|1|2, * supported-reactions: string[], * predefined-backgrounds: string[], * can-upload-background: bool, @@ -340,10 +346,10 @@ * can-enable-sip: bool, * }, * chat: array{ - * max-length: int, - * read-privacy: int, + * max-length: 32000, + * read-privacy: 0|1, * has-translation-providers: bool, - * typing-privacy: int, + * typing-privacy: 0|1, * }, * conversations: array{ * can-create: bool, @@ -355,15 +361,15 @@ * only-trusted-servers: bool, * }, * previews: array{ - * max-gif-size: int, + * max-gif-size: int<0, max>, * }, * signaling: array{ - * session-ping-limit: int, - * hello-v2-token-key?: string, + * session-ping-limit: int<0, max>, + * hello-v2-token-key?: non-empty-string, * }, * }, * config-local: array, - * version: string, + * version: non-empty-string, * } */ class ResponseDefinitions { diff --git a/lib/Room.php b/lib/Room.php index aa5ae0b02f7..bb7c079ed66 100644 --- a/lib/Room.php +++ b/lib/Room.php @@ -570,6 +570,9 @@ public function getMentionPermissions(): int { return $this->mentionPermissions; } + /** + * @psalm-param self::MENTION_PERMISSIONS_* $mentionPermissions + */ public function setMentionPermissions(int $mentionPermissions): void { $this->mentionPermissions = $mentionPermissions; } diff --git a/lib/Service/BotService.php b/lib/Service/BotService.php index 952e5cdcf90..8cf986a6910 100644 --- a/lib/Service/BotService.php +++ b/lib/Service/BotService.php @@ -59,7 +59,7 @@ public function afterBotEnabled(BotEnabledEvent $event): void { 'type' => 'Join', 'actor' => [ 'type' => 'Application', - 'id' => Attendee::ACTOR_BOTS . '/' . Attendee::ACTOR_BOT_PREFIX . $event->getBotServer()->getUrlHash(), + 'id' => Attendee::ACTOR_BOTS . '/' . Attendee::BOT_ACTOR_PREFIX . $event->getBotServer()->getUrlHash(), 'name' => $event->getBotServer()->getName(), ], 'object' => [ @@ -75,7 +75,7 @@ public function afterBotDisabled(BotDisabledEvent $event): void { 'type' => 'Leave', 'actor' => [ 'type' => 'Application', - 'id' => Attendee::ACTOR_BOTS . '/' . Attendee::ACTOR_BOT_PREFIX . $event->getBotServer()->getUrlHash(), + 'id' => Attendee::ACTOR_BOTS . '/' . Attendee::BOT_ACTOR_PREFIX . $event->getBotServer()->getUrlHash(), 'name' => $event->getBotServer()->getName(), ], 'object' => [ diff --git a/lib/Service/RoomService.php b/lib/Service/RoomService.php index 36d4c8f82f7..8c615636de3 100644 --- a/lib/Service/RoomService.php +++ b/lib/Service/RoomService.php @@ -225,6 +225,9 @@ public function setDefaultPermissions(Room $room, int $permissions): void { $this->dispatcher->dispatchTyped($event); } + /** + * @psalm-param Webinary::SIP_* $newSipEnabled + */ public function setSIPEnabled(Room $room, int $newSipEnabled): bool { $oldSipEnabled = $room->getSIPEnabled(); From 4c119d722f7c9960e9a5ca14bb9e55904f49a3bf Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 28 Aug 2024 09:12:55 +0200 Subject: [PATCH 2/2] fix(psalm): Match psalm definitions Signed-off-by: Joas Schilling --- lib/Capabilities.php | 8 +++++--- lib/Chat/ReactionManager.php | 4 ++-- lib/Config.php | 6 ++++++ lib/Model/Message.php | 3 +++ lib/ResponseDefinitions.php | 2 +- 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/lib/Capabilities.php b/lib/Capabilities.php index 8fb7cdc7f44..a868e6ab7ef 100644 --- a/lib/Capabilities.php +++ b/lib/Capabilities.php @@ -175,6 +175,8 @@ public function getCapabilities(): array { return []; } + /** @psalm-var non-empty-string $version */ + $version = $this->appManager->getAppVersion('spreed'); $capabilities = [ 'features' => self::FEATURES, 'features-local' => self::LOCAL_FEATURES, @@ -211,7 +213,7 @@ public function getCapabilities(): array { 'only-trusted-servers' => true, ], 'previews' => [ - 'max-gif-size' => (int)$this->serverConfig->getAppValue('spreed', 'max-gif-size', '3145728'), + 'max-gif-size' => max(0, (int)$this->serverConfig->getAppValue('spreed', 'max-gif-size', '3145728')), ], 'signaling' => [ 'session-ping-limit' => max(0, (int)$this->serverConfig->getAppValue('spreed', 'session-ping-limit', '200')), @@ -219,7 +221,7 @@ public function getCapabilities(): array { ], ], 'config-local' => self::LOCAL_CONFIGS, - 'version' => $this->appManager->getAppVersion('spreed'), + 'version' => $version, ]; if ($this->serverConfig->getAppValue('core', 'backgroundjobs_mode', 'ajax') === 'cron') { @@ -246,7 +248,7 @@ public function getCapabilities(): array { } $pubKey = $this->talkConfig->getSignalingTokenPublicKey(); - if ($pubKey) { + if ($pubKey !== '') { $capabilities['config']['signaling']['hello-v2-token-key'] = $pubKey; } diff --git a/lib/Chat/ReactionManager.php b/lib/Chat/ReactionManager.php index 11a0efe3e1b..0dda8405928 100644 --- a/lib/Chat/ReactionManager.php +++ b/lib/Chat/ReactionManager.php @@ -143,8 +143,8 @@ public function retrieveReactionMessages(Room $chat, Participant $participant, i $this->messageParser->parseMessage($message); $reactions[$comment->getMessage()][] = [ - 'actorType' => $comment->getActorType(), - 'actorId' => $comment->getActorId(), + 'actorType' => $message->getActorType(), + 'actorId' => $message->getActorId(), 'actorDisplayName' => $message->getActorDisplayName(), 'timestamp' => $comment->getCreationDateTime()->getTimestamp(), ]; diff --git a/lib/Config.php b/lib/Config.php index 6996b9999c3..29fe47cb709 100644 --- a/lib/Config.php +++ b/lib/Config.php @@ -64,6 +64,9 @@ public function getAllowedTalkGroupIds(): array { return \is_array($groups) ? $groups : []; } + /** + * @return Participant::PRIVACY_* + */ public function getUserReadPrivacy(string $userId): int { return (int)$this->config->getUserValue( $userId, @@ -71,6 +74,9 @@ public function getUserReadPrivacy(string $userId): int { (string)Participant::PRIVACY_PUBLIC); } + /** + * @return Participant::PRIVACY_* + */ public function getUserTypingPrivacy(string $userId): int { return (int)$this->config->getUserValue( $userId, diff --git a/lib/Model/Message.php b/lib/Model/Message.php index 9743f86e552..ed03c8cf0f4 100644 --- a/lib/Model/Message.php +++ b/lib/Model/Message.php @@ -149,6 +149,9 @@ public function setLastEdit(string $type, string $id, string $displayName, int $ $this->lastEditTimestamp = $timestamp; } + /** + * @return Attendee::ACTOR_* + */ public function getActorType(): string { return $this->actorType; } diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php index 872a4db6e82..731ace1fa7e 100644 --- a/lib/ResponseDefinitions.php +++ b/lib/ResponseDefinitions.php @@ -288,7 +288,7 @@ * * @psalm-type TalkSignalingSession = array{ * actorId: non-empty-string, - * actorType: non-empty-string, + * actorType: TalkActorTypes, * inCall: TalkCallFlags, * lastPing: int<0, max>, * participantPermissions: TalkPermissions,