From bf240be8cfd5a2f1ce5035e9266b0315ede3f9b5 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 8 May 2024 12:57:52 +0200 Subject: [PATCH] feat(capabilities): Expose which capabilities should be considered local vs federated Signed-off-by: Joas Schilling --- docs/capabilities.md | 36 ++-- lib/Capabilities.php | 188 +++++++++++------- lib/ResponseDefinitions.php | 2 + openapi-administration.json | 17 ++ openapi-backend-recording.json | 17 ++ openapi-backend-signaling.json | 17 ++ openapi-backend-sipbridge.json | 17 ++ openapi-bots.json | 17 ++ openapi-federation.json | 17 ++ openapi-full.json | 17 ++ openapi.json | 17 ++ src/types/openapi/openapi-administration.ts | 4 + .../openapi/openapi-backend-recording.ts | 4 + .../openapi/openapi-backend-signaling.ts | 4 + .../openapi/openapi-backend-sipbridge.ts | 4 + src/types/openapi/openapi-bots.ts | 4 + src/types/openapi/openapi-federation.ts | 4 + src/types/openapi/openapi-full.ts | 4 + src/types/openapi/openapi.ts | 4 + tests/php/CapabilitiesTest.php | 110 +++------- 20 files changed, 326 insertions(+), 178 deletions(-) diff --git a/docs/capabilities.md b/docs/capabilities.md index 5aa9d9e170e..454481748d4 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -15,7 +15,7 @@ * `chat-v2` - Chat messages are now [Rich Object Strings](https://github.com/nextcloud/server/issues/1706) and pagination is available, the previous `chat` is not available anymore. ## 4.0 -* `favorites` - Conversations can be marked as favorites which will pin them to the top of the conversation list. +* `favorites` (local) - Conversations can be marked as favorites which will pin them to the top of the conversation list. * `last-room-activity` - Conversations have the `lastActivity` attribute and should be sorted by that instead of the last ping of the user. * `no-ping` - The ping endpoint has been removed. Ping is updated with a call to fetch the signaling or chat messages instead. * `system-messages` - Chat messages have a `systemMessage` attribute and can be generated by the system @@ -44,9 +44,9 @@ ## 9.0 -* `config => attachments => allowed` - Whether the user can upload files into a chat -* `config => attachments => folder` - User defined folder where items should be uploaded to -* `config => conversations => can-create` - Whether the user can create public and group conversations, if not only one-to-one conversations are allowed +* `config => attachments => allowed` (local) - Whether the user can upload files into a chat +* `config => attachments => folder` (local) - User defined folder where items should be uploaded to +* `config => conversations => can-create` (local) - Whether the user can create public and group conversations, if not only one-to-one conversations are allowed * `force-mute` - "forceMute" signaling messages can be sent to mute other participants. * `conversation-v2` - ~~The conversations API v2 is less load heavy and should be used by clients when available. Check the difference in the [Conversation API documentation](conversation.md).~~ Replaced by API v4 when `conversation-v4` is set. * `chat-reference-id` - an optional referenceId can be sent with a chat message to be able to identify it in parallel get requests to earlier fade out a temporary message @@ -56,19 +56,19 @@ * `sip-support` - Whether SIP can be configured and enabled by moderators. The conversations API will come with some new values `sipEnabled` which signals whether this conversation has SIP configured as well as `canEnableSIP` to see if a user can enable it. When it is enabled `attendeePin` will contain the unique dial-in code for this user. ## 11.0 -* `chat-read-status` - On conversation API v3 and the chat API the last common read message is exposed which can be used to update the "read status" flag of own chat messages. The info should be shown only when the user also shares their read status. The user's value can be found in `config => chat => read-privacy`. -* `listable-rooms` - Conversations can searched for even when not joined. A "listable" attribute set on rooms defines the scope of who can find it. -* `phonebook-search` - Is present when the server has the endpoint to search for phone numbers to find matches in the accounts list +* `chat-read-status` (local) - On conversation API v3 and the chat API the last common read message is exposed which can be used to update the "read status" flag of own chat messages. The info should be shown only when the user also shares their read status. The user's value can be found in `config => chat => read-privacy`. +* `listable-rooms` (local) - Conversations can searched for even when not joined. A "listable" attribute set on rooms defines the scope of who can find it. +* `phonebook-search` (local) - Is present when the server has the endpoint to search for phone numbers to find matches in the accounts list * `raise-hand` - Participants can raise or lower hand, the state change is sent through signaling messages. * `room-description` - A description can be get and set for conversations. -* `config => chat => read-privacy` - See `chat-read-status` -* `config => previews => max-gif-size` - Maximum size in bytes below which a GIF can be embedded directly in the page at render time. Bigger files will be rendered statically using the preview endpoint instead. Can be set with `occ config:app:set spreed max-gif-size --value=X` where X is the new value in bytes. Defaults to 3 MB. +* `config => chat => read-privacy` (local) - See `chat-read-status` +* `config => previews => max-gif-size` (local) - Maximum size in bytes below which a GIF can be embedded directly in the page at render time. Bigger files will be rendered statically using the preview endpoint instead. Can be set with `occ config:app:set spreed max-gif-size --value=X` where X is the new value in bytes. Defaults to 3 MB. ## 11.1 * `delete-messages` - Allows to delete chat messages up to 6 hours for your own messages or when being a moderator. On deleting the message text will be replaced and a follow up system message will make sure clients and users update it in their cache and storage. * `rich-object-sharing` - Rich objects can be shared to chats. See [OCP\RichObjectStrings\Definitions](https://github.com/nextcloud/server/blob/master/lib/public/RichObjectStrings/Definitions.php) for more details on supported rich objects and required data. * `conversation-call-flags` - Whether the room api provides the `callFlag` to tell apart video and audio calls -* `temp-user-avatar-api` - Whether a temporary api is available to allow users to upload an avatar to their profile via an OCS endpoint. +* `temp-user-avatar-api` (local) - Whether a temporary api is available to allow users to upload an avatar to their profile via an OCS endpoint. ## 12.0 * `conversation-v4` - Whether conversations API v4 is available. This also means that v1, v2 and v3 are **not** available anymore. The changes on API v4 allow a user to have multiple sessions in the same conversation on different devices which is incompatible with the data structure that was used by the previous APIs. @@ -92,7 +92,7 @@ * `rich-object-delete` - When the API allows to delete chat messages which are file or rich object shares ## 15 -* `unified-search` - When the extended attributes of unified search results are there +* `unified-search` (local) - When the extended attributes of unified search results are there * `chat-permission` - When permission 128 is required to post chat messages, reaction or share items to the conversation * `silent-send` - Whether the chat API allows to send chat messages without triggering notifications * `message-expiration` - Message expiration time for a conversation @@ -114,26 +114,26 @@ * `chat-keep-notifications` - Whether messages can be retrieved without marking notifications as read ## 17 -* `avatar` - Avatar of conversation +* `avatar` (local) - Avatar of conversation * ~~`config => chat => translations` - List of translations tuples, JSON encoded sample `{"from":"de","fromLabel":"German","to":"en","toLabel":"English"}`. Those tuples should be provided as options when translating chat messages.~~ Due to some providers the list was too big causing issues in various clients. So the capability was replaced by boolean `config => chat => has-translation-providers` in Talk 18. -* `config => call => predefined-backgrounds` - List of predefined virtual backgrounds. The files are in Talks img/ folder, accessible via the normal image path methods. The list is cached for 5 minutes. -* `config => call => can-upload-background` - Boolean flag whether the user can upload a custom virtual background (requires an account and non-zero quota). Uploads should be done to Talk/Backgrounds/ (respecting the user's attachment directory setting). +* `config => call => predefined-backgrounds` (local) - List of predefined virtual backgrounds. The files are in Talks img/ folder, accessible via the normal image path methods. The list is cached for 5 minutes. +* `config => call => can-upload-background` (local) - Boolean flag whether the user can upload a custom virtual background (requires an account and non-zero quota). Uploads should be done to Talk/Backgrounds/ (respecting the user's attachment directory setting). * `config => call => supported-reactions` - A list of emojis supported as call reactions. If the list is absent or empty, clients should not show the emoji reaction option in calls. -* `config => chat => typing-privacy` - User defined numeric value to enable 1 or disable 0 the typing indicator to other users +* `config => chat => typing-privacy` (local) - User defined numeric value to enable 1 or disable 0 the typing indicator to other users * `typing-privacy` - Support toggle typing privacy ## 17.1 -* `remind-me-later` - Support for "Remind me later" for chat messages exists +* `remind-me-later` (local) - Support for "Remind me later" for chat messages exists * `bots-v1` - Support of the first version for Bots and Webhooks is available * `markdown-messages` - Chat messages support markdown and are rendered automatically ## 18 * `media-caption` - Whether media caption can be added to shared files * `session-state` - Sessions can mark themselves as inactive, so the participant receives notifications again -* `note-to-self` - Support for "Note-to-self" conversation exists +* `note-to-self` (local) - Support for "Note-to-self" conversation exists * `recording-consent` - Whether admins and moderators can require recording consent before joining a call * `sip-support-dialout` - Whether admins can enable SIP dial-out -* `config => chat => has-translation-providers` - When true, translation tuples can be loaded from the [OCS Translation API](https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-translation-api.html#get-available-translation-options). +* `config => chat => has-translation-providers` (local) - When true, translation tuples can be loaded from the [OCS Translation API](https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-translation-api.html#get-available-translation-options). * `config => call => recording-consent` - Whether users need to consent into call recording before joining a call (see [constants list](constants.md#recording-consent-required)) * `config => call => sip-enabled` - Whether SIP is configured on the server allowing for SIP dial-in * `config => call => sip-dialout-enabled` - Whether SIP dial-out is configured on the server, additionally requires `config => call => sip-enabled` diff --git a/lib/Capabilities.php b/lib/Capabilities.php index 8d3c5017e6b..58d44d58ada 100644 --- a/lib/Capabilities.php +++ b/lib/Capabilities.php @@ -25,6 +25,116 @@ * @psalm-import-type TalkCapabilities from ResponseDefinitions */ class Capabilities implements IPublicCapability { + public const FEATURES = [ + 'audio', + 'video', + 'chat-v2', + 'conversation-v4', + 'guest-signaling', + 'empty-group-room', + 'guest-display-names', + 'multi-room-users', + 'favorites', + 'last-room-activity', + 'no-ping', + 'system-messages', + 'delete-messages', + 'mention-flag', + 'in-call-flags', + 'conversation-call-flags', + 'notification-levels', + 'invite-groups-and-mails', + 'locked-one-to-one-rooms', + 'read-only-rooms', + 'listable-rooms', + 'chat-read-marker', + 'chat-unread', + 'webinary-lobby', + 'start-call-flag', + 'chat-replies', + 'circles-support', + 'force-mute', + 'sip-support', + 'sip-support-nopin', + 'chat-read-status', + 'phonebook-search', + 'raise-hand', + 'room-description', + 'rich-object-sharing', + 'temp-user-avatar-api', + 'geo-location-sharing', + 'voice-message-sharing', + 'signaling-v3', + 'publishing-permissions', + 'clear-history', + 'direct-mention-flag', + 'notification-calls', + 'conversation-permissions', + 'rich-object-list-media', + 'rich-object-delete', + 'unified-search', + 'chat-permission', + 'silent-send', + 'silent-call', + 'send-call-notification', + 'talk-polls', + 'breakout-rooms-v1', + 'recording-v1', + 'avatar', + 'chat-get-context', + 'single-conversation-status', + 'chat-keep-notifications', + 'typing-privacy', + 'remind-me-later', + 'bots-v1', + 'markdown-messages', + 'media-caption', + 'session-state', + 'note-to-self', + 'recording-consent', + 'sip-support-dialout', + 'delete-messages-unlimited', + 'edit-messages', + 'silent-send-state', + 'chat-read-last', + 'federation-v1', + 'ban-v1', + ]; + + public const LOCAL_FEATURES = [ + 'favorites', + 'chat-read-status', + 'listable-rooms', + 'phonebook-search', + 'temp-user-avatar-api', + 'unified-search', + 'avatar', + 'remind-me-later', + 'note-to-self', + ]; + + public const LOCAL_CONFIGS = [ + 'attachments' => [ + 'allowed', + 'folder', + ], + 'call' => [ + 'predefined-backgrounds', + 'can-upload-background', + ], + 'chat' => [ + 'read-privacy', + 'has-translation-providers', + 'typing-privacy', + ], + 'conversations' => [ + 'can-create', + ], + 'previews' => [ + 'max-gif-size', + ], + ]; + protected ICache $talkCache; public function __construct( @@ -52,81 +162,8 @@ public function getCapabilities(): array { } $capabilities = [ - 'features' => [ - 'audio', - 'video', - 'chat-v2', - 'conversation-v4', - 'guest-signaling', - 'empty-group-room', - 'guest-display-names', - 'multi-room-users', - 'favorites', - 'last-room-activity', - 'no-ping', - 'system-messages', - 'delete-messages', - 'mention-flag', - 'in-call-flags', - 'conversation-call-flags', - 'notification-levels', - 'invite-groups-and-mails', - 'locked-one-to-one-rooms', - 'read-only-rooms', - 'listable-rooms', - 'chat-read-marker', - 'chat-unread', - 'webinary-lobby', - 'start-call-flag', - 'chat-replies', - 'circles-support', - 'force-mute', - 'sip-support', - 'sip-support-nopin', - 'chat-read-status', - 'phonebook-search', - 'raise-hand', - 'room-description', - 'rich-object-sharing', - 'temp-user-avatar-api', - 'geo-location-sharing', - 'voice-message-sharing', - 'signaling-v3', - 'publishing-permissions', - 'clear-history', - 'direct-mention-flag', - 'notification-calls', - 'conversation-permissions', - 'rich-object-list-media', - 'rich-object-delete', - 'unified-search', - 'chat-permission', - 'silent-send', - 'silent-call', - 'send-call-notification', - 'talk-polls', - 'breakout-rooms-v1', - 'recording-v1', - 'avatar', - 'chat-get-context', - 'single-conversation-status', - 'chat-keep-notifications', - 'typing-privacy', - 'remind-me-later', - 'bots-v1', - 'markdown-messages', - 'media-caption', - 'session-state', - 'note-to-self', - 'recording-consent', - 'sip-support-dialout', - 'delete-messages-unlimited', - 'edit-messages', - 'silent-send-state', - 'chat-read-last', - 'federation-v1', - 'ban-v1', - ], + 'features' => self::FEATURES, + 'features-local' => self::LOCAL_FEATURES, 'config' => [ 'attachments' => [ 'allowed' => $user instanceof IUser, @@ -162,6 +199,7 @@ public function getCapabilities(): array { 'session-ping-limit' => max(0, (int)$this->serverConfig->getAppValue('spreed', 'session-ping-limit', '200')), ], ], + 'config-local' => self::LOCAL_CONFIGS, 'version' => $this->appManager->getAppVersion('spreed'), ]; diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php index e2bd54ed819..0470af3e255 100644 --- a/lib/ResponseDefinitions.php +++ b/lib/ResponseDefinitions.php @@ -294,6 +294,7 @@ * * @psalm-type TalkCapabilities = array{ * features: string[], + * features-local: string[], * config: array{ * attachments: array{ * allowed: bool, @@ -334,6 +335,7 @@ * hello-v2-token-key?: string, * }, * }, + * config-local: array, * version: string, * } */ diff --git a/openapi-administration.json b/openapi-administration.json index 0b27831ee34..5278dd8a1c6 100644 --- a/openapi-administration.json +++ b/openapi-administration.json @@ -91,7 +91,9 @@ "type": "object", "required": [ "features", + "features-local", "config", + "config-local", "version" ], "properties": { @@ -101,6 +103,12 @@ "type": "string" } }, + "features-local": { + "type": "array", + "items": { + "type": "string" + } + }, "config": { "type": "object", "required": [ @@ -270,6 +278,15 @@ } } }, + "config-local": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, "version": { "type": "string" } diff --git a/openapi-backend-recording.json b/openapi-backend-recording.json index b9164754626..9555d8bf632 100644 --- a/openapi-backend-recording.json +++ b/openapi-backend-recording.json @@ -24,7 +24,9 @@ "type": "object", "required": [ "features", + "features-local", "config", + "config-local", "version" ], "properties": { @@ -34,6 +36,12 @@ "type": "string" } }, + "features-local": { + "type": "array", + "items": { + "type": "string" + } + }, "config": { "type": "object", "required": [ @@ -203,6 +211,15 @@ } } }, + "config-local": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, "version": { "type": "string" } diff --git a/openapi-backend-signaling.json b/openapi-backend-signaling.json index bdf2bb70e96..26e2c110116 100644 --- a/openapi-backend-signaling.json +++ b/openapi-backend-signaling.json @@ -24,7 +24,9 @@ "type": "object", "required": [ "features", + "features-local", "config", + "config-local", "version" ], "properties": { @@ -34,6 +36,12 @@ "type": "string" } }, + "features-local": { + "type": "array", + "items": { + "type": "string" + } + }, "config": { "type": "object", "required": [ @@ -203,6 +211,15 @@ } } }, + "config-local": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, "version": { "type": "string" } diff --git a/openapi-backend-sipbridge.json b/openapi-backend-sipbridge.json index 3fce16be8f4..5d0c6b6c42c 100644 --- a/openapi-backend-sipbridge.json +++ b/openapi-backend-sipbridge.json @@ -67,7 +67,9 @@ "type": "object", "required": [ "features", + "features-local", "config", + "config-local", "version" ], "properties": { @@ -77,6 +79,12 @@ "type": "string" } }, + "features-local": { + "type": "array", + "items": { + "type": "string" + } + }, "config": { "type": "object", "required": [ @@ -246,6 +254,15 @@ } } }, + "config-local": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, "version": { "type": "string" } diff --git a/openapi-bots.json b/openapi-bots.json index 13d321fb8cc..a8787a88ec1 100644 --- a/openapi-bots.json +++ b/openapi-bots.json @@ -24,7 +24,9 @@ "type": "object", "required": [ "features", + "features-local", "config", + "config-local", "version" ], "properties": { @@ -34,6 +36,12 @@ "type": "string" } }, + "features-local": { + "type": "array", + "items": { + "type": "string" + } + }, "config": { "type": "object", "required": [ @@ -203,6 +211,15 @@ } } }, + "config-local": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, "version": { "type": "string" } diff --git a/openapi-federation.json b/openapi-federation.json index bf276f4acf0..eb255d8044b 100644 --- a/openapi-federation.json +++ b/openapi-federation.json @@ -67,7 +67,9 @@ "type": "object", "required": [ "features", + "features-local", "config", + "config-local", "version" ], "properties": { @@ -77,6 +79,12 @@ "type": "string" } }, + "features-local": { + "type": "array", + "items": { + "type": "string" + } + }, "config": { "type": "object", "required": [ @@ -246,6 +254,15 @@ } } }, + "config-local": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, "version": { "type": "string" } diff --git a/openapi-full.json b/openapi-full.json index bb7f64da57e..66054b8839a 100644 --- a/openapi-full.json +++ b/openapi-full.json @@ -221,7 +221,9 @@ "type": "object", "required": [ "features", + "features-local", "config", + "config-local", "version" ], "properties": { @@ -231,6 +233,12 @@ "type": "string" } }, + "features-local": { + "type": "array", + "items": { + "type": "string" + } + }, "config": { "type": "object", "required": [ @@ -400,6 +408,15 @@ } } }, + "config-local": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, "version": { "type": "string" } diff --git a/openapi.json b/openapi.json index fc73b582447..d5cd55ef55f 100644 --- a/openapi.json +++ b/openapi.json @@ -162,7 +162,9 @@ "type": "object", "required": [ "features", + "features-local", "config", + "config-local", "version" ], "properties": { @@ -172,6 +174,12 @@ "type": "string" } }, + "features-local": { + "type": "array", + "items": { + "type": "string" + } + }, "config": { "type": "object", "required": [ @@ -341,6 +349,15 @@ } } }, + "config-local": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, "version": { "type": "string" } diff --git a/src/types/openapi/openapi-administration.ts b/src/types/openapi/openapi-administration.ts index 24c71b525c9..ab0097f7475 100644 --- a/src/types/openapi/openapi-administration.ts +++ b/src/types/openapi/openapi-administration.ts @@ -101,6 +101,7 @@ export type components = { }; Capabilities: { features: string[]; + "features-local": string[]; config: { attachments: { allowed: boolean; @@ -147,6 +148,9 @@ export type components = { "hello-v2-token-key"?: string; }; }; + "config-local": { + [key: string]: string[]; + }; version: string; }; OCSMeta: { diff --git a/src/types/openapi/openapi-backend-recording.ts b/src/types/openapi/openapi-backend-recording.ts index 9c62cae160f..6bb66d5358b 100644 --- a/src/types/openapi/openapi-backend-recording.ts +++ b/src/types/openapi/openapi-backend-recording.ts @@ -26,6 +26,7 @@ export type components = { schemas: { Capabilities: { features: string[]; + "features-local": string[]; config: { attachments: { allowed: boolean; @@ -72,6 +73,9 @@ export type components = { "hello-v2-token-key"?: string; }; }; + "config-local": { + [key: string]: string[]; + }; version: string; }; OCSMeta: { diff --git a/src/types/openapi/openapi-backend-signaling.ts b/src/types/openapi/openapi-backend-signaling.ts index 8a431dafdf9..6539ee10fb1 100644 --- a/src/types/openapi/openapi-backend-signaling.ts +++ b/src/types/openapi/openapi-backend-signaling.ts @@ -25,6 +25,7 @@ export type components = { schemas: { Capabilities: { features: string[]; + "features-local": string[]; config: { attachments: { allowed: boolean; @@ -71,6 +72,9 @@ export type components = { "hello-v2-token-key"?: string; }; }; + "config-local": { + [key: string]: string[]; + }; version: string; }; OCSMeta: { diff --git a/src/types/openapi/openapi-backend-sipbridge.ts b/src/types/openapi/openapi-backend-sipbridge.ts index 9c84f364867..e2032d5648a 100644 --- a/src/types/openapi/openapi-backend-sipbridge.ts +++ b/src/types/openapi/openapi-backend-sipbridge.ts @@ -55,6 +55,7 @@ export type components = { }; Capabilities: { features: string[]; + "features-local": string[]; config: { attachments: { allowed: boolean; @@ -101,6 +102,9 @@ export type components = { "hello-v2-token-key"?: string; }; }; + "config-local": { + [key: string]: string[]; + }; version: string; }; ChatMessage: components["schemas"]["BaseMessage"] & { diff --git a/src/types/openapi/openapi-bots.ts b/src/types/openapi/openapi-bots.ts index c4f3ef46656..b2337d8941c 100644 --- a/src/types/openapi/openapi-bots.ts +++ b/src/types/openapi/openapi-bots.ts @@ -31,6 +31,7 @@ export type components = { schemas: { Capabilities: { features: string[]; + "features-local": string[]; config: { attachments: { allowed: boolean; @@ -77,6 +78,9 @@ export type components = { "hello-v2-token-key"?: string; }; }; + "config-local": { + [key: string]: string[]; + }; version: string; }; OCSMeta: { diff --git a/src/types/openapi/openapi-federation.ts b/src/types/openapi/openapi-federation.ts index 0cdcd9d8fca..164ac921749 100644 --- a/src/types/openapi/openapi-federation.ts +++ b/src/types/openapi/openapi-federation.ts @@ -70,6 +70,7 @@ export type components = { }; Capabilities: { features: string[]; + "features-local": string[]; config: { attachments: { allowed: boolean; @@ -116,6 +117,9 @@ export type components = { "hello-v2-token-key"?: string; }; }; + "config-local": { + [key: string]: string[]; + }; version: string; }; ChatMessage: components["schemas"]["BaseMessage"] & { diff --git a/src/types/openapi/openapi-full.ts b/src/types/openapi/openapi-full.ts index 5c9815401ac..a9699f34b19 100644 --- a/src/types/openapi/openapi-full.ts +++ b/src/types/openapi/openapi-full.ts @@ -606,6 +606,7 @@ export type components = { }; Capabilities: { features: string[]; + "features-local": string[]; config: { attachments: { allowed: boolean; @@ -652,6 +653,9 @@ export type components = { "hello-v2-token-key"?: string; }; }; + "config-local": { + [key: string]: string[]; + }; version: string; }; ChatMentionSuggestion: { diff --git a/src/types/openapi/openapi.ts b/src/types/openapi/openapi.ts index 2662409f25d..e0d1c8bccfb 100644 --- a/src/types/openapi/openapi.ts +++ b/src/types/openapi/openapi.ts @@ -445,6 +445,7 @@ export type components = { }; Capabilities: { features: string[]; + "features-local": string[]; config: { attachments: { allowed: boolean; @@ -491,6 +492,9 @@ export type components = { "hello-v2-token-key"?: string; }; }; + "config-local": { + [key: string]: string[]; + }; version: string; }; ChatMentionSuggestion: { diff --git a/tests/php/CapabilitiesTest.php b/tests/php/CapabilitiesTest.php index 07d92887757..1ad094f7923 100644 --- a/tests/php/CapabilitiesTest.php +++ b/tests/php/CapabilitiesTest.php @@ -35,7 +35,6 @@ class CapabilitiesTest extends TestCase { protected ITranslationManager&MockObject $translationManager; protected ICacheFactory&MockObject $cacheFactory; protected ICache&MockObject $talkCache; - protected ?array $baseFeatures = null; public function setUp(): void { parent::setUp(); @@ -61,84 +60,6 @@ public function setUp(): void { ->method('getAppVersion') ->with('spreed') ->willReturn('1.2.3'); - - $this->baseFeatures = [ - 'audio', - 'video', - 'chat-v2', - 'conversation-v4', - 'guest-signaling', - 'empty-group-room', - 'guest-display-names', - 'multi-room-users', - 'favorites', - 'last-room-activity', - 'no-ping', - 'system-messages', - 'delete-messages', - 'mention-flag', - 'in-call-flags', - 'conversation-call-flags', - 'notification-levels', - 'invite-groups-and-mails', - 'locked-one-to-one-rooms', - 'read-only-rooms', - 'listable-rooms', - 'chat-read-marker', - 'chat-unread', - 'webinary-lobby', - 'start-call-flag', - 'chat-replies', - 'circles-support', - 'force-mute', - 'sip-support', - 'sip-support-nopin', - 'chat-read-status', - 'phonebook-search', - 'raise-hand', - 'room-description', - 'rich-object-sharing', - 'temp-user-avatar-api', - 'geo-location-sharing', - 'voice-message-sharing', - 'signaling-v3', - 'publishing-permissions', - 'clear-history', - 'direct-mention-flag', - 'notification-calls', - 'conversation-permissions', - 'rich-object-list-media', - 'rich-object-delete', - 'unified-search', - 'chat-permission', - 'silent-send', - 'silent-call', - 'send-call-notification', - 'talk-polls', - 'breakout-rooms-v1', - 'recording-v1', - 'avatar', - 'chat-get-context', - 'single-conversation-status', - 'chat-keep-notifications', - 'typing-privacy', - 'remind-me-later', - 'bots-v1', - 'markdown-messages', - 'media-caption', - 'session-state', - 'note-to-self', - 'recording-consent', - 'sip-support-dialout', - 'delete-messages-unlimited', - 'edit-messages', - 'silent-send-state', - 'chat-read-last', - 'federation-v1', - 'ban-v1', - 'message-expiration', - 'reactions', - ]; } public function testGetCapabilitiesGuest(): void { @@ -177,7 +98,13 @@ public function testGetCapabilitiesGuest(): void { $this->assertInstanceOf(IPublicCapability::class, $capabilities); $this->assertSame([ 'spreed' => [ - 'features' => $this->baseFeatures, + 'features' => array_merge( + Capabilities::FEATURES, [ + 'message-expiration', + 'reactions', + ] + ), + 'features-local' => Capabilities::LOCAL_FEATURES, 'config' => [ 'attachments' => [ 'allowed' => false, @@ -225,6 +152,7 @@ public function testGetCapabilitiesGuest(): void { 'session-ping-limit' => 200, ], ], + 'config-local' => Capabilities::LOCAL_CONFIGS, 'version' => '1.2.3', ], ], $capabilities->getCapabilities()); @@ -303,10 +231,13 @@ public function testGetCapabilitiesUserAllowed(bool $isNotAllowed, bool $canCrea $this->assertSame([ 'spreed' => [ 'features' => array_merge( - $this->baseFeatures, [ - 'chat-reference-id' + Capabilities::FEATURES, [ + 'message-expiration', + 'reactions', + 'chat-reference-id', ] ), + 'features-local' => Capabilities::LOCAL_FEATURES, 'config' => [ 'attachments' => [ 'allowed' => true, @@ -355,17 +286,26 @@ public function testGetCapabilitiesUserAllowed(bool $isNotAllowed, bool $canCrea 'session-ping-limit' => 50, ], ], + 'config-local' => Capabilities::LOCAL_CONFIGS, 'version' => '1.2.3', ], ], $data); foreach ($data['spreed']['features'] as $feature) { - $this->assertCapabilityIsDocumented("`$feature`"); + $suffix = ''; + if (in_array($feature, $data['spreed']['features-local'])) { + $suffix = ' (local)'; + } + $this->assertCapabilityIsDocumented("`$feature`" . $suffix); } foreach ($data['spreed']['config'] as $feature => $configs) { - foreach ($configs as $config => $data) { - $this->assertCapabilityIsDocumented("`config => $feature => $config`"); + foreach ($configs as $config => $configData) { + $suffix = ''; + if (isset($data['spreed']['config-local'][$feature]) && in_array($config, $data['spreed']['config-local'][$feature])) { + $suffix = ' (local)'; + } + $this->assertCapabilityIsDocumented("`config => $feature => $config`" . $suffix); } } }