diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c26e7bf..6b16d61 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,37 +6,78 @@ on: pull_request: branches: [ master, main ] -env: - STREAM_API_KEY: ${{ vars.STREAM_API_KEY }} - STREAM_API_SECRET: ${{ secrets.STREAM_API_SECRET }} - jobs: - test: - name: Test Suite + unit: + name: Unit Tests & Code Quality runs-on: ubuntu-latest - environment: ci - + steps: - name: Checkout code uses: actions/checkout@v4 - + - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: '3.1.0' - + - name: Install dependencies run: bundle install --jobs 4 --retry 3 - - - name: Run tests + + - name: Run unit tests run: make test - - - name: Run integration tests - if: github.event_name == 'push' || github.event_name == 'pull_request' - run: make test-integration - + - name: Run code quality checks run: | make format-check make lint - make security \ No newline at end of file + make security + + integration-non-video: + name: Non-video Integration Tests + runs-on: ubuntu-latest + environment: ci + if: github.event_name == 'push' || github.event_name == 'pull_request' + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.1.0' + + - name: Install dependencies + run: bundle install --jobs 4 --retry 3 + + - name: Run chat integration tests + env: + STREAM_API_KEY: ${{ vars.STREAM_API_KEY }} + STREAM_API_SECRET: ${{ secrets.STREAM_API_SECRET }} + STREAM_BASE_URL: ${{ vars.STREAM_BASE_URL }} + run: make test-integration-chat + + integration-video: + name: Video Integration Tests + runs-on: ubuntu-latest + environment: ci + if: github.event_name == 'push' || github.event_name == 'pull_request' + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.1.0' + + - name: Install dependencies + run: bundle install --jobs 4 --retry 3 + + - name: Run video integration tests + env: + STREAM_API_KEY: ${{ vars.STREAM_VIDEO_API_KEY }} + STREAM_API_SECRET: ${{ secrets.STREAM_VIDEO_API_SECRET }} + STREAM_BASE_URL: ${{ vars.STREAM_VIDEO_BASE_URL }} + run: make test-integration-video diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml new file mode 100644 index 0000000..a140505 --- /dev/null +++ b/.github/workflows/prerelease.yml @@ -0,0 +1,37 @@ +name: Pre-release + +on: + release: + types: [prereleased] + +jobs: + prerelease: + name: ๐Ÿš€ Pre-release + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Resolve version + run: | + TAG="${{ github.event.release.tag_name }}" + VERSION="${TAG#v}" + echo "VERSION=$VERSION" >> $GITHUB_ENV + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.1.0' + + - name: Install dependencies + run: bundle install --jobs 4 --retry 3 + + - name: Update version file + run: | + sed -i "s/VERSION = '[^']*'/VERSION = '$VERSION'/" lib/getstream_ruby/version.rb + + - name: Build and publish gem + env: + GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }} + run: | + gem build getstream-ruby.gemspec + gem push getstream-ruby-$VERSION.gem --key $GEM_HOST_API_KEY diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 07981d4..a4683b9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: inputs: version_type: - description: 'Version type' + description: 'Version type (used by create-release-pr only)' required: true default: 'patch' type: choice @@ -13,9 +13,19 @@ on: - minor - major release_notes: - description: 'Release notes (optional)' + description: 'Release notes (used by create-release-pr only)' required: false type: string + publish_directly: + description: 'Skip PR creation and publish the version already in version.rb directly' + required: false + default: false + type: boolean + prerelease: + description: 'Mark the GitHub Release as a pre-release (used when publish_directly is true)' + required: false + default: false + type: boolean push: branches: [ main, master ] @@ -23,7 +33,7 @@ jobs: create-release-pr: name: Create Release PR runs-on: ubuntu-latest - if: github.event_name == 'workflow_dispatch' + if: github.event_name == 'workflow_dispatch' && github.event.inputs.publish_directly != 'true' steps: - name: Checkout code @@ -162,7 +172,7 @@ jobs: release: name: Release runs-on: ubuntu-latest - if: github.event_name == 'push' + if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.publish_directly == 'true') steps: - name: Checkout code @@ -200,7 +210,7 @@ jobs: See CHANGELOG.md for details. draft: false - prerelease: false + prerelease: ${{ github.event.inputs.prerelease == 'true' }} - name: Build and publish gem diff --git a/CHANGELOG.md b/CHANGELOG.md index 25aca89..c2a543f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,102 +1,63 @@ -## [2.1.0] - 2026-02-18 +# Changelog -### minor^2 changes -- +All notable changes to this project will be documented in this file. -## [2.0.0] - 2026-02-02 +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -### major^2 changes -- +## [3.0.0.beta.1] - 2026-02-27 -## [1.1.1] - 2026-01-29 +### Breaking Changes -### patch^2 changes -- +- Type names across all products now follow the OpenAPI spec naming convention: response types are suffixed with `Response`, input types with `Request`. See [MIGRATION_v2_to_v3.md](./MIGRATION_v2_to_v3.md) for the complete rename mapping. +- `Event` (WebSocket envelope type) renamed to `WSEvent`. Base event type renamed from `BaseEvent` to `Event` (with field `type` instead of `T`). +- Event composition changed from monolithic `*Preset` embeds to modular `Has*` types. +- `Pager` renamed to `PagerResponse` and migrated from offset-based to cursor-based pagination (`next`/`prev` tokens). -## [1.1.0] - 2026-01-26 +### Added -### minor^2 changes -- +- Full product coverage: Chat, Video, Moderation, and Feeds APIs are all supported in a single SDK. +- **Feeds**: activities, feeds, feed groups, follows, comments, reactions, collections, bookmarks, membership levels, feed views, and more. +- **Video**: calls, recordings, transcription, closed captions, SFU, call statistics, user feedback analytics, and more. +- **Moderation**: flags, review queue, moderation rules, config, appeals, moderation logs, and more. +- Push notification types, preferences, and templates. +- Webhook support: `WHEvent` envelope class for receiving webhook payloads, utility methods for decoding and verifying webhook signatures, and a full set of individual typed event classes for every event across all products (Chat, Video, Moderation, Feeds) usable as discriminated event types. +- Cursor-based pagination across all list endpoints. -## [1.0.1] - 2025-12-11 +## [2.1.0] - 2026-02-18 -### patch^2 changes -- +## [2.0.0] - 2026-02-02 -## [1.0.0] - 2025-12-11 +## [1.1.1] - 2026-01-29 -### major^2 changes -- +## [1.1.0] - 2026-01-26 -## [0.1.12] - 2025-10-13 +## [1.0.1] - 2025-12-11 -### patch^2 changes -- +## [1.0.0] - 2025-12-11 -## [0.1.11] - 2025-10-13 +## [0.1.12] - 2025-10-13 -### patch^2 changes -- +## [0.1.11] - 2025-10-13 ## [0.1.10] - 2025-10-13 -### patch^2 changes -- - ## [0.1.9] - 2025-10-13 -### patch^2 changes -- - ## [0.1.8] - 2025-10-13 -### patch^2 changes -- - ## [0.1.7] - 2025-10-13 -### patch^2 changes -- - ## [0.1.6] - 2025-10-13 -### patch^2 changes -- - ## [0.1.5] - 2025-10-10 -### patch^2 changes -- - ## [0.1.4] - 2025-10-10 -### patch^2 changes -- - ## [0.1.3] - 2025-10-10 -### patch^2 changes -- - ## [0.1.2] - 2025-10-08 -### patch^2 changes -- - ## [0.1.1] - 2025-10-08 -### patch^2 changes -- - ## [0.1.0] - 2025-10-07 - -### minor^2 changes -- - -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - diff --git a/MIGRATION_v2_to_v3.md b/MIGRATION_v2_to_v3.md new file mode 100644 index 0000000..57c24b5 --- /dev/null +++ b/MIGRATION_v2_to_v3.md @@ -0,0 +1,209 @@ +# Migration Guide: v2 โ†’ v3 + +This guide covers all breaking changes when upgrading from `getstream-ruby` v2 to v3. + +## Overview + +v3 is a full OpenAPI-aligned release. The primary change is a **systematic type renaming**: types that appear in API responses now have a `Response` suffix, and input types have a `Request` suffix. There are no removed features โ€” all functionality from v2 is available in v3. Additionally, v3 adds complete coverage of the **Feeds**, **Video**, and **Moderation** product APIs. + +## Installation + +Update your `Gemfile`: + +```ruby +gem 'getstream-ruby', '~> 3.0' +``` + +Then run: + +```bash +bundle install +``` + +## Naming Conventions + +All classes use `PascalCase` (standard Ruby convention). The general rules: + +- Classes returned in API responses: `Foo` โ†’ `FooResponse` +- Classes used as API inputs: `Foo` โ†’ `FooRequest` +- Some moderation action payloads: `FooRequest` โ†’ `FooRequestPayload` + +## Breaking Changes + +### Common / Shared Types + +| v2 | v3 | Notes | +| --- | --- | --- | +| `ApplicationConfig` | `AppResponseFields` | App configuration in responses | +| `ChannelPushPreferences` | `ChannelPushPreferencesResponse` | Per-channel push settings | +| `Device` | `DeviceResponse` | Device data (push, voip) | +| `Event` | `WSEvent` | WebSocket event envelope | +| `FeedsPreferences` | `FeedsPreferencesResponse` | Feeds push preferences | +| `ImportV2Task` | `ImportV2TaskItem` | V2 import task | +| `OwnUser` | `OwnUserResponse` | Authenticated user data | +| `Pager` | `PagerResponse` | Now cursor-based (`next`/`prev`) | +| `PushPreferences` | `PushPreferencesResponse` | Push preferences | +| `PushTemplate` | `PushTemplateResponse` | Push template | +| `PrivacySettings` | `PrivacySettingsResponse` | Typing indicators, read receipts | +| `RateLimitInfo` | `LimitInfoResponse` | Rate limit info | +| `SortParam` | `SortParamRequest` | Sort parameter for queries | +| `User` | `UserResponse` | Full user in responses | +| `UserBlock` | `BlockedUserResponse` | Blocked user details | +| `UserCustomEvent` | `CustomEvent` | Custom user event | +| `UserMute` | `UserMuteResponse` | User mute details | + +### Event System + +| Before (v2) | After (v3) | Notes | +| --- | --- | --- | +| `BaseEvent` (field `T`) | `Event` (field `type`) | Base event type | +| `Event` (WS envelope) | `WSEvent` | WebSocket event wrapper | +| `*Preset` embeds | `Has*` composition types | e.g., `HasChannel`, `HasMessage` | +| โ€” | `WHEvent` | New webhook envelope type | + +New composition types: `HasOwnUser`, `HasUserCommonFields`, `HasUserPrivacyFields`, `HasOptionalUserCommonFields`, `HasChannel`, `HasOptionalChannel`, `HasMessage`, `HasOptionalMessage`, `HasThreadParticipants`, `HasChannelTypeAndID`. + +### Chat Types + +| v2 | v3 | Notes | +| --- | --- | --- | +| `Campaign` | `CampaignResponse` | | +| `CampaignStats` | `CampaignStatsResponse` | | +| `Channel` | `ChannelResponse` | | +| `ChannelConfigFields` | `ChannelConfigWithInfo` | Channel config + commands/grants | +| `ChannelMember` | `ChannelMemberResponse` | | +| `ChannelTypeConfigWithInfo` | `ChannelTypeConfig` | | +| `ConfigOverrides` | `ConfigOverridesRequest` | | +| `DraftMessage` / `DraftMessagePayload` | `DraftResponse` | Two classes merged into one | +| `Message` | `MessageResponse` | | +| `MessageReminder` | `ReminderResponseData` | | +| `PendingMessage` | `PendingMessageResponse` | | +| `Poll` | `PollResponse` | | +| `PollOption` | `PollOptionResponse` | | +| `PollVote` | `PollVoteResponse` | | +| `Reaction` | `ReactionResponse` | | +| `ReadState` | `ReadStateResponse` | | +| `Thread` | `ThreadResponse` | | + +### Video Types + +| v2 | v3 | Notes | +| --- | --- | --- | +| `AudioSettings` | `AudioSettingsResponse` | | +| `BackstageSettings` | `BackstageSettingsResponse` | | +| `BroadcastSettings` | `BroadcastSettingsResponse` | | +| `Call` | `CallResponse` | | +| `CallEgress` | `EgressResponse` | | +| `CallMember` | `MemberResponse` | Note: not `CallMemberResponse` | +| `CallParticipant` | `CallParticipantResponse` | | +| `CallParticipantFeedback` | *(removed)* | Use `CollectUserFeedbackRequest` | +| `CallSession` | `CallSessionResponse` | | +| `CallSettings` | `CallSettingsResponse` | | +| `CallType` | `CallTypeResponse` | | +| `EventNotificationSettings` | `EventNotificationSettingsResponse` | | +| `FrameRecordSettings` | `FrameRecordingSettingsResponse` | `Recording` inserted in name | +| `GeofenceSettings` | `GeofenceSettingsResponse` | | +| `HLSSettings` | `HLSSettingsResponse` | | +| `IndividualRecordSettings` | `IndividualRecordingSettingsResponse` | `Recording` inserted in name | +| `IngressSettings` | `IngressSettingsResponse` | | +| `IngressSource` | `IngressSourceResponse` | | +| `IngressAudioEncodingOptions` | `IngressAudioEncodingResponse` | Shortened name | +| `IngressVideoEncodingOptions` | `IngressVideoEncodingResponse` | Shortened name | +| `IngressVideoLayer` | `IngressVideoLayerResponse` | | +| `LimitsSettings` | `LimitsSettingsResponse` | | +| `NotificationSettings` | `NotificationSettingsResponse` | | +| `RawRecordSettings` | `RawRecordingSettingsResponse` | `Recording` inserted in name | +| `RecordSettings` | `RecordSettingsResponse` | | +| `RingSettings` | `RingSettingsResponse` | | +| `RTMPSettings` | `RTMPSettingsResponse` | | +| `ScreensharingSettings` | `ScreensharingSettingsResponse` | | +| `SessionSettings` | `SessionSettingsResponse` | | +| `SIPCallConfigs` | `SIPCallConfigsResponse` | | +| `SIPCallerConfigs` | `SIPCallerConfigsResponse` | | +| `SIPDirectRoutingRuleCallConfigs` | `SIPDirectRoutingRuleCallConfigsResponse` | | +| `SIPInboundRoutingRules` | `SIPInboundRoutingRuleResponse` | Plural โ†’ singular | +| `SIPPinProtectionConfigs` | `SIPPinProtectionConfigsResponse` | | +| `SIPTrunk` | `SIPTrunkResponse` | | +| `ThumbnailsSettings` | `ThumbnailsSettingsResponse` | | +| `TranscriptionSettings` | `TranscriptionSettingsResponse` | | +| `VideoSettings` | `VideoSettingsResponse` | | + +### Moderation Types + +| v2 | v3 | Notes | +| --- | --- | --- | +| `ActionLog` | `ActionLogResponse` | | +| `Appeal` | `AppealItemResponse` | | +| `AutomodDetails` | `AutomodDetailsResponse` | | +| `Ban` | `BanInfoResponse` | | +| `BanOptions` | *(removed)* | Merged into `BanActionRequestPayload` | +| `BanActionRequest` | `BanActionRequestPayload` | | +| `BlockActionRequest` | `BlockActionRequestPayload` | | +| `BlockedMessage` | *(removed)* | Internal only | +| `CustomActionRequest` | `CustomActionRequestPayload` | | +| `DeleteMessageRequest` | `DeleteMessageRequestPayload` | | +| `DeleteUserRequest` | `DeleteUserRequestPayload` | | +| `EntityCreator` | `EntityCreatorResponse` | | +| `Evaluation` | `EvaluationResponse` | | +| `FeedsModerationTemplate` | `QueryFeedModerationTemplate` | No `Response` suffix | +| `FeedsModerationTemplateConfig` | `FeedsModerationTemplateConfigPayload` | | +| `Flag` | *(removed)* | Use `ModerationFlagResponse` | +| `Flag2` | `ModerationFlagResponse` | | +| `FlagDetails` | `FlagDetailsResponse` | | +| `FlagFeedback` | `FlagFeedbackResponse` | | +| `FlagMessageDetails` | `FlagMessageDetailsResponse` | | +| `FlagReport` | *(removed)* | Internal only | +| `FutureChannelBan` | `FutureChannelBanResponse` | | +| `MarkReviewedRequest` | `MarkReviewedRequestPayload` | | +| `Match` | `MatchResponse` | | +| `ModerationActionConfig` | `ModerationActionConfigResponse` | | +| `ModerationBulkSubmitActionRequest` | `BulkSubmitActionRequest` | `Moderation` prefix dropped | +| `ModerationConfig` | `ConfigResponse` | | +| `ModerationFlags` | *(removed)* | Use array of `ModerationFlagResponse` | +| `ModerationLog` | *(removed)* | Use `ActionLogResponse` | +| `ModerationLogResponse` | *(removed)* | Use `QueryModerationLogsResponse` | +| `ModerationUsageStats` | `ModerationUsageStatsResponse` | | +| `RestoreActionRequest` | `RestoreActionRequestPayload` | | +| `ReviewQueueItem` | `ReviewQueueItemResponse` | | +| `Rule` | `RuleResponse` | | +| `ShadowBlockActionRequest` | `ShadowBlockActionRequestPayload` | | +| `Task` | `TaskResponse` | | +| `Trigger` | `TriggerResponse` | | +| `UnbanActionRequest` | `UnbanActionRequestPayload` | | +| `UnblockActionRequest` | `UnblockActionRequestPayload` | | +| `VideoEndCallRequest` | `VideoEndCallRequestPayload` | | +| `VideoKickUserRequest` | `VideoKickUserRequestPayload` | | + +### Feeds Types + +| v2 | v3 | Notes | +| --- | --- | --- | +| `Activity` | `ActivityResponse` | | +| `ActivityFeedback` | `ActivityFeedbackRequest` | Request-only (no `Response` suffix) | +| `ActivityMark` | `MarkActivityRequest` | | +| `ActivityPin` | `ActivityPinResponse` | | +| `AggregatedActivity` | `AggregatedActivityResponse` | | +| `Bookmark` | `BookmarkResponse` | | +| `BookmarkFolder` | `BookmarkFolderResponse` | | +| `Collection` | `CollectionResponse` | | +| `Comment` | `CommentResponse` | | +| `CommentMedia` | *(removed)* | Embedded inline in `CommentResponse` | +| `CommentMention` | *(removed)* | Embedded inline in `CommentResponse` | +| `DenormalizedFeedsReaction` | *(removed)* | Internal only | +| `Feed` | `FeedResponse` | | +| `FeedGroup` | `FeedGroupResponse` | | +| `FeedMember` | `FeedMemberResponse` | | +| `FeedsReaction` | `FeedsReactionResponse` | | +| `FeedsReactionGroup` | `FeedsReactionGroupResponse` | | +| `FeedSuggestion` | `FeedSuggestionResponse` | | +| `FeedView` | `FeedViewResponse` | | +| `FeedVisibilityInfo` | `FeedVisibilityResponse` | | +| `Follow` | `FollowResponse` | | +| `MembershipLevel` | `MembershipLevelResponse` | | +| `ThreadedComment` | `ThreadedCommentResponse` | | + +## Getting Help + +- [Stream documentation](https://getstream.io/docs/) +- [GitHub Issues](https://github.com/GetStream/getstream-ruby/issues) +- [Stream support](https://getstream.io/contact/support/) diff --git a/Makefile b/Makefile index ea50cb4..d468cc4 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # GetStream Ruby SDK Makefile -.PHONY: help install test test-unit test-integration lint format clean setup +.PHONY: help install test test-unit test-integration test-integration-chat test-integration-video lint format clean setup # Default target help: ## Show this help message @@ -28,9 +28,15 @@ test: test-unit ## Run unit tests only test-unit: ## Run unit tests (excluding integration tests) bundle exec rspec spec --exclude-pattern "spec/integration/**/*_spec.rb" -test-integration: ## Run integration tests only +test-integration: ## Run all integration tests bundle exec rspec spec/integration/ +test-integration-chat: ## Run chat integration tests only (excludes video) + bundle exec rspec spec/integration/ --exclude-pattern "spec/integration/video*_spec.rb" + +test-integration-video: ## Run video integration tests only + bundle exec rspec spec/integration/video_integration_spec.rb spec/integration/video_client_integration_spec.rb + test-all: ## Run all tests (unit + integration) bundle exec rspec spec/ diff --git a/README.md b/README.md index 4cc16cc..31c99b1 100644 --- a/README.md +++ b/README.md @@ -288,6 +288,9 @@ The project includes simple GitHub Actions workflows: - Create a tag: `git tag v1.0.0 && git push origin v1.0.0` - Automated gem build and release +- **Pre-releasee Pipeline:** Create a pre-release to trigger the workflow + - Push a tag (e.g. `1.0.0.beta.1`), then go to **GitHub Releases -> Draft a new release**, select the tag, check **"Set as a pre-release"**, and publish. The CI job will trigger automatically and publish the package. + #### GitHub Environment Variables To enable integration tests in CI, configure these GitHub repository settings: diff --git a/lib/getstream_ruby/client.rb b/lib/getstream_ruby/client.rb index 7d49495..d948b53 100644 --- a/lib/getstream_ruby/client.rb +++ b/lib/getstream_ruby/client.rb @@ -9,6 +9,8 @@ require_relative 'generated/common_client' require_relative 'generated/feeds_client' require_relative 'generated/moderation_client' +require_relative 'generated/chat_client' +require_relative 'generated/video_client' require_relative 'extensions/moderation_extensions' require_relative 'generated/feed' require_relative 'stream_response' @@ -57,6 +59,16 @@ def moderation @moderation ||= GetStream::Generated::ModerationClient.new(self) end + # @return [GetStream::Generated::ChatClient] The chat API client + def chat + @chat ||= GetStream::Generated::ChatClient.new(self) + end + + # @return [GetStream::Generated::VideoClient] The video API client + def video + @video ||= GetStream::Generated::VideoClient.new(self) + end + # Create an individual feed instance # @param feed_group_id [String] The feed group ID # @param feed_id [String] The feed ID diff --git a/lib/getstream_ruby/generated/chat_client.rb b/lib/getstream_ruby/generated/chat_client.rb new file mode 100644 index 0000000..b30a959 --- /dev/null +++ b/lib/getstream_ruby/generated/chat_client.rb @@ -0,0 +1,1652 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +# Load all models at once +Dir[File.join(__dir__, "models", "*.rb")].sort.each { |file| require_relative file } + +module GetStream + module Generated + # Chat API client with generated methods + class ChatClient + def initialize(client) + @client = client + end + # Query campaigns with filter query + # + # @param query_campaigns_request [QueryCampaignsRequest] + # @return [Models::QueryCampaignsResponse] + def query_campaigns(query_campaigns_request) + path = '/api/v2/chat/campaigns/query' + # Build request body + body = query_campaigns_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Get campaign by ID. + # + # @param _id [String] + # @param prev [String] + # @param _next [String] + # @param limit [Integer] + # @return [Models::GetCampaignResponse] + def get_campaign(_id, prev = nil, _next = nil, limit = nil) + path = '/api/v2/chat/campaigns/{id}' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build query parameters + query_params = {} + query_params['prev'] = prev unless prev.nil? + query_params['next'] = _next unless _next.nil? + query_params['limit'] = limit unless limit.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Starts or schedules a campaign + # + # @param _id [String] + # @param start_campaign_request [StartCampaignRequest] + # @return [Models::StartCampaignResponse] + def start_campaign(_id, start_campaign_request) + path = '/api/v2/chat/campaigns/{id}/start' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = start_campaign_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Stops a campaign + # + # @param _id [String] + # @param stop_campaign_request [StopCampaignRequest] + # @return [Models::CampaignResponse] + def stop_campaign(_id, stop_campaign_request) + path = '/api/v2/chat/campaigns/{id}/stop' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = stop_campaign_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Query channels with filter query + # + # @param query_channels_request [QueryChannelsRequest] + # @return [Models::QueryChannelsResponse] + def query_channels(query_channels_request) + path = '/api/v2/chat/channels' + # Build request body + body = query_channels_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Update channels in batchSends events:- channel.frozen- channel.hidden- channel.unfrozen- channel.updated- channel.visible- member.added- member.removed- member.updated + # + # @param channel_batch_update_request [ChannelBatchUpdateRequest] + # @return [Models::ChannelBatchUpdateResponse] + def channel_batch_update(channel_batch_update_request) + path = '/api/v2/chat/channels/batch' + # Build request body + body = channel_batch_update_request + + # Make the API request + @client.make_request( + :put, + path, + body: body + ) + end + + # Allows to delete several channels at once asynchronouslySends events:- channel.deleted + # + # @param delete_channels_request [DeleteChannelsRequest] + # @return [Models::DeleteChannelsResponse] + def delete_channels(delete_channels_request) + path = '/api/v2/chat/channels/delete' + # Build request body + body = delete_channels_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Mark the status of a channel message delivered. + # + # @param mark_delivered_request [MarkDeliveredRequest] + # @param user_id [String] + # @return [Models::MarkDeliveredResponse] + def mark_delivered(mark_delivered_request, user_id = nil) + path = '/api/v2/chat/channels/delivered' + # Build query parameters + query_params = {} + query_params['user_id'] = user_id unless user_id.nil? + # Build request body + body = mark_delivered_request + + # Make the API request + @client.make_request( + :post, + path, + query_params: query_params, + body: body + ) + end + + # Marks channels as read up to the specific message. If no channels is given, mark all channel as readSends events:- message.read + # + # @param mark_channels_read_request [MarkChannelsReadRequest] + # @return [Models::MarkReadResponse] + def mark_channels_read(mark_channels_read_request) + path = '/api/v2/chat/channels/read' + # Build request body + body = mark_channels_read_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # This Method creates a channel or returns an existing one with matching attributesSends events:- channel.created- member.added- member.removed- member.updated- user.watching.start + # + # @param _type [String] + # @param channel_get_or_create_request [ChannelGetOrCreateRequest] + # @return [Models::ChannelStateResponse] + def get_or_create_distinct_channel(_type, channel_get_or_create_request) + path = '/api/v2/chat/channels/{type}/query' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + # Build request body + body = channel_get_or_create_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Deletes channelSends events:- channel.deleted + # + # @param _type [String] + # @param _id [String] + # @param hard_delete [Boolean] + # @return [Models::DeleteChannelResponse] + def delete_channel(_type, _id, hard_delete = nil) + path = '/api/v2/chat/channels/{type}/{id}' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build query parameters + query_params = {} + query_params['hard_delete'] = hard_delete unless hard_delete.nil? + + # Make the API request + @client.make_request( + :delete, + path, + query_params: query_params + ) + end + + # Updates certain fields of the channelSends events:- channel.updated + # + # @param _type [String] + # @param _id [String] + # @param update_channel_partial_request [UpdateChannelPartialRequest] + # @return [Models::UpdateChannelPartialResponse] + def update_channel_partial(_type, _id, update_channel_partial_request) + path = '/api/v2/chat/channels/{type}/{id}' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = update_channel_partial_request + + # Make the API request + @client.make_request( + :patch, + path, + body: body + ) + end + + # Change channel dataSends events:- channel.updated- member.added- member.removed- member.updated- message.new + # + # @param _type [String] + # @param _id [String] + # @param update_channel_request [UpdateChannelRequest] + # @return [Models::UpdateChannelResponse] + def update_channel(_type, _id, update_channel_request) + path = '/api/v2/chat/channels/{type}/{id}' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = update_channel_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Deletes a draftSends events:- draft.deleted + # + # @param _type [String] + # @param _id [String] + # @param parent_id [String] + # @param user_id [String] + # @return [Models::Response] + def delete_draft(_type, _id, parent_id = nil, user_id = nil) + path = '/api/v2/chat/channels/{type}/{id}/draft' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build query parameters + query_params = {} + query_params['parent_id'] = parent_id unless parent_id.nil? + query_params['user_id'] = user_id unless user_id.nil? + + # Make the API request + @client.make_request( + :delete, + path, + query_params: query_params + ) + end + + # Get a draft + # + # @param _type [String] + # @param _id [String] + # @param parent_id [String] + # @param user_id [String] + # @return [Models::GetDraftResponse] + def get_draft(_type, _id, parent_id = nil, user_id = nil) + path = '/api/v2/chat/channels/{type}/{id}/draft' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build query parameters + query_params = {} + query_params['parent_id'] = parent_id unless parent_id.nil? + query_params['user_id'] = user_id unless user_id.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Sends event to the channel + # + # @param _type [String] + # @param _id [String] + # @param send_event_request [SendEventRequest] + # @return [Models::EventResponse] + def send_event(_type, _id, send_event_request) + path = '/api/v2/chat/channels/{type}/{id}/event' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = send_event_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Deletes previously uploaded file + # + # @param _type [String] + # @param _id [String] + # @param url [String] + # @return [Models::Response] + def delete_channel_file(_type, _id, url = nil) + path = '/api/v2/chat/channels/{type}/{id}/file' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build query parameters + query_params = {} + query_params['url'] = url unless url.nil? + + # Make the API request + @client.make_request( + :delete, + path, + query_params: query_params + ) + end + + # Uploads file + # + # @param _type [String] + # @param _id [String] + # @param upload_channel_file_request [UploadChannelFileRequest] + # @return [Models::UploadChannelFileResponse] + def upload_channel_file(_type, _id, upload_channel_file_request) + path = '/api/v2/chat/channels/{type}/{id}/file' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = upload_channel_file_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Marks channel as hidden for current userSends events:- channel.hidden + # + # @param _type [String] + # @param _id [String] + # @param hide_channel_request [HideChannelRequest] + # @return [Models::HideChannelResponse] + def hide_channel(_type, _id, hide_channel_request) + path = '/api/v2/chat/channels/{type}/{id}/hide' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = hide_channel_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Deletes previously uploaded image + # + # @param _type [String] + # @param _id [String] + # @param url [String] + # @return [Models::Response] + def delete_channel_image(_type, _id, url = nil) + path = '/api/v2/chat/channels/{type}/{id}/image' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build query parameters + query_params = {} + query_params['url'] = url unless url.nil? + + # Make the API request + @client.make_request( + :delete, + path, + query_params: query_params + ) + end + + # Uploads image + # + # @param _type [String] + # @param _id [String] + # @param upload_channel_request [UploadChannelRequest] + # @return [Models::UploadChannelResponse] + def upload_channel_image(_type, _id, upload_channel_request) + path = '/api/v2/chat/channels/{type}/{id}/image' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = upload_channel_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # + # + # @param _type [String] + # @param _id [String] + # @param update_member_partial_request [UpdateMemberPartialRequest] + # @param user_id [String] + # @return [Models::UpdateMemberPartialResponse] + def update_member_partial(_type, _id, update_member_partial_request, user_id = nil) + path = '/api/v2/chat/channels/{type}/{id}/member' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build query parameters + query_params = {} + query_params['user_id'] = user_id unless user_id.nil? + # Build request body + body = update_member_partial_request + + # Make the API request + @client.make_request( + :patch, + path, + query_params: query_params, + body: body + ) + end + + # Sends new message to the specified channelSends events:- message.new- message.updated + # + # @param _type [String] + # @param _id [String] + # @param send_message_request [SendMessageRequest] + # @return [Models::SendMessageResponse] + def send_message(_type, _id, send_message_request) + path = '/api/v2/chat/channels/{type}/{id}/message' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = send_message_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Returns list messages found by IDs + # + # @param _type [String] + # @param _id [String] + # @param ids [Array] + # @return [Models::GetManyMessagesResponse] + def get_many_messages(_type, _id, ids) + path = '/api/v2/chat/channels/{type}/{id}/messages' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build query parameters + query_params = {} + query_params['ids'] = ids unless ids.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # This Method creates a channel or returns an existing one with matching attributesSends events:- channel.created- member.added- member.removed- member.updated- user.watching.start + # + # @param _type [String] + # @param _id [String] + # @param channel_get_or_create_request [ChannelGetOrCreateRequest] + # @return [Models::ChannelStateResponse] + def get_or_create_channel(_type, _id, channel_get_or_create_request) + path = '/api/v2/chat/channels/{type}/{id}/query' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = channel_get_or_create_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Marks channel as read up to the specific messageSends events:- message.read + # + # @param _type [String] + # @param _id [String] + # @param mark_read_request [MarkReadRequest] + # @return [Models::MarkReadResponse] + def mark_read(_type, _id, mark_read_request) + path = '/api/v2/chat/channels/{type}/{id}/read' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = mark_read_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Shows previously hidden channelSends events:- channel.visible + # + # @param _type [String] + # @param _id [String] + # @param show_channel_request [ShowChannelRequest] + # @return [Models::ShowChannelResponse] + def show_channel(_type, _id, show_channel_request) + path = '/api/v2/chat/channels/{type}/{id}/show' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = show_channel_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Truncates messages from a channel. Can be applied to the entire channel or scoped to specific members.Sends events:- channel.truncated + # + # @param _type [String] + # @param _id [String] + # @param truncate_channel_request [TruncateChannelRequest] + # @return [Models::TruncateChannelResponse] + def truncate_channel(_type, _id, truncate_channel_request) + path = '/api/v2/chat/channels/{type}/{id}/truncate' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = truncate_channel_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Marks channel as unread from a specific message + # + # @param _type [String] + # @param _id [String] + # @param mark_unread_request [MarkUnreadRequest] + # @return [Models::Response] + def mark_unread(_type, _id, mark_unread_request) + path = '/api/v2/chat/channels/{type}/{id}/unread' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = mark_unread_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Lists all available channel types + # + # @return [Models::ListChannelTypesResponse] + def list_channel_types() + path = '/api/v2/chat/channeltypes' + + # Make the API request + @client.make_request( + :get, + path + ) + end + + # Creates new channel type + # + # @param create_channel_type_request [CreateChannelTypeRequest] + # @return [Models::CreateChannelTypeResponse] + def create_channel_type(create_channel_type_request) + path = '/api/v2/chat/channeltypes' + # Build request body + body = create_channel_type_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Deletes channel type + # + # @param name [String] + # @return [Models::Response] + def delete_channel_type(name) + path = '/api/v2/chat/channeltypes/{name}' + # Replace path parameters + path = path.gsub('{name}', name.to_s) + + # Make the API request + @client.make_request( + :delete, + path + ) + end + + # Gets channel type + # + # @param name [String] + # @return [Models::GetChannelTypeResponse] + def get_channel_type(name) + path = '/api/v2/chat/channeltypes/{name}' + # Replace path parameters + path = path.gsub('{name}', name.to_s) + + # Make the API request + @client.make_request( + :get, + path + ) + end + + # Updates channel type + # + # @param name [String] + # @param update_channel_type_request [UpdateChannelTypeRequest] + # @return [Models::UpdateChannelTypeResponse] + def update_channel_type(name, update_channel_type_request) + path = '/api/v2/chat/channeltypes/{name}' + # Replace path parameters + path = path.gsub('{name}', name.to_s) + # Build request body + body = update_channel_type_request + + # Make the API request + @client.make_request( + :put, + path, + body: body + ) + end + + # Returns all custom commands + # + # @return [Models::ListCommandsResponse] + def list_commands() + path = '/api/v2/chat/commands' + + # Make the API request + @client.make_request( + :get, + path + ) + end + + # Creates custom chat command + # + # @param create_command_request [CreateCommandRequest] + # @return [Models::CreateCommandResponse] + def create_command(create_command_request) + path = '/api/v2/chat/commands' + # Build request body + body = create_command_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Deletes custom chat command + # + # @param name [String] + # @return [Models::DeleteCommandResponse] + def delete_command(name) + path = '/api/v2/chat/commands/{name}' + # Replace path parameters + path = path.gsub('{name}', name.to_s) + + # Make the API request + @client.make_request( + :delete, + path + ) + end + + # Returns custom command by its name + # + # @param name [String] + # @return [Models::GetCommandResponse] + def get_command(name) + path = '/api/v2/chat/commands/{name}' + # Replace path parameters + path = path.gsub('{name}', name.to_s) + + # Make the API request + @client.make_request( + :get, + path + ) + end + + # Updates custom chat command + # + # @param name [String] + # @param update_command_request [UpdateCommandRequest] + # @return [Models::UpdateCommandResponse] + def update_command(name, update_command_request) + path = '/api/v2/chat/commands/{name}' + # Replace path parameters + path = path.gsub('{name}', name.to_s) + # Build request body + body = update_command_request + + # Make the API request + @client.make_request( + :put, + path, + body: body + ) + end + + # Queries draft messages for a user + # + # @param query_drafts_request [QueryDraftsRequest] + # @return [Models::QueryDraftsResponse] + def query_drafts(query_drafts_request) + path = '/api/v2/chat/drafts/query' + # Build request body + body = query_drafts_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Exports channel data to JSON file + # + # @param export_channels_request [ExportChannelsRequest] + # @return [Models::ExportChannelsResponse] + def export_channels(export_channels_request) + path = '/api/v2/chat/export_channels' + # Build request body + body = export_channels_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Find and filter channel members + # + # @param payload [QueryMembersPayload] + # @return [Models::MembersResponse] + def query_members(payload = nil) + path = '/api/v2/chat/members' + # Build query parameters + query_params = {} + query_params['payload'] = payload unless payload.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Queries history for one message + # + # @param query_message_history_request [QueryMessageHistoryRequest] + # @return [Models::QueryMessageHistoryResponse] + def query_message_history(query_message_history_request) + path = '/api/v2/chat/messages/history' + # Build request body + body = query_message_history_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Deletes messageSends events:- message.deleted + # + # @param _id [String] + # @param hard [Boolean] + # @param deleted_by [String] + # @param delete_for_me [Boolean] + # @return [Models::DeleteMessageResponse] + def delete_message(_id, hard = nil, deleted_by = nil, delete_for_me = nil) + path = '/api/v2/chat/messages/{id}' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build query parameters + query_params = {} + query_params['hard'] = hard unless hard.nil? + query_params['deleted_by'] = deleted_by unless deleted_by.nil? + query_params['delete_for_me'] = delete_for_me unless delete_for_me.nil? + + # Make the API request + @client.make_request( + :delete, + path, + query_params: query_params + ) + end + + # Returns message by ID + # + # @param _id [String] + # @param show_deleted_message [Boolean] + # @return [Models::GetMessageResponse] + def get_message(_id, show_deleted_message = nil) + path = '/api/v2/chat/messages/{id}' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build query parameters + query_params = {} + query_params['show_deleted_message'] = show_deleted_message unless show_deleted_message.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Updates message with new dataSends events:- message.updated + # + # @param _id [String] + # @param update_message_request [UpdateMessageRequest] + # @return [Models::UpdateMessageResponse] + def update_message(_id, update_message_request) + path = '/api/v2/chat/messages/{id}' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = update_message_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Updates certain fields of the messageSends events:- message.updated + # + # @param _id [String] + # @param update_message_partial_request [UpdateMessagePartialRequest] + # @return [Models::UpdateMessagePartialResponse] + def update_message_partial(_id, update_message_partial_request) + path = '/api/v2/chat/messages/{id}' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = update_message_partial_request + + # Make the API request + @client.make_request( + :put, + path, + body: body + ) + end + + # Executes message command action with given parametersSends events:- message.new + # + # @param _id [String] + # @param message_action_request [MessageActionRequest] + # @return [Models::MessageActionResponse] + def run_message_action(_id, message_action_request) + path = '/api/v2/chat/messages/{id}/action' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = message_action_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Commits a pending message, which will make it visible in the channelSends events:- message.new- message.updated + # + # @param _id [String] + # @param commit_message_request [CommitMessageRequest] + # @return [Models::MessageActionResponse] + def commit_message(_id, commit_message_request) + path = '/api/v2/chat/messages/{id}/commit' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = commit_message_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Updates message fields without storing in database, only sends update eventSends events:- message.updated + # + # @param _id [String] + # @param update_message_partial_request [UpdateMessagePartialRequest] + # @return [Models::UpdateMessagePartialResponse] + def ephemeral_message_update(_id, update_message_partial_request) + path = '/api/v2/chat/messages/{id}/ephemeral' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = update_message_partial_request + + # Make the API request + @client.make_request( + :patch, + path, + body: body + ) + end + + # Sends reaction to specified messageSends events:- reaction.new- reaction.updated + # + # @param _id [String] + # @param send_reaction_request [SendReactionRequest] + # @return [Models::SendReactionResponse] + def send_reaction(_id, send_reaction_request) + path = '/api/v2/chat/messages/{id}/reaction' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = send_reaction_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Removes user reaction from the messageSends events:- reaction.deleted + # + # @param _id [String] + # @param _type [String] + # @param user_id [String] + # @return [Models::DeleteReactionResponse] + def delete_reaction(_id, _type, user_id = nil) + path = '/api/v2/chat/messages/{id}/reaction/{type}' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + path = path.gsub('{type}', _type.to_s) + # Build query parameters + query_params = {} + query_params['user_id'] = user_id unless user_id.nil? + + # Make the API request + @client.make_request( + :delete, + path, + query_params: query_params + ) + end + + # Returns list of reactions of specific message + # + # @param _id [String] + # @param limit [Integer] + # @param offset [Integer] + # @return [Models::GetReactionsResponse] + def get_reactions(_id, limit = nil, offset = nil) + path = '/api/v2/chat/messages/{id}/reactions' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build query parameters + query_params = {} + query_params['limit'] = limit unless limit.nil? + query_params['offset'] = offset unless offset.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Get reactions on a message + # + # @param _id [String] + # @param query_reactions_request [QueryReactionsRequest] + # @return [Models::QueryReactionsResponse] + def query_reactions(_id, query_reactions_request) + path = '/api/v2/chat/messages/{id}/reactions' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = query_reactions_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Translates message to a given language using automated translation softwareSends events:- message.updated + # + # @param _id [String] + # @param translate_message_request [TranslateMessageRequest] + # @return [Models::MessageActionResponse] + def translate_message(_id, translate_message_request) + path = '/api/v2/chat/messages/{id}/translate' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = translate_message_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Undelete a message that was previously soft-deletedSends events:- message.undeleted + # + # @param _id [String] + # @param undelete_message_request [UndeleteMessageRequest] + # @return [Models::UndeleteMessageResponse] + def undelete_message(_id, undelete_message_request) + path = '/api/v2/chat/messages/{id}/undelete' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = undelete_message_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Cast a vote on a pollSends events:- feeds.poll.vote_casted- feeds.poll.vote_changed- feeds.poll.vote_removed- poll.vote_casted- poll.vote_changed- poll.vote_removed + # + # @param message_id [String] + # @param poll_id [String] + # @param cast_poll_vote_request [CastPollVoteRequest] + # @return [Models::PollVoteResponse] + def cast_poll_vote(message_id, poll_id, cast_poll_vote_request) + path = '/api/v2/chat/messages/{message_id}/polls/{poll_id}/vote' + # Replace path parameters + path = path.gsub('{message_id}', message_id.to_s) + path = path.gsub('{poll_id}', poll_id.to_s) + # Build request body + body = cast_poll_vote_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Delete a vote from a pollSends events:- feeds.poll.vote_removed- poll.vote_removed + # + # @param message_id [String] + # @param poll_id [String] + # @param vote_id [String] + # @param user_id [String] + # @return [Models::PollVoteResponse] + def delete_poll_vote(message_id, poll_id, vote_id, user_id = nil) + path = '/api/v2/chat/messages/{message_id}/polls/{poll_id}/vote/{vote_id}' + # Replace path parameters + path = path.gsub('{message_id}', message_id.to_s) + path = path.gsub('{poll_id}', poll_id.to_s) + path = path.gsub('{vote_id}', vote_id.to_s) + # Build query parameters + query_params = {} + query_params['user_id'] = user_id unless user_id.nil? + + # Make the API request + @client.make_request( + :delete, + path, + query_params: query_params + ) + end + + # Deletes a user's created reminderSends events:- reminder.deleted + # + # @param message_id [String] + # @param user_id [String] + # @return [Models::DeleteReminderResponse] + def delete_reminder(message_id, user_id = nil) + path = '/api/v2/chat/messages/{message_id}/reminders' + # Replace path parameters + path = path.gsub('{message_id}', message_id.to_s) + # Build query parameters + query_params = {} + query_params['user_id'] = user_id unless user_id.nil? + + # Make the API request + @client.make_request( + :delete, + path, + query_params: query_params + ) + end + + # Updates an existing reminderSends events:- reminder.updated + # + # @param message_id [String] + # @param update_reminder_request [UpdateReminderRequest] + # @return [Models::UpdateReminderResponse] + def update_reminder(message_id, update_reminder_request) + path = '/api/v2/chat/messages/{message_id}/reminders' + # Replace path parameters + path = path.gsub('{message_id}', message_id.to_s) + # Build request body + body = update_reminder_request + + # Make the API request + @client.make_request( + :patch, + path, + body: body + ) + end + + # Creates a new reminderSends events:- reminder.created + # + # @param message_id [String] + # @param create_reminder_request [CreateReminderRequest] + # @return [Models::ReminderResponseData] + def create_reminder(message_id, create_reminder_request) + path = '/api/v2/chat/messages/{message_id}/reminders' + # Replace path parameters + path = path.gsub('{message_id}', message_id.to_s) + # Build request body + body = create_reminder_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Returns replies (thread) of the message + # + # @param parent_id [String] + # @param limit [Integer] + # @param id_gte [String] + # @param id_gt [String] + # @param id_lte [String] + # @param id_lt [String] + # @param id_around [String] + # @param sort [Array] + # @return [Models::GetRepliesResponse] + def get_replies(parent_id, limit = nil, id_gte = nil, id_gt = nil, id_lte = nil, id_lt = nil, id_around = nil, sort = nil) + path = '/api/v2/chat/messages/{parent_id}/replies' + # Replace path parameters + path = path.gsub('{parent_id}', parent_id.to_s) + # Build query parameters + query_params = {} + query_params['limit'] = limit unless limit.nil? + query_params['id_gte'] = id_gte unless id_gte.nil? + query_params['id_gt'] = id_gt unless id_gt.nil? + query_params['id_lte'] = id_lte unless id_lte.nil? + query_params['id_lt'] = id_lt unless id_lt.nil? + query_params['id_around'] = id_around unless id_around.nil? + query_params['sort'] = sort unless sort.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Find and filter message flags + # + # @param payload [QueryMessageFlagsPayload] + # @return [Models::QueryMessageFlagsResponse] + def query_message_flags(payload = nil) + path = '/api/v2/chat/moderation/flags/message' + # Build query parameters + query_params = {} + query_params['payload'] = payload unless payload.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Mutes channel for userSends events:- channel.muted + # + # @param mute_channel_request [MuteChannelRequest] + # @return [Models::MuteChannelResponse] + def mute_channel(mute_channel_request) + path = '/api/v2/chat/moderation/mute/channel' + # Build request body + body = mute_channel_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Unmutes channel for userSends events:- channel.unmuted + # + # @param unmute_channel_request [UnmuteChannelRequest] + # @return [Models::UnmuteResponse] + def unmute_channel(unmute_channel_request) + path = '/api/v2/chat/moderation/unmute/channel' + # Build request body + body = unmute_channel_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Find and filter channel scoped or global user bans + # + # @param payload [QueryBannedUsersPayload] + # @return [Models::QueryBannedUsersResponse] + def query_banned_users(payload = nil) + path = '/api/v2/chat/query_banned_users' + # Build query parameters + query_params = {} + query_params['payload'] = payload unless payload.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Find and filter future channel bans created by the authenticated user + # + # @param payload [QueryFutureChannelBansPayload] + # @return [Models::QueryFutureChannelBansResponse] + def query_future_channel_bans(payload = nil) + path = '/api/v2/chat/query_future_channel_bans' + # Build query parameters + query_params = {} + query_params['payload'] = payload unless payload.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Queries reminders + # + # @param query_reminders_request [QueryRemindersRequest] + # @return [Models::QueryRemindersResponse] + def query_reminders(query_reminders_request) + path = '/api/v2/chat/reminders/query' + # Build request body + body = query_reminders_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Search messages across channels + # + # @param payload [SearchPayload] + # @return [Models::SearchResponse] + def search(payload = nil) + path = '/api/v2/chat/search' + # Build query parameters + query_params = {} + query_params['payload'] = payload unless payload.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Query segments + # + # @param query_segments_request [QuerySegmentsRequest] + # @return [Models::QuerySegmentsResponse] + def query_segments(query_segments_request) + path = '/api/v2/chat/segments/query' + # Build request body + body = query_segments_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Delete a segment + # + # @param _id [String] + # @return [Models::Response] + def delete_segment(_id) + path = '/api/v2/chat/segments/{id}' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + + # Make the API request + @client.make_request( + :delete, + path + ) + end + + # Get segment + # + # @param _id [String] + # @return [Models::GetSegmentResponse] + def get_segment(_id) + path = '/api/v2/chat/segments/{id}' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + + # Make the API request + @client.make_request( + :get, + path + ) + end + + # Delete targets from a segment + # + # @param _id [String] + # @param delete_segment_targets_request [DeleteSegmentTargetsRequest] + # @return [Models::Response] + def delete_segment_targets(_id, delete_segment_targets_request) + path = '/api/v2/chat/segments/{id}/deletetargets' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = delete_segment_targets_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Check whether a target exists in a segment. Returns 200 if the target exists, 404 otherwise + # + # @param _id [String] + # @param target_id [String] + # @return [Models::Response] + def segment_target_exists(_id, target_id) + path = '/api/v2/chat/segments/{id}/target/{target_id}' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + path = path.gsub('{target_id}', target_id.to_s) + + # Make the API request + @client.make_request( + :get, + path + ) + end + + # Query segment targets + # + # @param _id [String] + # @param query_segment_targets_request [QuerySegmentTargetsRequest] + # @return [Models::QuerySegmentTargetsResponse] + def query_segment_targets(_id, query_segment_targets_request) + path = '/api/v2/chat/segments/{id}/targets/query' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = query_segment_targets_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Retrieve team-level usage statistics from the warehouse database.Returns all 16 metrics grouped by team with cursor-based pagination.**Date Range Options (mutually exclusive):**- Use 'month' parameter (YYYY-MM format) for monthly aggregated values- Use 'start_date'/'end_date' parameters (YYYY-MM-DD format) for daily breakdown- If neither provided, defaults to current month (monthly mode)This endpoint is server-side only. + # + # @param query_team_usage_stats_request [QueryTeamUsageStatsRequest] + # @return [Models::QueryTeamUsageStatsResponse] + def query_team_usage_stats(query_team_usage_stats_request) + path = '/api/v2/chat/stats/team_usage' + # Build request body + body = query_team_usage_stats_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Returns the list of threads for specific user + # + # @param query_threads_request [QueryThreadsRequest] + # @return [Models::QueryThreadsResponse] + def query_threads(query_threads_request) + path = '/api/v2/chat/threads' + # Build request body + body = query_threads_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Return a specific thread + # + # @param message_id [String] + # @param reply_limit [Integer] + # @param participant_limit [Integer] + # @param member_limit [Integer] + # @return [Models::GetThreadResponse] + def get_thread(message_id, reply_limit = nil, participant_limit = nil, member_limit = nil) + path = '/api/v2/chat/threads/{message_id}' + # Replace path parameters + path = path.gsub('{message_id}', message_id.to_s) + # Build query parameters + query_params = {} + query_params['reply_limit'] = reply_limit unless reply_limit.nil? + query_params['participant_limit'] = participant_limit unless participant_limit.nil? + query_params['member_limit'] = member_limit unless member_limit.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Updates certain fields of the threadSends events:- thread.updated + # + # @param message_id [String] + # @param update_thread_partial_request [UpdateThreadPartialRequest] + # @return [Models::UpdateThreadPartialResponse] + def update_thread_partial(message_id, update_thread_partial_request) + path = '/api/v2/chat/threads/{message_id}' + # Replace path parameters + path = path.gsub('{message_id}', message_id.to_s) + # Build request body + body = update_thread_partial_request + + # Make the API request + @client.make_request( + :patch, + path, + body: body + ) + end + + # Fetch unread counts for a single user + # + # @param user_id [String] + # @return [Models::WrappedUnreadCountsResponse] + def unread_counts(user_id = nil) + path = '/api/v2/chat/unread' + # Build query parameters + query_params = {} + query_params['user_id'] = user_id unless user_id.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Fetch unread counts in batch for multiple users in one call + # + # @param unread_counts_batch_request [UnreadCountsBatchRequest] + # @return [Models::UnreadCountsBatchResponse] + def unread_counts_batch(unread_counts_batch_request) + path = '/api/v2/chat/unread_batch' + # Build request body + body = unread_counts_batch_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Sends a custom event to a userSends events:- * + # + # @param user_id [String] + # @param send_user_custom_event_request [SendUserCustomEventRequest] + # @return [Models::Response] + def send_user_custom_event(user_id, send_user_custom_event_request) + path = '/api/v2/chat/users/{user_id}/event' + # Replace path parameters + path = path.gsub('{user_id}', user_id.to_s) + # Build request body + body = send_user_custom_event_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + end + end +end \ No newline at end of file diff --git a/lib/getstream_ruby/generated/common_client.rb b/lib/getstream_ruby/generated/common_client.rb index 475ab20..ef4fffb 100644 --- a/lib/getstream_ruby/generated/common_client.rb +++ b/lib/getstream_ruby/generated/common_client.rb @@ -1027,6 +1027,175 @@ def upload_image(image_upload_request) ) end + # Lists user groups with cursor-based pagination + # + # @param limit [Integer] + # @param id_gt [String] + # @param created_at_gt [String] + # @param team_id [String] + # @return [Models::ListUserGroupsResponse] + def list_user_groups(limit = nil, id_gt = nil, created_at_gt = nil, team_id = nil) + path = '/api/v2/usergroups' + # Build query parameters + query_params = {} + query_params['limit'] = limit unless limit.nil? + query_params['id_gt'] = id_gt unless id_gt.nil? + query_params['created_at_gt'] = created_at_gt unless created_at_gt.nil? + query_params['team_id'] = team_id unless team_id.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Creates a new user group, optionally with initial members + # + # @param create_user_group_request [CreateUserGroupRequest] + # @return [Models::CreateUserGroupResponse] + def create_user_group(create_user_group_request) + path = '/api/v2/usergroups' + # Build request body + body = create_user_group_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Searches user groups by name prefix for autocomplete + # + # @param query [String] + # @param limit [Integer] + # @param name_gt [String] + # @param id_gt [String] + # @param team_id [String] + # @return [Models::SearchUserGroupsResponse] + def search_user_groups(query, limit = nil, name_gt = nil, id_gt = nil, team_id = nil) + path = '/api/v2/usergroups/search' + # Build query parameters + query_params = {} + query_params['query'] = query unless query.nil? + query_params['limit'] = limit unless limit.nil? + query_params['name_gt'] = name_gt unless name_gt.nil? + query_params['id_gt'] = id_gt unless id_gt.nil? + query_params['team_id'] = team_id unless team_id.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Deletes a user group and all its members + # + # @param _id [String] + # @param team_id [String] + # @return [Models::Response] + def delete_user_group(_id, team_id = nil) + path = '/api/v2/usergroups/{id}' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build query parameters + query_params = {} + query_params['team_id'] = team_id unless team_id.nil? + + # Make the API request + @client.make_request( + :delete, + path, + query_params: query_params + ) + end + + # Gets a user group by ID, including its members + # + # @param _id [String] + # @param team_id [String] + # @return [Models::GetUserGroupResponse] + def get_user_group(_id, team_id = nil) + path = '/api/v2/usergroups/{id}' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build query parameters + query_params = {} + query_params['team_id'] = team_id unless team_id.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Updates a user group's name and/or description. team_id is immutable. + # + # @param _id [String] + # @param update_user_group_request [UpdateUserGroupRequest] + # @return [Models::UpdateUserGroupResponse] + def update_user_group(_id, update_user_group_request) + path = '/api/v2/usergroups/{id}' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = update_user_group_request + + # Make the API request + @client.make_request( + :put, + path, + body: body + ) + end + + # Adds members to a user group. All user IDs must exist. The operation is all-or-nothing. + # + # @param _id [String] + # @param add_user_group_members_request [AddUserGroupMembersRequest] + # @return [Models::AddUserGroupMembersResponse] + def add_user_group_members(_id, add_user_group_members_request) + path = '/api/v2/usergroups/{id}/members' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = add_user_group_members_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Removes members from a user group. Users already not in the group are silently ignored. + # + # @param _id [String] + # @param remove_user_group_members_request [RemoveUserGroupMembersRequest] + # @return [Models::RemoveUserGroupMembersResponse] + def remove_user_group_members(_id, remove_user_group_members_request) + path = '/api/v2/usergroups/{id}/members/delete' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = remove_user_group_members_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + # Find and filter users # # @param payload [QueryUsersPayload] @@ -1045,7 +1214,7 @@ def query_users(payload = nil) ) end - # Updates certain fields of the userSends events:- user.presence.changed- user.updated- user.presence.changed + # Updates certain fields of the userSends events:- user.presence.changed- user.updated # # @param update_users_partial_request [UpdateUsersPartialRequest] # @return [Models::UpdateUsersResponse] @@ -1188,7 +1357,7 @@ def update_live_location(update_live_location_request, user_id = nil) ) end - # Reactivate users in batchesSends events:- user.reactivated- user.reactivated + # Reactivate users in batchesSends events:- user.reactivated # # @param reactivate_users_request [ReactivateUsersRequest] # @return [Models::ReactivateUsersResponse] diff --git a/lib/getstream_ruby/generated/feed.rb b/lib/getstream_ruby/generated/feed.rb index 400d590..247cff9 100644 --- a/lib/getstream_ruby/generated/feed.rb +++ b/lib/getstream_ruby/generated/feed.rb @@ -60,11 +60,13 @@ def mark_activity(mark_activity_request) # Unpin an activity from a feed. This removes the pin, so the activity will no longer be displayed at the top of the feed. # # @param activity_id [String] + # @param enrich_own_fields [Boolean] # @param user_id [String] # @return [Models::UnpinActivityResponse] - def unpin_activity(activity_id, user_id = nil) + def unpin_activity(activity_id, enrich_own_fields = nil, user_id = nil) # Build query parameters query_params = {} + query_params['enrich_own_fields'] = enrich_own_fields unless enrich_own_fields.nil? query_params['user_id'] = user_id unless user_id.nil? # Delegate to the FeedsClient diff --git a/lib/getstream_ruby/generated/feeds_client.rb b/lib/getstream_ruby/generated/feeds_client.rb index 42285b7..f7a3851 100644 --- a/lib/getstream_ruby/generated/feeds_client.rb +++ b/lib/getstream_ruby/generated/feeds_client.rb @@ -80,6 +80,23 @@ def delete_activities(delete_activities_request) ) end + # Track metric events (views, clicks, impressions) for activities. Supports batching up to 100 events per request. Each event is independently rate-limited per user per activity per metric. Server-side calls must include user_id. + # + # @param track_activity_metrics_request [TrackActivityMetricsRequest] + # @return [Models::TrackActivityMetricsResponse] + def track_activity_metrics(track_activity_metrics_request) + path = '/api/v2/feeds/activities/metrics/track' + # Build request body + body = track_activity_metrics_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + # Query activities based on filters with pagination and sorting options # # @param query_activities_request [QueryActivitiesRequest] @@ -375,11 +392,15 @@ def update_activity(_id, update_activity_request) # # @param _id [String] # @param restore_activity_request [RestoreActivityRequest] + # @param enrich_own_fields [Boolean] # @return [Models::RestoreActivityResponse] - def restore_activity(_id, restore_activity_request) + def restore_activity(_id, restore_activity_request, enrich_own_fields = nil) path = '/api/v2/feeds/activities/{id}/restore' # Replace path parameters path = path.gsub('{id}', _id.to_s) + # Build query parameters + query_params = {} + query_params['enrich_own_fields'] = enrich_own_fields unless enrich_own_fields.nil? # Build request body body = restore_activity_request @@ -387,6 +408,7 @@ def restore_activity(_id, restore_activity_request) @client.make_request( :post, path, + query_params: query_params, body: body ) end @@ -481,15 +503,15 @@ def delete_collections(collection_refs) # Read collections with optional filtering by user ID and collection name. By default, users can only read their own collections. # - # @param collection_refs [Array] # @param user_id [String] + # @param collection_refs [Array] # @return [Models::ReadCollectionsResponse] - def read_collections(collection_refs, user_id = nil) + def read_collections(user_id = nil, collection_refs = nil) path = '/api/v2/feeds/collections' # Build query parameters query_params = {} - query_params['collection_refs'] = collection_refs unless collection_refs.nil? query_params['user_id'] = user_id unless user_id.nil? + query_params['collection_refs'] = collection_refs unless collection_refs.nil? # Make the API request @client.make_request( @@ -921,9 +943,10 @@ def mark_activity(feed_group_id, feed_id, mark_activity_request) # @param feed_group_id [String] # @param feed_id [String] # @param activity_id [String] + # @param enrich_own_fields [Boolean] # @param user_id [String] # @return [Models::UnpinActivityResponse] - def unpin_activity(feed_group_id, feed_id, activity_id, user_id = nil) + def unpin_activity(feed_group_id, feed_id, activity_id, enrich_own_fields = nil, user_id = nil) path = '/api/v2/feeds/feed_groups/{feed_group_id}/feeds/{feed_id}/activities/{activity_id}/pin' # Replace path parameters path = path.gsub('{feed_group_id}', feed_group_id.to_s) @@ -931,6 +954,7 @@ def unpin_activity(feed_group_id, feed_id, activity_id, user_id = nil) path = path.gsub('{activity_id}', activity_id.to_s) # Build query parameters query_params = {} + query_params['enrich_own_fields'] = enrich_own_fields unless enrich_own_fields.nil? query_params['user_id'] = user_id unless user_id.nil? # Make the API request @@ -1098,6 +1122,22 @@ def get_follow_suggestions(feed_group_id, limit = nil, user_id = nil) ) end + # Restores a soft-deleted feed group by its ID. Only clears DeletedAt in the database; no other fields are updated. + # + # @param feed_group_id [String] + # @return [Models::RestoreFeedGroupResponse] + def restore_feed_group(feed_group_id) + path = '/api/v2/feeds/feed_groups/{feed_group_id}/restore' + # Replace path parameters + path = path.gsub('{feed_group_id}', feed_group_id.to_s) + + # Make the API request + @client.make_request( + :post, + path + ) + end + # Delete a feed group by its ID. Can perform a soft delete (default) or hard delete. # # @param _id [String] @@ -1549,8 +1589,9 @@ def reject_follow(reject_follow_request) # @param source [String] # @param target [String] # @param delete_notification_activity [Boolean] + # @param enrich_own_fields [Boolean] # @return [Models::UnfollowResponse] - def unfollow(source, target, delete_notification_activity = nil) + def unfollow(source, target, delete_notification_activity = nil, enrich_own_fields = nil) path = '/api/v2/feeds/follows/{source}/{target}' # Replace path parameters path = path.gsub('{source}', source.to_s) @@ -1558,6 +1599,7 @@ def unfollow(source, target, delete_notification_activity = nil) # Build query parameters query_params = {} query_params['delete_notification_activity'] = delete_notification_activity unless delete_notification_activity.nil? + query_params['enrich_own_fields'] = enrich_own_fields unless enrich_own_fields.nil? # Make the API request @client.make_request( diff --git a/lib/getstream_ruby/generated/models/activity_response.rb b/lib/getstream_ruby/generated/models/activity_response.rb index b7cf01a..a41c872 100644 --- a/lib/getstream_ruby/generated/models/activity_response.rb +++ b/lib/getstream_ruby/generated/models/activity_response.rb @@ -105,6 +105,12 @@ class ActivityResponse < GetStream::BaseModel # @!attribute friend_reaction_count # @return [Integer] Total count of reactions from friends on this activity attr_accessor :friend_reaction_count + # @!attribute is_read + # @return [Boolean] Whether this activity has been read. Only set for feed groups with notification config (track_seen/track_read enabled). + attr_accessor :is_read + # @!attribute is_seen + # @return [Boolean] Whether this activity has been seen. Only set for feed groups with notification config (track_seen/track_read enabled). + attr_accessor :is_seen # @!attribute is_watched # @return [Boolean] attr_accessor :is_watched @@ -129,6 +135,9 @@ class ActivityResponse < GetStream::BaseModel # @!attribute location # @return [ActivityLocation] attr_accessor :location + # @!attribute metrics + # @return [Hash] + attr_accessor :metrics # @!attribute moderation # @return [ModerationV2Response] attr_accessor :moderation @@ -177,6 +186,8 @@ def initialize(attributes = {}) @edited_at = attributes[:edited_at] || attributes['edited_at'] || nil @expires_at = attributes[:expires_at] || attributes['expires_at'] || nil @friend_reaction_count = attributes[:friend_reaction_count] || attributes['friend_reaction_count'] || nil + @is_read = attributes[:is_read] || attributes['is_read'] || nil + @is_seen = attributes[:is_seen] || attributes['is_seen'] || nil @is_watched = attributes[:is_watched] || attributes['is_watched'] || nil @moderation_action = attributes[:moderation_action] || attributes['moderation_action'] || nil @selector_source = attributes[:selector_source] || attributes['selector_source'] || nil @@ -185,6 +196,7 @@ def initialize(attributes = {}) @friend_reactions = attributes[:friend_reactions] || attributes['friend_reactions'] || nil @current_feed = attributes[:current_feed] || attributes['current_feed'] || nil @location = attributes[:location] || attributes['location'] || nil + @metrics = attributes[:metrics] || attributes['metrics'] || nil @moderation = attributes[:moderation] || attributes['moderation'] || nil @notification_context = attributes[:notification_context] || attributes['notification_context'] || nil @parent = attributes[:parent] || attributes['parent'] || nil @@ -226,6 +238,8 @@ def self.json_field_mappings edited_at: 'edited_at', expires_at: 'expires_at', friend_reaction_count: 'friend_reaction_count', + is_read: 'is_read', + is_seen: 'is_seen', is_watched: 'is_watched', moderation_action: 'moderation_action', selector_source: 'selector_source', @@ -234,6 +248,7 @@ def self.json_field_mappings friend_reactions: 'friend_reactions', current_feed: 'current_feed', location: 'location', + metrics: 'metrics', moderation: 'moderation', notification_context: 'notification_context', parent: 'parent', diff --git a/lib/getstream_ruby/generated/models/add_activity_request.rb b/lib/getstream_ruby/generated/models/add_activity_request.rb index bfcbe46..348b404 100644 --- a/lib/getstream_ruby/generated/models/add_activity_request.rb +++ b/lib/getstream_ruby/generated/models/add_activity_request.rb @@ -21,6 +21,9 @@ class AddActivityRequest < GetStream::BaseModel # @!attribute create_notification_activity # @return [Boolean] Whether to create notification activities for mentioned users attr_accessor :create_notification_activity + # @!attribute enrich_own_fields + # @return [Boolean] + attr_accessor :enrich_own_fields # @!attribute expires_at # @return [String] Expiration time for the activity attr_accessor :expires_at @@ -86,6 +89,7 @@ def initialize(attributes = {}) @feeds = attributes[:feeds] || attributes['feeds'] @copy_custom_to_notification = attributes[:copy_custom_to_notification] || attributes['copy_custom_to_notification'] || nil @create_notification_activity = attributes[:create_notification_activity] || attributes['create_notification_activity'] || nil + @enrich_own_fields = attributes[:enrich_own_fields] || attributes['enrich_own_fields'] || nil @expires_at = attributes[:expires_at] || attributes['expires_at'] || nil @id = attributes[:id] || attributes['id'] || nil @parent_id = attributes[:parent_id] || attributes['parent_id'] || nil @@ -114,6 +118,7 @@ def self.json_field_mappings feeds: 'feeds', copy_custom_to_notification: 'copy_custom_to_notification', create_notification_activity: 'create_notification_activity', + enrich_own_fields: 'enrich_own_fields', expires_at: 'expires_at', id: 'id', parent_id: 'parent_id', diff --git a/lib/getstream_ruby/generated/models/add_user_group_members_request.rb b/lib/getstream_ruby/generated/models/add_user_group_members_request.rb new file mode 100644 index 0000000..544fc5a --- /dev/null +++ b/lib/getstream_ruby/generated/models/add_user_group_members_request.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Request body for adding members to a user group + class AddUserGroupMembersRequest < GetStream::BaseModel + + # Model attributes + # @!attribute member_ids + # @return [Array] List of user IDs to add as members + attr_accessor :member_ids + # @!attribute team_id + # @return [String] + attr_accessor :team_id + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @member_ids = attributes[:member_ids] || attributes['member_ids'] + @team_id = attributes[:team_id] || attributes['team_id'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + member_ids: 'member_ids', + team_id: 'team_id' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/add_user_group_members_response.rb b/lib/getstream_ruby/generated/models/add_user_group_members_response.rb new file mode 100644 index 0000000..31f4bec --- /dev/null +++ b/lib/getstream_ruby/generated/models/add_user_group_members_response.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Response for adding members to a user group + class AddUserGroupMembersResponse < GetStream::BaseModel + + # Model attributes + # @!attribute duration + # @return [String] + attr_accessor :duration + # @!attribute user_group + # @return [UserGroupResponse] + attr_accessor :user_group + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @duration = attributes[:duration] || attributes['duration'] + @user_group = attributes[:user_group] || attributes['user_group'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + duration: 'duration', + user_group: 'user_group' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/aggregated_activity_response.rb b/lib/getstream_ruby/generated/models/aggregated_activity_response.rb index 0066528..906d96c 100644 --- a/lib/getstream_ruby/generated/models/aggregated_activity_response.rb +++ b/lib/getstream_ruby/generated/models/aggregated_activity_response.rb @@ -33,6 +33,12 @@ class AggregatedActivityResponse < GetStream::BaseModel # @!attribute activities # @return [Array] List of activities in this aggregation attr_accessor :activities + # @!attribute is_read + # @return [Boolean] Whether this aggregated group has been read. Only set for feed groups with notification config (track_seen/track_read enabled). + attr_accessor :is_read + # @!attribute is_seen + # @return [Boolean] Whether this aggregated group has been seen. Only set for feed groups with notification config (track_seen/track_read enabled). + attr_accessor :is_seen # @!attribute is_watched # @return [Boolean] attr_accessor :is_watched @@ -48,6 +54,8 @@ def initialize(attributes = {}) @user_count = attributes[:user_count] || attributes['user_count'] @user_count_truncated = attributes[:user_count_truncated] || attributes['user_count_truncated'] @activities = attributes[:activities] || attributes['activities'] + @is_read = attributes[:is_read] || attributes['is_read'] || nil + @is_seen = attributes[:is_seen] || attributes['is_seen'] || nil @is_watched = attributes[:is_watched] || attributes['is_watched'] || nil end @@ -62,6 +70,8 @@ def self.json_field_mappings user_count: 'user_count', user_count_truncated: 'user_count_truncated', activities: 'activities', + is_read: 'is_read', + is_seen: 'is_seen', is_watched: 'is_watched' } end diff --git a/lib/getstream_ruby/generated/models/app_response_fields.rb b/lib/getstream_ruby/generated/models/app_response_fields.rb index e11186f..fcf7e29 100644 --- a/lib/getstream_ruby/generated/models/app_response_fields.rb +++ b/lib/getstream_ruby/generated/models/app_response_fields.rb @@ -48,6 +48,9 @@ class AppResponseFields < GetStream::BaseModel # @!attribute max_aggregated_activities_length # @return [Integer] attr_accessor :max_aggregated_activities_length + # @!attribute moderation_audio_call_moderation_enabled + # @return [Boolean] + attr_accessor :moderation_audio_call_moderation_enabled # @!attribute moderation_enabled # @return [Boolean] attr_accessor :moderation_enabled @@ -57,6 +60,9 @@ class AppResponseFields < GetStream::BaseModel # @!attribute moderation_multitenant_blocklist_enabled # @return [Boolean] attr_accessor :moderation_multitenant_blocklist_enabled + # @!attribute moderation_video_call_moderation_enabled + # @return [Boolean] + attr_accessor :moderation_video_call_moderation_enabled # @!attribute moderation_webhook_url # @return [String] attr_accessor :moderation_webhook_url @@ -144,6 +150,9 @@ class AppResponseFields < GetStream::BaseModel # @!attribute before_message_send_hook_url # @return [String] attr_accessor :before_message_send_hook_url + # @!attribute moderation_s3_image_access_role_arn + # @return [String] + attr_accessor :moderation_s3_image_access_role_arn # @!attribute revoke_tokens_issued_before # @return [DateTime] attr_accessor :revoke_tokens_issued_before @@ -179,9 +188,11 @@ def initialize(attributes = {}) @id = attributes[:id] || attributes['id'] @image_moderation_enabled = attributes[:image_moderation_enabled] || attributes['image_moderation_enabled'] @max_aggregated_activities_length = attributes[:max_aggregated_activities_length] || attributes['max_aggregated_activities_length'] + @moderation_audio_call_moderation_enabled = attributes[:moderation_audio_call_moderation_enabled] || attributes['moderation_audio_call_moderation_enabled'] @moderation_enabled = attributes[:moderation_enabled] || attributes['moderation_enabled'] @moderation_llm_configurability_enabled = attributes[:moderation_llm_configurability_enabled] || attributes['moderation_llm_configurability_enabled'] @moderation_multitenant_blocklist_enabled = attributes[:moderation_multitenant_blocklist_enabled] || attributes['moderation_multitenant_blocklist_enabled'] + @moderation_video_call_moderation_enabled = attributes[:moderation_video_call_moderation_enabled] || attributes['moderation_video_call_moderation_enabled'] @moderation_webhook_url = attributes[:moderation_webhook_url] || attributes['moderation_webhook_url'] @multi_tenant_enabled = attributes[:multi_tenant_enabled] || attributes['multi_tenant_enabled'] @name = attributes[:name] || attributes['name'] @@ -211,6 +222,7 @@ def initialize(attributes = {}) @policies = attributes[:policies] || attributes['policies'] @push_notifications = attributes[:push_notifications] || attributes['push_notifications'] @before_message_send_hook_url = attributes[:before_message_send_hook_url] || attributes['before_message_send_hook_url'] || nil + @moderation_s3_image_access_role_arn = attributes[:moderation_s3_image_access_role_arn] || attributes['moderation_s3_image_access_role_arn'] || nil @revoke_tokens_issued_before = attributes[:revoke_tokens_issued_before] || attributes['revoke_tokens_issued_before'] || nil @allowed_flag_reasons = attributes[:allowed_flag_reasons] || attributes['allowed_flag_reasons'] || nil @geofences = attributes[:geofences] || attributes['geofences'] || nil @@ -235,9 +247,11 @@ def self.json_field_mappings id: 'id', image_moderation_enabled: 'image_moderation_enabled', max_aggregated_activities_length: 'max_aggregated_activities_length', + moderation_audio_call_moderation_enabled: 'moderation_audio_call_moderation_enabled', moderation_enabled: 'moderation_enabled', moderation_llm_configurability_enabled: 'moderation_llm_configurability_enabled', moderation_multitenant_blocklist_enabled: 'moderation_multitenant_blocklist_enabled', + moderation_video_call_moderation_enabled: 'moderation_video_call_moderation_enabled', moderation_webhook_url: 'moderation_webhook_url', multi_tenant_enabled: 'multi_tenant_enabled', name: 'name', @@ -267,6 +281,7 @@ def self.json_field_mappings policies: 'policies', push_notifications: 'push_notifications', before_message_send_hook_url: 'before_message_send_hook_url', + moderation_s3_image_access_role_arn: 'moderation_s3_image_access_role_arn', revoke_tokens_issued_before: 'revoke_tokens_issued_before', allowed_flag_reasons: 'allowed_flag_reasons', geofences: 'geofences', diff --git a/lib/getstream_ruby/generated/models/async_export_error_event.rb b/lib/getstream_ruby/generated/models/async_export_error_event.rb index e297b0e..85cf709 100644 --- a/lib/getstream_ruby/generated/models/async_export_error_event.rb +++ b/lib/getstream_ruby/generated/models/async_export_error_event.rb @@ -43,7 +43,7 @@ def initialize(attributes = {}) @started_at = attributes[:started_at] || attributes['started_at'] @task_id = attributes[:task_id] || attributes['task_id'] @custom = attributes[:custom] || attributes['custom'] - @type = attributes[:type] || attributes['type'] || "export.channels.error" + @type = attributes[:type] || attributes['type'] || "export.moderation_logs.error" @received_at = attributes[:received_at] || attributes['received_at'] || nil end diff --git a/lib/getstream_ruby/generated/models/aws_rekognition_rule.rb b/lib/getstream_ruby/generated/models/aws_rekognition_rule.rb index 93720c9..b00fe08 100644 --- a/lib/getstream_ruby/generated/models/aws_rekognition_rule.rb +++ b/lib/getstream_ruby/generated/models/aws_rekognition_rule.rb @@ -18,6 +18,9 @@ class AWSRekognitionRule < GetStream::BaseModel # @!attribute min_confidence # @return [Float] attr_accessor :min_confidence + # @!attribute subclassifications + # @return [Hash] + attr_accessor :subclassifications # Initialize with attributes def initialize(attributes = {}) @@ -25,6 +28,7 @@ def initialize(attributes = {}) @action = attributes[:action] || attributes['action'] @label = attributes[:label] || attributes['label'] @min_confidence = attributes[:min_confidence] || attributes['min_confidence'] + @subclassifications = attributes[:subclassifications] || attributes['subclassifications'] || nil end # Override field mappings for JSON serialization @@ -32,7 +36,8 @@ def self.json_field_mappings { action: 'action', label: 'label', - min_confidence: 'min_confidence' + min_confidence: 'min_confidence', + subclassifications: 'subclassifications' } end end diff --git a/lib/getstream_ruby/generated/models/block_list_config.rb b/lib/getstream_ruby/generated/models/block_list_config.rb index 349c41d..10bab6c 100644 --- a/lib/getstream_ruby/generated/models/block_list_config.rb +++ b/lib/getstream_ruby/generated/models/block_list_config.rb @@ -15,6 +15,9 @@ class BlockListConfig < GetStream::BaseModel # @!attribute enabled # @return [Boolean] attr_accessor :enabled + # @!attribute match_substring + # @return [Boolean] + attr_accessor :match_substring # @!attribute rules # @return [Array] attr_accessor :rules @@ -24,6 +27,7 @@ def initialize(attributes = {}) super(attributes) @async = attributes[:async] || attributes['async'] || nil @enabled = attributes[:enabled] || attributes['enabled'] || nil + @match_substring = attributes[:match_substring] || attributes['match_substring'] || nil @rules = attributes[:rules] || attributes['rules'] || nil end @@ -32,6 +36,7 @@ def self.json_field_mappings { async: 'async', enabled: 'enabled', + match_substring: 'match_substring', rules: 'rules' } end diff --git a/lib/getstream_ruby/generated/models/call_stats_report_ready_event.rb b/lib/getstream_ruby/generated/models/call_stats_report_ready_event.rb index f3b0310..6a0c82c 100644 --- a/lib/getstream_ruby/generated/models/call_stats_report_ready_event.rb +++ b/lib/getstream_ruby/generated/models/call_stats_report_ready_event.rb @@ -21,6 +21,12 @@ class CallStatsReportReadyEvent < GetStream::BaseModel # @!attribute type # @return [String] The type of event, "call.report_ready" in this case attr_accessor :type + # @!attribute is_trimmed + # @return [Boolean] Whether participants_overview is truncated by the server-side limit + attr_accessor :is_trimmed + # @!attribute participants_overview + # @return [Array] Top participant sessions overview + attr_accessor :participants_overview # Initialize with attributes def initialize(attributes = {}) @@ -29,6 +35,8 @@ def initialize(attributes = {}) @created_at = attributes[:created_at] || attributes['created_at'] @session_id = attributes[:session_id] || attributes['session_id'] @type = attributes[:type] || attributes['type'] || "call.stats_report_ready" + @is_trimmed = attributes[:is_trimmed] || attributes['is_trimmed'] || nil + @participants_overview = attributes[:participants_overview] || attributes['participants_overview'] || nil end # Override field mappings for JSON serialization @@ -37,7 +45,9 @@ def self.json_field_mappings call_cid: 'call_cid', created_at: 'created_at', session_id: 'session_id', - type: 'type' + type: 'type', + is_trimmed: 'is_trimmed', + participants_overview: 'participants_overview' } end end diff --git a/lib/getstream_ruby/generated/models/call_violation_count_parameters.rb b/lib/getstream_ruby/generated/models/call_violation_count_parameters.rb new file mode 100644 index 0000000..78350b6 --- /dev/null +++ b/lib/getstream_ruby/generated/models/call_violation_count_parameters.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class CallViolationCountParameters < GetStream::BaseModel + + # Model attributes + # @!attribute threshold + # @return [Integer] + attr_accessor :threshold + # @!attribute time_window + # @return [String] + attr_accessor :time_window + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @threshold = attributes[:threshold] || attributes['threshold'] || nil + @time_window = attributes[:time_window] || attributes['time_window'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + threshold: 'threshold', + time_window: 'time_window' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/channel_batch_member_request.rb b/lib/getstream_ruby/generated/models/channel_batch_member_request.rb new file mode 100644 index 0000000..8c648d2 --- /dev/null +++ b/lib/getstream_ruby/generated/models/channel_batch_member_request.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class ChannelBatchMemberRequest < GetStream::BaseModel + + # Model attributes + # @!attribute user_id + # @return [String] + attr_accessor :user_id + # @!attribute channel_role + # @return [String] + attr_accessor :channel_role + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @user_id = attributes[:user_id] || attributes['user_id'] + @channel_role = attributes[:channel_role] || attributes['channel_role'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + user_id: 'user_id', + channel_role: 'channel_role' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/channel_batch_update_request.rb b/lib/getstream_ruby/generated/models/channel_batch_update_request.rb new file mode 100644 index 0000000..00c5005 --- /dev/null +++ b/lib/getstream_ruby/generated/models/channel_batch_update_request.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class ChannelBatchUpdateRequest < GetStream::BaseModel + + # Model attributes + # @!attribute operation + # @return [String] + attr_accessor :operation + # @!attribute filter + # @return [Object] + attr_accessor :filter + # @!attribute members + # @return [Array] + attr_accessor :members + # @!attribute data + # @return [ChannelDataUpdate] + attr_accessor :data + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @operation = attributes[:operation] || attributes['operation'] + @filter = attributes[:filter] || attributes['filter'] + @members = attributes[:members] || attributes['members'] || nil + @data = attributes[:data] || attributes['data'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + operation: 'operation', + filter: 'filter', + members: 'members', + data: 'data' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/channel_batch_update_response.rb b/lib/getstream_ruby/generated/models/channel_batch_update_response.rb new file mode 100644 index 0000000..049574b --- /dev/null +++ b/lib/getstream_ruby/generated/models/channel_batch_update_response.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Basic response information + class ChannelBatchUpdateResponse < GetStream::BaseModel + + # Model attributes + # @!attribute duration + # @return [String] Duration of the request in milliseconds + attr_accessor :duration + # @!attribute task_id + # @return [String] + attr_accessor :task_id + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @duration = attributes[:duration] || attributes['duration'] + @task_id = attributes[:task_id] || attributes['task_id'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + duration: 'duration', + task_id: 'task_id' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/channel_data_update.rb b/lib/getstream_ruby/generated/models/channel_data_update.rb new file mode 100644 index 0000000..886e2c6 --- /dev/null +++ b/lib/getstream_ruby/generated/models/channel_data_update.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class ChannelDataUpdate < GetStream::BaseModel + + # Model attributes + # @!attribute auto_translation_enabled + # @return [Boolean] + attr_accessor :auto_translation_enabled + # @!attribute auto_translation_language + # @return [String] + attr_accessor :auto_translation_language + # @!attribute disabled + # @return [Boolean] + attr_accessor :disabled + # @!attribute frozen + # @return [Boolean] + attr_accessor :frozen + # @!attribute team + # @return [String] + attr_accessor :team + # @!attribute config_overrides + # @return [ChannelConfig] + attr_accessor :config_overrides + # @!attribute custom + # @return [Object] + attr_accessor :custom + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @auto_translation_enabled = attributes[:auto_translation_enabled] || attributes['auto_translation_enabled'] || nil + @auto_translation_language = attributes[:auto_translation_language] || attributes['auto_translation_language'] || nil + @disabled = attributes[:disabled] || attributes['disabled'] || nil + @frozen = attributes[:frozen] || attributes['frozen'] || nil + @team = attributes[:team] || attributes['team'] || nil + @config_overrides = attributes[:config_overrides] || attributes['config_overrides'] || nil + @custom = attributes[:custom] || attributes['custom'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + auto_translation_enabled: 'auto_translation_enabled', + auto_translation_language: 'auto_translation_language', + disabled: 'disabled', + frozen: 'frozen', + team: 'team', + config_overrides: 'config_overrides', + custom: 'custom' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/check_s3_access_request.rb b/lib/getstream_ruby/generated/models/check_s3_access_request.rb new file mode 100644 index 0000000..d08cf42 --- /dev/null +++ b/lib/getstream_ruby/generated/models/check_s3_access_request.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class CheckS3AccessRequest < GetStream::BaseModel + + # Model attributes + # @!attribute s3_url + # @return [String] Optional stream+s3:// reference to test access against + attr_accessor :s3_url + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @s3_url = attributes[:s3_url] || attributes['s3_url'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + s3_url: 's3_url' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/check_s3_access_response.rb b/lib/getstream_ruby/generated/models/check_s3_access_response.rb new file mode 100644 index 0000000..0bf1eb7 --- /dev/null +++ b/lib/getstream_ruby/generated/models/check_s3_access_response.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class CheckS3AccessResponse < GetStream::BaseModel + + # Model attributes + # @!attribute duration + # @return [String] + attr_accessor :duration + # @!attribute success + # @return [Boolean] Whether the S3 access check succeeded + attr_accessor :success + # @!attribute message + # @return [String] Descriptive message about the check result + attr_accessor :message + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @duration = attributes[:duration] || attributes['duration'] + @success = attributes[:success] || attributes['success'] + @message = attributes[:message] || attributes['message'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + duration: 'duration', + success: 'success', + message: 'message' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/config_response.rb b/lib/getstream_ruby/generated/models/config_response.rb index f590f1a..c8c1668 100644 --- a/lib/getstream_ruby/generated/models/config_response.rb +++ b/lib/getstream_ruby/generated/models/config_response.rb @@ -30,6 +30,9 @@ class ConfigResponse < GetStream::BaseModel # @!attribute ai_image_config # @return [AIImageConfig] attr_accessor :ai_image_config + # @!attribute ai_image_subclassifications + # @return [Hash>] Available L2 subclassifications per L1 image moderation label, based on the active provider + attr_accessor :ai_image_subclassifications # @!attribute ai_text_config # @return [AITextConfig] attr_accessor :ai_text_config @@ -68,6 +71,7 @@ def initialize(attributes = {}) @updated_at = attributes[:updated_at] || attributes['updated_at'] @supported_video_call_harm_types = attributes[:supported_video_call_harm_types] || attributes['supported_video_call_harm_types'] @ai_image_config = attributes[:ai_image_config] || attributes['ai_image_config'] || nil + @ai_image_subclassifications = attributes[:ai_image_subclassifications] || attributes['ai_image_subclassifications'] || nil @ai_text_config = attributes[:ai_text_config] || attributes['ai_text_config'] || nil @ai_video_config = attributes[:ai_video_config] || attributes['ai_video_config'] || nil @automod_platform_circumvention_config = attributes[:automod_platform_circumvention_config] || attributes['automod_platform_circumvention_config'] || nil @@ -89,6 +93,7 @@ def self.json_field_mappings updated_at: 'updated_at', supported_video_call_harm_types: 'supported_video_call_harm_types', ai_image_config: 'ai_image_config', + ai_image_subclassifications: 'ai_image_subclassifications', ai_text_config: 'ai_text_config', ai_video_config: 'ai_video_config', automod_platform_circumvention_config: 'automod_platform_circumvention_config', diff --git a/lib/getstream_ruby/generated/models/create_feeds_batch_request.rb b/lib/getstream_ruby/generated/models/create_feeds_batch_request.rb index 048ae94..5faed1f 100644 --- a/lib/getstream_ruby/generated/models/create_feeds_batch_request.rb +++ b/lib/getstream_ruby/generated/models/create_feeds_batch_request.rb @@ -12,17 +12,22 @@ class CreateFeedsBatchRequest < GetStream::BaseModel # @!attribute feeds # @return [Array] List of feeds to create attr_accessor :feeds + # @!attribute enrich_own_fields + # @return [Boolean] If true, enriches the created feeds with own_* fields (own_follows, own_followings, own_capabilities, own_membership). Defaults to false for performance. + attr_accessor :enrich_own_fields # Initialize with attributes def initialize(attributes = {}) super(attributes) @feeds = attributes[:feeds] || attributes['feeds'] + @enrich_own_fields = attributes[:enrich_own_fields] || attributes['enrich_own_fields'] || nil end # Override field mappings for JSON serialization def self.json_field_mappings { - feeds: 'feeds' + feeds: 'feeds', + enrich_own_fields: 'enrich_own_fields' } end end diff --git a/lib/getstream_ruby/generated/models/create_import_request.rb b/lib/getstream_ruby/generated/models/create_import_request.rb index 5586f27..88849bb 100644 --- a/lib/getstream_ruby/generated/models/create_import_request.rb +++ b/lib/getstream_ruby/generated/models/create_import_request.rb @@ -15,19 +15,24 @@ class CreateImportRequest < GetStream::BaseModel # @!attribute path # @return [String] attr_accessor :path + # @!attribute merge_custom + # @return [Boolean] + attr_accessor :merge_custom # Initialize with attributes def initialize(attributes = {}) super(attributes) @mode = attributes[:mode] || attributes['mode'] @path = attributes[:path] || attributes['path'] + @merge_custom = attributes[:merge_custom] || attributes['merge_custom'] || nil end # Override field mappings for JSON serialization def self.json_field_mappings { mode: 'mode', - path: 'path' + path: 'path', + merge_custom: 'merge_custom' } end end diff --git a/lib/getstream_ruby/generated/models/create_user_group_request.rb b/lib/getstream_ruby/generated/models/create_user_group_request.rb new file mode 100644 index 0000000..cd00dee --- /dev/null +++ b/lib/getstream_ruby/generated/models/create_user_group_request.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Request body for creating a user group + class CreateUserGroupRequest < GetStream::BaseModel + + # Model attributes + # @!attribute name + # @return [String] The user friendly name of the user group + attr_accessor :name + # @!attribute description + # @return [String] An optional description for the group + attr_accessor :description + # @!attribute id + # @return [String] Optional user group ID. If not provided, a UUID v7 will be generated + attr_accessor :id + # @!attribute team_id + # @return [String] Optional team ID to scope the group to a team + attr_accessor :team_id + # @!attribute member_ids + # @return [Array] Optional initial list of user IDs to add as members + attr_accessor :member_ids + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @name = attributes[:name] || attributes['name'] + @description = attributes[:description] || attributes['description'] || nil + @id = attributes[:id] || attributes['id'] || nil + @team_id = attributes[:team_id] || attributes['team_id'] || nil + @member_ids = attributes[:member_ids] || attributes['member_ids'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + name: 'name', + description: 'description', + id: 'id', + team_id: 'team_id', + member_ids: 'member_ids' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/create_user_group_response.rb b/lib/getstream_ruby/generated/models/create_user_group_response.rb new file mode 100644 index 0000000..4b664dc --- /dev/null +++ b/lib/getstream_ruby/generated/models/create_user_group_response.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Response for creating a user group + class CreateUserGroupResponse < GetStream::BaseModel + + # Model attributes + # @!attribute duration + # @return [String] + attr_accessor :duration + # @!attribute user_group + # @return [UserGroupResponse] + attr_accessor :user_group + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @duration = attributes[:duration] || attributes['duration'] + @user_group = attributes[:user_group] || attributes['user_group'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + duration: 'duration', + user_group: 'user_group' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/daily_value.rb b/lib/getstream_ruby/generated/models/daily_value.rb new file mode 100644 index 0000000..297fd19 --- /dev/null +++ b/lib/getstream_ruby/generated/models/daily_value.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Metric value for a specific date + class DailyValue < GetStream::BaseModel + + # Model attributes + # @!attribute date + # @return [String] Date in YYYY-MM-DD format + attr_accessor :date + # @!attribute value + # @return [Integer] Metric value for this date + attr_accessor :value + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @date = attributes[:date] || attributes['date'] + @value = attributes[:value] || attributes['value'] + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + date: 'date', + value: 'value' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_activity_reaction_request.rb b/lib/getstream_ruby/generated/models/delete_activity_reaction_request.rb new file mode 100644 index 0000000..41cc2de --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_activity_reaction_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteActivityReactionRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_activity_request.rb b/lib/getstream_ruby/generated/models/delete_activity_request.rb index ead5dde..fbb30d1 100644 --- a/lib/getstream_ruby/generated/models/delete_activity_request.rb +++ b/lib/getstream_ruby/generated/models/delete_activity_request.rb @@ -7,29 +7,7 @@ module Generated module Models # class DeleteActivityRequest < GetStream::BaseModel - - # Model attributes - # @!attribute hard_delete - # @return [Boolean] - attr_accessor :hard_delete - # @!attribute reason - # @return [String] - attr_accessor :reason - - # Initialize with attributes - def initialize(attributes = {}) - super(attributes) - @hard_delete = attributes[:hard_delete] || attributes['hard_delete'] || nil - @reason = attributes[:reason] || attributes['reason'] || nil - end - - # Override field mappings for JSON serialization - def self.json_field_mappings - { - hard_delete: 'hard_delete', - reason: 'reason' - } - end + # Empty model - inherits all functionality from BaseModel end end end diff --git a/lib/getstream_ruby/generated/models/delete_activity_request_payload.rb b/lib/getstream_ruby/generated/models/delete_activity_request_payload.rb index 610fc58..35ad713 100644 --- a/lib/getstream_ruby/generated/models/delete_activity_request_payload.rb +++ b/lib/getstream_ruby/generated/models/delete_activity_request_payload.rb @@ -9,6 +9,12 @@ module Models class DeleteActivityRequestPayload < GetStream::BaseModel # Model attributes + # @!attribute entity_id + # @return [String] ID of the activity to delete (alternative to item_id) + attr_accessor :entity_id + # @!attribute entity_type + # @return [String] Type of the entity (required for delete_activity to distinguish v2 vs v3) + attr_accessor :entity_type # @!attribute hard_delete # @return [Boolean] Whether to permanently delete the activity attr_accessor :hard_delete @@ -19,6 +25,8 @@ class DeleteActivityRequestPayload < GetStream::BaseModel # Initialize with attributes def initialize(attributes = {}) super(attributes) + @entity_id = attributes[:entity_id] || attributes['entity_id'] || nil + @entity_type = attributes[:entity_type] || attributes['entity_type'] || nil @hard_delete = attributes[:hard_delete] || attributes['hard_delete'] || nil @reason = attributes[:reason] || attributes['reason'] || nil end @@ -26,6 +34,8 @@ def initialize(attributes = {}) # Override field mappings for JSON serialization def self.json_field_mappings { + entity_id: 'entity_id', + entity_type: 'entity_type', hard_delete: 'hard_delete', reason: 'reason' } diff --git a/lib/getstream_ruby/generated/models/delete_block_list_request.rb b/lib/getstream_ruby/generated/models/delete_block_list_request.rb new file mode 100644 index 0000000..6b11a21 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_block_list_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteBlockListRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_bookmark_folder_request.rb b/lib/getstream_ruby/generated/models/delete_bookmark_folder_request.rb new file mode 100644 index 0000000..369560a --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_bookmark_folder_request.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteBookmarkFolderRequest < GetStream::BaseModel + + # Model attributes + # @!attribute user_id + # @return [String] + attr_accessor :user_id + # @!attribute user + # @return [UserRequest] + attr_accessor :user + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @user_id = attributes[:user_id] || attributes['user_id'] || nil + @user = attributes[:user] || attributes['user'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + user_id: 'user_id', + user: 'user' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_bookmark_request.rb b/lib/getstream_ruby/generated/models/delete_bookmark_request.rb new file mode 100644 index 0000000..72dfc18 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_bookmark_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteBookmarkRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_call_type_request.rb b/lib/getstream_ruby/generated/models/delete_call_type_request.rb new file mode 100644 index 0000000..dc1bfdd --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_call_type_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # DeleteCallTypeRequest is the payload for deleting a call type. + class DeleteCallTypeRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_channel_request.rb b/lib/getstream_ruby/generated/models/delete_channel_request.rb new file mode 100644 index 0000000..1d3857d --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_channel_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteChannelRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_collections_request.rb b/lib/getstream_ruby/generated/models/delete_collections_request.rb new file mode 100644 index 0000000..05d7e01 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_collections_request.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteCollectionsRequest < GetStream::BaseModel + + # Model attributes + # @!attribute user_id + # @return [String] + attr_accessor :user_id + # @!attribute user + # @return [UserRequest] + attr_accessor :user + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @user_id = attributes[:user_id] || attributes['user_id'] || nil + @user = attributes[:user] || attributes['user'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + user_id: 'user_id', + user: 'user' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_command_request.rb b/lib/getstream_ruby/generated/models/delete_command_request.rb new file mode 100644 index 0000000..0473634 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_command_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteCommandRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_comment_reaction_request.rb b/lib/getstream_ruby/generated/models/delete_comment_reaction_request.rb new file mode 100644 index 0000000..d99ccfb --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_comment_reaction_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteCommentReactionRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_comment_request.rb b/lib/getstream_ruby/generated/models/delete_comment_request.rb index 2b8980f..08b9685 100644 --- a/lib/getstream_ruby/generated/models/delete_comment_request.rb +++ b/lib/getstream_ruby/generated/models/delete_comment_request.rb @@ -7,29 +7,7 @@ module Generated module Models # class DeleteCommentRequest < GetStream::BaseModel - - # Model attributes - # @!attribute hard_delete - # @return [Boolean] - attr_accessor :hard_delete - # @!attribute reason - # @return [String] - attr_accessor :reason - - # Initialize with attributes - def initialize(attributes = {}) - super(attributes) - @hard_delete = attributes[:hard_delete] || attributes['hard_delete'] || nil - @reason = attributes[:reason] || attributes['reason'] || nil - end - - # Override field mappings for JSON serialization - def self.json_field_mappings - { - hard_delete: 'hard_delete', - reason: 'reason' - } - end + # Empty model - inherits all functionality from BaseModel end end end diff --git a/lib/getstream_ruby/generated/models/delete_comment_request_payload.rb b/lib/getstream_ruby/generated/models/delete_comment_request_payload.rb index 09b15e1..b9df98a 100644 --- a/lib/getstream_ruby/generated/models/delete_comment_request_payload.rb +++ b/lib/getstream_ruby/generated/models/delete_comment_request_payload.rb @@ -9,6 +9,12 @@ module Models class DeleteCommentRequestPayload < GetStream::BaseModel # Model attributes + # @!attribute entity_id + # @return [String] ID of the comment to delete (alternative to item_id) + attr_accessor :entity_id + # @!attribute entity_type + # @return [String] Type of the entity + attr_accessor :entity_type # @!attribute hard_delete # @return [Boolean] Whether to permanently delete the comment attr_accessor :hard_delete @@ -19,6 +25,8 @@ class DeleteCommentRequestPayload < GetStream::BaseModel # Initialize with attributes def initialize(attributes = {}) super(attributes) + @entity_id = attributes[:entity_id] || attributes['entity_id'] || nil + @entity_type = attributes[:entity_type] || attributes['entity_type'] || nil @hard_delete = attributes[:hard_delete] || attributes['hard_delete'] || nil @reason = attributes[:reason] || attributes['reason'] || nil end @@ -26,6 +34,8 @@ def initialize(attributes = {}) # Override field mappings for JSON serialization def self.json_field_mappings { + entity_id: 'entity_id', + entity_type: 'entity_type', hard_delete: 'hard_delete', reason: 'reason' } diff --git a/lib/getstream_ruby/generated/models/delete_custom_role_request.rb b/lib/getstream_ruby/generated/models/delete_custom_role_request.rb new file mode 100644 index 0000000..4eb0c61 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_custom_role_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteCustomRoleRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_device_request.rb b/lib/getstream_ruby/generated/models/delete_device_request.rb new file mode 100644 index 0000000..1882691 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_device_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Delete device request + class DeleteDeviceRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_draft_request.rb b/lib/getstream_ruby/generated/models/delete_draft_request.rb new file mode 100644 index 0000000..e59f9e3 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_draft_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteDraftRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_external_storage_request.rb b/lib/getstream_ruby/generated/models/delete_external_storage_request.rb new file mode 100644 index 0000000..8a19162 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_external_storage_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteExternalStorageRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_feed_group_request.rb b/lib/getstream_ruby/generated/models/delete_feed_group_request.rb new file mode 100644 index 0000000..abbf63d --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_feed_group_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteFeedGroupRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_feed_request.rb b/lib/getstream_ruby/generated/models/delete_feed_request.rb new file mode 100644 index 0000000..c9bb473 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_feed_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteFeedRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_feed_view_request.rb b/lib/getstream_ruby/generated/models/delete_feed_view_request.rb new file mode 100644 index 0000000..f88f2b8 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_feed_view_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteFeedViewRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_import_v2_task_request.rb b/lib/getstream_ruby/generated/models/delete_import_v2_task_request.rb new file mode 100644 index 0000000..2b4578f --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_import_v2_task_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteImportV2TaskRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_membership_level_request.rb b/lib/getstream_ruby/generated/models/delete_membership_level_request.rb new file mode 100644 index 0000000..21025dc --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_membership_level_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Request to delete a membership level by its UUID + class DeleteMembershipLevelRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_message_request.rb b/lib/getstream_ruby/generated/models/delete_message_request.rb index 5287f23..ac479fe 100644 --- a/lib/getstream_ruby/generated/models/delete_message_request.rb +++ b/lib/getstream_ruby/generated/models/delete_message_request.rb @@ -7,29 +7,7 @@ module Generated module Models # class DeleteMessageRequest < GetStream::BaseModel - - # Model attributes - # @!attribute hard_delete - # @return [Boolean] - attr_accessor :hard_delete - # @!attribute reason - # @return [String] - attr_accessor :reason - - # Initialize with attributes - def initialize(attributes = {}) - super(attributes) - @hard_delete = attributes[:hard_delete] || attributes['hard_delete'] || nil - @reason = attributes[:reason] || attributes['reason'] || nil - end - - # Override field mappings for JSON serialization - def self.json_field_mappings - { - hard_delete: 'hard_delete', - reason: 'reason' - } - end + # Empty model - inherits all functionality from BaseModel end end end diff --git a/lib/getstream_ruby/generated/models/delete_message_request_payload.rb b/lib/getstream_ruby/generated/models/delete_message_request_payload.rb index 14dbfc9..9a027d3 100644 --- a/lib/getstream_ruby/generated/models/delete_message_request_payload.rb +++ b/lib/getstream_ruby/generated/models/delete_message_request_payload.rb @@ -9,6 +9,12 @@ module Models class DeleteMessageRequestPayload < GetStream::BaseModel # Model attributes + # @!attribute entity_id + # @return [String] ID of the message to delete (alternative to item_id) + attr_accessor :entity_id + # @!attribute entity_type + # @return [String] Type of the entity + attr_accessor :entity_type # @!attribute hard_delete # @return [Boolean] Whether to permanently delete the message attr_accessor :hard_delete @@ -19,6 +25,8 @@ class DeleteMessageRequestPayload < GetStream::BaseModel # Initialize with attributes def initialize(attributes = {}) super(attributes) + @entity_id = attributes[:entity_id] || attributes['entity_id'] || nil + @entity_type = attributes[:entity_type] || attributes['entity_type'] || nil @hard_delete = attributes[:hard_delete] || attributes['hard_delete'] || nil @reason = attributes[:reason] || attributes['reason'] || nil end @@ -26,6 +34,8 @@ def initialize(attributes = {}) # Override field mappings for JSON serialization def self.json_field_mappings { + entity_id: 'entity_id', + entity_type: 'entity_type', hard_delete: 'hard_delete', reason: 'reason' } diff --git a/lib/getstream_ruby/generated/models/delete_moderation_config_request.rb b/lib/getstream_ruby/generated/models/delete_moderation_config_request.rb new file mode 100644 index 0000000..f8bab70 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_moderation_config_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteModerationConfigRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_moderation_template_request.rb b/lib/getstream_ruby/generated/models/delete_moderation_template_request.rb new file mode 100644 index 0000000..227ccfc --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_moderation_template_request.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteModerationTemplateRequest < GetStream::BaseModel + + # Model attributes + # @!attribute name + # @return [String] Name of the moderation template to delete + attr_accessor :name + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @name = attributes[:name] || attributes['name'] + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + name: 'name' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_poll_option_request.rb b/lib/getstream_ruby/generated/models/delete_poll_option_request.rb new file mode 100644 index 0000000..d4da82e --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_poll_option_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeletePollOptionRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_poll_request.rb b/lib/getstream_ruby/generated/models/delete_poll_request.rb new file mode 100644 index 0000000..e22bdf5 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_poll_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeletePollRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_poll_vote_request.rb b/lib/getstream_ruby/generated/models/delete_poll_vote_request.rb new file mode 100644 index 0000000..d3a3458 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_poll_vote_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeletePollVoteRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_push_provider_request.rb b/lib/getstream_ruby/generated/models/delete_push_provider_request.rb new file mode 100644 index 0000000..cecbcf1 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_push_provider_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeletePushProviderRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_reaction_request.rb b/lib/getstream_ruby/generated/models/delete_reaction_request.rb index 254105b..a571eff 100644 --- a/lib/getstream_ruby/generated/models/delete_reaction_request.rb +++ b/lib/getstream_ruby/generated/models/delete_reaction_request.rb @@ -5,31 +5,9 @@ module GetStream module Generated module Models - # + # Delete reaction request class DeleteReactionRequest < GetStream::BaseModel - - # Model attributes - # @!attribute hard_delete - # @return [Boolean] - attr_accessor :hard_delete - # @!attribute reason - # @return [String] - attr_accessor :reason - - # Initialize with attributes - def initialize(attributes = {}) - super(attributes) - @hard_delete = attributes[:hard_delete] || attributes['hard_delete'] || nil - @reason = attributes[:reason] || attributes['reason'] || nil - end - - # Override field mappings for JSON serialization - def self.json_field_mappings - { - hard_delete: 'hard_delete', - reason: 'reason' - } - end + # Empty model - inherits all functionality from BaseModel end end end diff --git a/lib/getstream_ruby/generated/models/delete_reaction_request_payload.rb b/lib/getstream_ruby/generated/models/delete_reaction_request_payload.rb index afb3968..8ae00ee 100644 --- a/lib/getstream_ruby/generated/models/delete_reaction_request_payload.rb +++ b/lib/getstream_ruby/generated/models/delete_reaction_request_payload.rb @@ -9,6 +9,12 @@ module Models class DeleteReactionRequestPayload < GetStream::BaseModel # Model attributes + # @!attribute entity_id + # @return [String] ID of the reaction to delete (alternative to item_id) + attr_accessor :entity_id + # @!attribute entity_type + # @return [String] Type of the entity + attr_accessor :entity_type # @!attribute hard_delete # @return [Boolean] Whether to permanently delete the reaction attr_accessor :hard_delete @@ -19,6 +25,8 @@ class DeleteReactionRequestPayload < GetStream::BaseModel # Initialize with attributes def initialize(attributes = {}) super(attributes) + @entity_id = attributes[:entity_id] || attributes['entity_id'] || nil + @entity_type = attributes[:entity_type] || attributes['entity_type'] || nil @hard_delete = attributes[:hard_delete] || attributes['hard_delete'] || nil @reason = attributes[:reason] || attributes['reason'] || nil end @@ -26,6 +34,8 @@ def initialize(attributes = {}) # Override field mappings for JSON serialization def self.json_field_mappings { + entity_id: 'entity_id', + entity_type: 'entity_type', hard_delete: 'hard_delete', reason: 'reason' } diff --git a/lib/getstream_ruby/generated/models/delete_recording_request.rb b/lib/getstream_ruby/generated/models/delete_recording_request.rb new file mode 100644 index 0000000..8e9951e --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_recording_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Request for DeleteRecording + class DeleteRecordingRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_reminder_request.rb b/lib/getstream_ruby/generated/models/delete_reminder_request.rb new file mode 100644 index 0000000..dfccb2f --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_reminder_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteReminderRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_segment_request.rb b/lib/getstream_ruby/generated/models/delete_segment_request.rb new file mode 100644 index 0000000..d1d7e2b --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_segment_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteSegmentRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_sip_inbound_routing_rule_request.rb b/lib/getstream_ruby/generated/models/delete_sip_inbound_routing_rule_request.rb new file mode 100644 index 0000000..78c2b86 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_sip_inbound_routing_rule_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Request to delete a SIP Inbound Routing Rule + class DeleteSIPInboundRoutingRuleRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_sip_trunk_request.rb b/lib/getstream_ruby/generated/models/delete_sip_trunk_request.rb new file mode 100644 index 0000000..3bf5d20 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_sip_trunk_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Request to delete a SIP trunk + class DeleteSIPTrunkRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_transcription_request.rb b/lib/getstream_ruby/generated/models/delete_transcription_request.rb new file mode 100644 index 0000000..c140d88 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_transcription_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # DeleteTranscriptionRequest is the payload for deleting a transcription. + class DeleteTranscriptionRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_user_group_request.rb b/lib/getstream_ruby/generated/models/delete_user_group_request.rb new file mode 100644 index 0000000..2ef9f56 --- /dev/null +++ b/lib/getstream_ruby/generated/models/delete_user_group_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class DeleteUserGroupRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/delete_user_request_payload.rb b/lib/getstream_ruby/generated/models/delete_user_request_payload.rb index 1ba276b..e25dde7 100644 --- a/lib/getstream_ruby/generated/models/delete_user_request_payload.rb +++ b/lib/getstream_ruby/generated/models/delete_user_request_payload.rb @@ -15,6 +15,12 @@ class DeleteUserRequestPayload < GetStream::BaseModel # @!attribute delete_feeds_content # @return [Boolean] Delete flagged feeds content attr_accessor :delete_feeds_content + # @!attribute entity_id + # @return [String] ID of the user to delete (alternative to item_id) + attr_accessor :entity_id + # @!attribute entity_type + # @return [String] Type of the entity + attr_accessor :entity_type # @!attribute hard_delete # @return [Boolean] Whether to permanently delete the user attr_accessor :hard_delete @@ -30,6 +36,8 @@ def initialize(attributes = {}) super(attributes) @delete_conversation_channels = attributes[:delete_conversation_channels] || attributes['delete_conversation_channels'] || nil @delete_feeds_content = attributes[:delete_feeds_content] || attributes['delete_feeds_content'] || nil + @entity_id = attributes[:entity_id] || attributes['entity_id'] || nil + @entity_type = attributes[:entity_type] || attributes['entity_type'] || nil @hard_delete = attributes[:hard_delete] || attributes['hard_delete'] || nil @mark_messages_deleted = attributes[:mark_messages_deleted] || attributes['mark_messages_deleted'] || nil @reason = attributes[:reason] || attributes['reason'] || nil @@ -40,6 +48,8 @@ def self.json_field_mappings { delete_conversation_channels: 'delete_conversation_channels', delete_feeds_content: 'delete_feeds_content', + entity_id: 'entity_id', + entity_type: 'entity_type', hard_delete: 'hard_delete', mark_messages_deleted: 'mark_messages_deleted', reason: 'reason' diff --git a/lib/getstream_ruby/generated/models/feed_group_restored_event.rb b/lib/getstream_ruby/generated/models/feed_group_restored_event.rb new file mode 100644 index 0000000..821064a --- /dev/null +++ b/lib/getstream_ruby/generated/models/feed_group_restored_event.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Emitted when a feed group is restored. + class FeedGroupRestoredEvent < GetStream::BaseModel + + # Model attributes + # @!attribute created_at + # @return [DateTime] Date/time of creation + attr_accessor :created_at + # @!attribute fid + # @return [String] + attr_accessor :fid + # @!attribute group_id + # @return [String] The ID of the feed group that was restored + attr_accessor :group_id + # @!attribute custom + # @return [Object] + attr_accessor :custom + # @!attribute type + # @return [String] The type of event: "feeds.feed_group.restored" in this case + attr_accessor :type + # @!attribute feed_visibility + # @return [String] + attr_accessor :feed_visibility + # @!attribute received_at + # @return [DateTime] + attr_accessor :received_at + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @created_at = attributes[:created_at] || attributes['created_at'] + @fid = attributes[:fid] || attributes['fid'] + @group_id = attributes[:group_id] || attributes['group_id'] + @custom = attributes[:custom] || attributes['custom'] + @type = attributes[:type] || attributes['type'] || "feeds.feed_group.restored" + @feed_visibility = attributes[:feed_visibility] || attributes['feed_visibility'] || nil + @received_at = attributes[:received_at] || attributes['received_at'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + created_at: 'created_at', + fid: 'fid', + group_id: 'group_id', + custom: 'custom', + type: 'type', + feed_visibility: 'feed_visibility', + received_at: 'received_at' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/feed_own_capability.rb b/lib/getstream_ruby/generated/models/feed_own_capability.rb index 45342a8..af2a100 100644 --- a/lib/getstream_ruby/generated/models/feed_own_capability.rb +++ b/lib/getstream_ruby/generated/models/feed_own_capability.rb @@ -5,7 +5,7 @@ module GetStream module Generated module Models - # All possibility of string to use + # Represents a feed capability value and enumerates all possible capability strings. class FeedOwnCapability < GetStream::BaseModel # Empty model - inherits all functionality from BaseModel end diff --git a/lib/getstream_ruby/generated/models/feed_updated_event.rb b/lib/getstream_ruby/generated/models/feed_updated_event.rb index 3acd2f9..ff9b620 100644 --- a/lib/getstream_ruby/generated/models/feed_updated_event.rb +++ b/lib/getstream_ruby/generated/models/feed_updated_event.rb @@ -5,7 +5,7 @@ module GetStream module Generated module Models - # Emitted when a feed is created. + # Emitted when a feed is updated. class FeedUpdatedEvent < GetStream::BaseModel # Model attributes diff --git a/lib/getstream_ruby/generated/models/file_delete_request.rb b/lib/getstream_ruby/generated/models/file_delete_request.rb new file mode 100644 index 0000000..74f22bf --- /dev/null +++ b/lib/getstream_ruby/generated/models/file_delete_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class FileDeleteRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/follow_batch_request.rb b/lib/getstream_ruby/generated/models/follow_batch_request.rb index daf78b4..8099db4 100644 --- a/lib/getstream_ruby/generated/models/follow_batch_request.rb +++ b/lib/getstream_ruby/generated/models/follow_batch_request.rb @@ -12,17 +12,22 @@ class FollowBatchRequest < GetStream::BaseModel # @!attribute follows # @return [Array] List of follow relationships to create attr_accessor :follows + # @!attribute enrich_own_fields + # @return [Boolean] If true, enriches the follow's source_feed and target_feed with own_* fields (own_follows, own_followings, own_capabilities, own_membership). Defaults to false for performance. + attr_accessor :enrich_own_fields # Initialize with attributes def initialize(attributes = {}) super(attributes) @follows = attributes[:follows] || attributes['follows'] + @enrich_own_fields = attributes[:enrich_own_fields] || attributes['enrich_own_fields'] || nil end # Override field mappings for JSON serialization def self.json_field_mappings { - follows: 'follows' + follows: 'follows', + enrich_own_fields: 'enrich_own_fields' } end end diff --git a/lib/getstream_ruby/generated/models/follow_request.rb b/lib/getstream_ruby/generated/models/follow_request.rb index 3571bf8..68ef004 100644 --- a/lib/getstream_ruby/generated/models/follow_request.rb +++ b/lib/getstream_ruby/generated/models/follow_request.rb @@ -21,6 +21,9 @@ class FollowRequest < GetStream::BaseModel # @!attribute create_notification_activity # @return [Boolean] Whether to create a notification activity for this follow attr_accessor :create_notification_activity + # @!attribute enrich_own_fields + # @return [Boolean] If true, enriches the follow's source_feed and target_feed with own_* fields (own_follows, own_followings, own_capabilities, own_membership). Defaults to false for performance. + attr_accessor :enrich_own_fields # @!attribute push_preference # @return [String] Push preference for the follow relationship attr_accessor :push_preference @@ -41,6 +44,7 @@ def initialize(attributes = {}) @target = attributes[:target] || attributes['target'] @copy_custom_to_notification = attributes[:copy_custom_to_notification] || attributes['copy_custom_to_notification'] || nil @create_notification_activity = attributes[:create_notification_activity] || attributes['create_notification_activity'] || nil + @enrich_own_fields = attributes[:enrich_own_fields] || attributes['enrich_own_fields'] || nil @push_preference = attributes[:push_preference] || attributes['push_preference'] || nil @skip_push = attributes[:skip_push] || attributes['skip_push'] || nil @status = attributes[:status] || attributes['status'] || nil @@ -54,6 +58,7 @@ def self.json_field_mappings target: 'target', copy_custom_to_notification: 'copy_custom_to_notification', create_notification_activity: 'create_notification_activity', + enrich_own_fields: 'enrich_own_fields', push_preference: 'push_preference', skip_push: 'skip_push', status: 'status', diff --git a/lib/getstream_ruby/generated/models/get_channel_type_request.rb b/lib/getstream_ruby/generated/models/get_channel_type_request.rb new file mode 100644 index 0000000..22e6ce7 --- /dev/null +++ b/lib/getstream_ruby/generated/models/get_channel_type_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class GetChannelTypeRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/get_user_group_response.rb b/lib/getstream_ruby/generated/models/get_user_group_response.rb new file mode 100644 index 0000000..a41e20a --- /dev/null +++ b/lib/getstream_ruby/generated/models/get_user_group_response.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Response for getting a user group + class GetUserGroupResponse < GetStream::BaseModel + + # Model attributes + # @!attribute duration + # @return [String] + attr_accessor :duration + # @!attribute user_group + # @return [UserGroupResponse] + attr_accessor :user_group + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @duration = attributes[:duration] || attributes['duration'] + @user_group = attributes[:user_group] || attributes['user_group'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + duration: 'duration', + user_group: 'user_group' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/import_v2_task_settings.rb b/lib/getstream_ruby/generated/models/import_v2_task_settings.rb index eccd5f0..30f7f79 100644 --- a/lib/getstream_ruby/generated/models/import_v2_task_settings.rb +++ b/lib/getstream_ruby/generated/models/import_v2_task_settings.rb @@ -9,6 +9,9 @@ module Models class ImportV2TaskSettings < GetStream::BaseModel # Model attributes + # @!attribute merge_custom + # @return [Boolean] + attr_accessor :merge_custom # @!attribute mode # @return [String] attr_accessor :mode @@ -25,6 +28,7 @@ class ImportV2TaskSettings < GetStream::BaseModel # Initialize with attributes def initialize(attributes = {}) super(attributes) + @merge_custom = attributes[:merge_custom] || attributes['merge_custom'] || nil @mode = attributes[:mode] || attributes['mode'] || nil @path = attributes[:path] || attributes['path'] || nil @skip_references_check = attributes[:skip_references_check] || attributes['skip_references_check'] || nil @@ -34,6 +38,7 @@ def initialize(attributes = {}) # Override field mappings for JSON serialization def self.json_field_mappings { + merge_custom: 'merge_custom', mode: 'mode', path: 'path', skip_references_check: 'skip_references_check', diff --git a/lib/getstream_ruby/generated/models/individual_record_settings.rb b/lib/getstream_ruby/generated/models/individual_record_settings.rb index 63c0bcf..f5fe2e5 100644 --- a/lib/getstream_ruby/generated/models/individual_record_settings.rb +++ b/lib/getstream_ruby/generated/models/individual_record_settings.rb @@ -12,17 +12,22 @@ class IndividualRecordSettings < GetStream::BaseModel # @!attribute mode # @return [String] attr_accessor :mode + # @!attribute output_types + # @return [Array] + attr_accessor :output_types # Initialize with attributes def initialize(attributes = {}) super(attributes) @mode = attributes[:mode] || attributes['mode'] + @output_types = attributes[:output_types] || attributes['output_types'] || nil end # Override field mappings for JSON serialization def self.json_field_mappings { - mode: 'mode' + mode: 'mode', + output_types: 'output_types' } end end diff --git a/lib/getstream_ruby/generated/models/individual_recording_settings_request.rb b/lib/getstream_ruby/generated/models/individual_recording_settings_request.rb index cba368a..1e3c8c4 100644 --- a/lib/getstream_ruby/generated/models/individual_recording_settings_request.rb +++ b/lib/getstream_ruby/generated/models/individual_recording_settings_request.rb @@ -12,17 +12,22 @@ class IndividualRecordingSettingsRequest < GetStream::BaseModel # @!attribute mode # @return [String] Recording mode. One of: available, disabled, auto-on attr_accessor :mode + # @!attribute output_types + # @return [Array] Output types to include: audio_only, video_only, audio_video, screenshare_audio_only, screenshare_video_only, screenshare_audio_video + attr_accessor :output_types # Initialize with attributes def initialize(attributes = {}) super(attributes) @mode = attributes[:mode] || attributes['mode'] + @output_types = attributes[:output_types] || attributes['output_types'] || nil end # Override field mappings for JSON serialization def self.json_field_mappings { - mode: 'mode' + mode: 'mode', + output_types: 'output_types' } end end diff --git a/lib/getstream_ruby/generated/models/individual_recording_settings_response.rb b/lib/getstream_ruby/generated/models/individual_recording_settings_response.rb index ab57f2a..f72f920 100644 --- a/lib/getstream_ruby/generated/models/individual_recording_settings_response.rb +++ b/lib/getstream_ruby/generated/models/individual_recording_settings_response.rb @@ -12,17 +12,22 @@ class IndividualRecordingSettingsResponse < GetStream::BaseModel # @!attribute mode # @return [String] attr_accessor :mode + # @!attribute output_types + # @return [Array] + attr_accessor :output_types # Initialize with attributes def initialize(attributes = {}) super(attributes) @mode = attributes[:mode] || attributes['mode'] + @output_types = attributes[:output_types] || attributes['output_types'] || nil end # Override field mappings for JSON serialization def self.json_field_mappings { - mode: 'mode' + mode: 'mode', + output_types: 'output_types' } end end diff --git a/lib/getstream_ruby/generated/models/list_user_groups_response.rb b/lib/getstream_ruby/generated/models/list_user_groups_response.rb new file mode 100644 index 0000000..1c79862 --- /dev/null +++ b/lib/getstream_ruby/generated/models/list_user_groups_response.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Response for listing user groups + class ListUserGroupsResponse < GetStream::BaseModel + + # Model attributes + # @!attribute duration + # @return [String] + attr_accessor :duration + # @!attribute user_groups + # @return [Array] List of user groups + attr_accessor :user_groups + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @duration = attributes[:duration] || attributes['duration'] + @user_groups = attributes[:user_groups] || attributes['user_groups'] + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + duration: 'duration', + user_groups: 'user_groups' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/message_request.rb b/lib/getstream_ruby/generated/models/message_request.rb index f2fb16d..a17fb05 100644 --- a/lib/getstream_ruby/generated/models/message_request.rb +++ b/lib/getstream_ruby/generated/models/message_request.rb @@ -60,6 +60,9 @@ class MessageRequest < GetStream::BaseModel # @!attribute attachments # @return [Array] Array of message attachments attr_accessor :attachments + # @!attribute mentioned_roles + # @return [Array] + attr_accessor :mentioned_roles # @!attribute mentioned_users # @return [Array] Array of user IDs to mention attr_accessor :mentioned_users @@ -96,6 +99,7 @@ def initialize(attributes = {}) @type = attributes[:type] || attributes['type'] || nil @user_id = attributes[:user_id] || attributes['user_id'] || nil @attachments = attributes[:attachments] || attributes['attachments'] || nil + @mentioned_roles = attributes[:mentioned_roles] || attributes['mentioned_roles'] || nil @mentioned_users = attributes[:mentioned_users] || attributes['mentioned_users'] || nil @restricted_visibility = attributes[:restricted_visibility] || attributes['restricted_visibility'] || nil @custom = attributes[:custom] || attributes['custom'] || nil @@ -123,6 +127,7 @@ def self.json_field_mappings type: 'type', user_id: 'user_id', attachments: 'attachments', + mentioned_roles: 'mentioned_roles', mentioned_users: 'mentioned_users', restricted_visibility: 'restricted_visibility', custom: 'custom', diff --git a/lib/getstream_ruby/generated/models/message_response.rb b/lib/getstream_ruby/generated/models/message_response.rb index a49ba4d..fd34cb4 100644 --- a/lib/getstream_ruby/generated/models/message_response.rb +++ b/lib/getstream_ruby/generated/models/message_response.rb @@ -111,6 +111,9 @@ class MessageResponse < GetStream::BaseModel # @!attribute show_in_channel # @return [Boolean] Whether thread reply should be shown in the channel as well attr_accessor :show_in_channel + # @!attribute mentioned_roles + # @return [Array] List of roles mentioned in the message (e.g. admin, channel_moderator, custom roles). Members with matching roles will receive push notifications based on their push preferences. Max 10 roles + attr_accessor :mentioned_roles # @!attribute thread_participants # @return [Array] List of users who participate in thread attr_accessor :thread_participants @@ -185,6 +188,7 @@ def initialize(attributes = {}) @poll_id = attributes[:poll_id] || attributes['poll_id'] || nil @quoted_message_id = attributes[:quoted_message_id] || attributes['quoted_message_id'] || nil @show_in_channel = attributes[:show_in_channel] || attributes['show_in_channel'] || nil + @mentioned_roles = attributes[:mentioned_roles] || attributes['mentioned_roles'] || nil @thread_participants = attributes[:thread_participants] || attributes['thread_participants'] || nil @draft = attributes[:draft] || attributes['draft'] || nil @i18n = attributes[:i18n] || attributes['i18n'] || nil @@ -236,6 +240,7 @@ def self.json_field_mappings poll_id: 'poll_id', quoted_message_id: 'quoted_message_id', show_in_channel: 'show_in_channel', + mentioned_roles: 'mentioned_roles', thread_participants: 'thread_participants', draft: 'draft', i18n: 'i18n', diff --git a/lib/getstream_ruby/generated/models/message_with_channel_response.rb b/lib/getstream_ruby/generated/models/message_with_channel_response.rb index 99934f0..5400b70 100644 --- a/lib/getstream_ruby/generated/models/message_with_channel_response.rb +++ b/lib/getstream_ruby/generated/models/message_with_channel_response.rb @@ -114,6 +114,9 @@ class MessageWithChannelResponse < GetStream::BaseModel # @!attribute show_in_channel # @return [Boolean] Whether thread reply should be shown in the channel as well attr_accessor :show_in_channel + # @!attribute mentioned_roles + # @return [Array] List of roles mentioned in the message (e.g. admin, channel_moderator, custom roles). Members with matching roles will receive push notifications based on their push preferences. Max 10 roles + attr_accessor :mentioned_roles # @!attribute thread_participants # @return [Array] List of users who participate in thread attr_accessor :thread_participants @@ -189,6 +192,7 @@ def initialize(attributes = {}) @poll_id = attributes[:poll_id] || attributes['poll_id'] || nil @quoted_message_id = attributes[:quoted_message_id] || attributes['quoted_message_id'] || nil @show_in_channel = attributes[:show_in_channel] || attributes['show_in_channel'] || nil + @mentioned_roles = attributes[:mentioned_roles] || attributes['mentioned_roles'] || nil @thread_participants = attributes[:thread_participants] || attributes['thread_participants'] || nil @draft = attributes[:draft] || attributes['draft'] || nil @i18n = attributes[:i18n] || attributes['i18n'] || nil @@ -241,6 +245,7 @@ def self.json_field_mappings poll_id: 'poll_id', quoted_message_id: 'quoted_message_id', show_in_channel: 'show_in_channel', + mentioned_roles: 'mentioned_roles', thread_participants: 'thread_participants', draft: 'draft', i18n: 'i18n', diff --git a/lib/getstream_ruby/generated/models/metric_stats.rb b/lib/getstream_ruby/generated/models/metric_stats.rb new file mode 100644 index 0000000..ef557c3 --- /dev/null +++ b/lib/getstream_ruby/generated/models/metric_stats.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Statistics for a single metric with optional daily breakdown + class MetricStats < GetStream::BaseModel + + # Model attributes + # @!attribute total + # @return [Integer] Aggregated total value + attr_accessor :total + # @!attribute daily + # @return [Array] Per-day values (only present in daily mode) + attr_accessor :daily + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @total = attributes[:total] || attributes['total'] + @daily = attributes[:daily] || attributes['daily'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + total: 'total', + daily: 'daily' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/notification_status_response.rb b/lib/getstream_ruby/generated/models/notification_status_response.rb index 8176599..aefb88f 100644 --- a/lib/getstream_ruby/generated/models/notification_status_response.rb +++ b/lib/getstream_ruby/generated/models/notification_status_response.rb @@ -16,16 +16,16 @@ class NotificationStatusResponse < GetStream::BaseModel # @return [Integer] Number of unseen notifications attr_accessor :unseen # @!attribute last_read_at - # @return [DateTime] + # @return [DateTime] When notifications were last read attr_accessor :last_read_at # @!attribute last_seen_at # @return [DateTime] When notifications were last seen attr_accessor :last_seen_at # @!attribute read_activities - # @return [Array] IDs of activities that have been read + # @return [Array] Deprecated: use is_read on each activity/group instead. IDs of activities that have been read. Capped at ~101 entries for aggregated feeds. attr_accessor :read_activities # @!attribute seen_activities - # @return [Array] + # @return [Array] Deprecated: use is_seen on each activity/group instead. IDs of activities that have been seen. Capped at ~101 entries for aggregated feeds. attr_accessor :seen_activities # Initialize with attributes diff --git a/lib/getstream_ruby/generated/models/pin_activity_request.rb b/lib/getstream_ruby/generated/models/pin_activity_request.rb index 5430e85..5d149ed 100644 --- a/lib/getstream_ruby/generated/models/pin_activity_request.rb +++ b/lib/getstream_ruby/generated/models/pin_activity_request.rb @@ -9,6 +9,9 @@ module Models class PinActivityRequest < GetStream::BaseModel # Model attributes + # @!attribute enrich_own_fields + # @return [Boolean] If true, enriches the activity's current_feed with own_* fields (own_follows, own_followings, own_capabilities, own_membership). Defaults to false for performance. + attr_accessor :enrich_own_fields # @!attribute user_id # @return [String] attr_accessor :user_id @@ -19,6 +22,7 @@ class PinActivityRequest < GetStream::BaseModel # Initialize with attributes def initialize(attributes = {}) super(attributes) + @enrich_own_fields = attributes[:enrich_own_fields] || attributes['enrich_own_fields'] || nil @user_id = attributes[:user_id] || attributes['user_id'] || nil @user = attributes[:user] || attributes['user'] || nil end @@ -26,6 +30,7 @@ def initialize(attributes = {}) # Override field mappings for JSON serialization def self.json_field_mappings { + enrich_own_fields: 'enrich_own_fields', user_id: 'user_id', user: 'user' } diff --git a/lib/getstream_ruby/generated/models/query_activities_request.rb b/lib/getstream_ruby/generated/models/query_activities_request.rb index 7df55f4..3b24dda 100644 --- a/lib/getstream_ruby/generated/models/query_activities_request.rb +++ b/lib/getstream_ruby/generated/models/query_activities_request.rb @@ -9,6 +9,9 @@ module Models class QueryActivitiesRequest < GetStream::BaseModel # Model attributes + # @!attribute enrich_own_fields + # @return [Boolean] + attr_accessor :enrich_own_fields # @!attribute include_expired_activities # @return [Boolean] When true, include both expired and non-expired activities in the result. attr_accessor :include_expired_activities @@ -40,6 +43,7 @@ class QueryActivitiesRequest < GetStream::BaseModel # Initialize with attributes def initialize(attributes = {}) super(attributes) + @enrich_own_fields = attributes[:enrich_own_fields] || attributes['enrich_own_fields'] || nil @include_expired_activities = attributes[:include_expired_activities] || attributes['include_expired_activities'] || nil @include_private_activities = attributes[:include_private_activities] || attributes['include_private_activities'] || nil @limit = attributes[:limit] || attributes['limit'] || nil @@ -54,6 +58,7 @@ def initialize(attributes = {}) # Override field mappings for JSON serialization def self.json_field_mappings { + enrich_own_fields: 'enrich_own_fields', include_expired_activities: 'include_expired_activities', include_private_activities: 'include_private_activities', limit: 'limit', diff --git a/lib/getstream_ruby/generated/models/query_bookmarks_request.rb b/lib/getstream_ruby/generated/models/query_bookmarks_request.rb index 779a6e5..01f0086 100644 --- a/lib/getstream_ruby/generated/models/query_bookmarks_request.rb +++ b/lib/getstream_ruby/generated/models/query_bookmarks_request.rb @@ -9,6 +9,9 @@ module Models class QueryBookmarksRequest < GetStream::BaseModel # Model attributes + # @!attribute enrich_own_fields + # @return [Boolean] + attr_accessor :enrich_own_fields # @!attribute limit # @return [Integer] attr_accessor :limit @@ -28,6 +31,7 @@ class QueryBookmarksRequest < GetStream::BaseModel # Initialize with attributes def initialize(attributes = {}) super(attributes) + @enrich_own_fields = attributes[:enrich_own_fields] || attributes['enrich_own_fields'] || nil @limit = attributes[:limit] || attributes['limit'] || nil @next = attributes[:next] || attributes['next'] || nil @prev = attributes[:prev] || attributes['prev'] || nil @@ -38,6 +42,7 @@ def initialize(attributes = {}) # Override field mappings for JSON serialization def self.json_field_mappings { + enrich_own_fields: 'enrich_own_fields', limit: 'limit', next: 'next', prev: 'prev', diff --git a/lib/getstream_ruby/generated/models/query_comments_request.rb b/lib/getstream_ruby/generated/models/query_comments_request.rb index 90d86e7..44bccdc 100644 --- a/lib/getstream_ruby/generated/models/query_comments_request.rb +++ b/lib/getstream_ruby/generated/models/query_comments_request.rb @@ -12,6 +12,9 @@ class QueryCommentsRequest < GetStream::BaseModel # @!attribute filter # @return [Object] MongoDB-style filter for querying comments attr_accessor :filter + # @!attribute id_around + # @return [String] Returns the comment with the specified ID along with surrounding comments for context + attr_accessor :id_around # @!attribute limit # @return [Integer] Maximum number of comments to return attr_accessor :limit @@ -24,25 +27,37 @@ class QueryCommentsRequest < GetStream::BaseModel # @!attribute sort # @return [String] first (oldest), last (newest) or top. One of: first, last, top, best, controversial attr_accessor :sort + # @!attribute user_id + # @return [String] + attr_accessor :user_id + # @!attribute user + # @return [UserRequest] + attr_accessor :user # Initialize with attributes def initialize(attributes = {}) super(attributes) @filter = attributes[:filter] || attributes['filter'] + @id_around = attributes[:id_around] || attributes['id_around'] || nil @limit = attributes[:limit] || attributes['limit'] || nil @next = attributes[:next] || attributes['next'] || nil @prev = attributes[:prev] || attributes['prev'] || nil @sort = attributes[:sort] || attributes['sort'] || nil + @user_id = attributes[:user_id] || attributes['user_id'] || nil + @user = attributes[:user] || attributes['user'] || nil end # Override field mappings for JSON serialization def self.json_field_mappings { filter: 'filter', + id_around: 'id_around', limit: 'limit', next: 'next', prev: 'prev', - sort: 'sort' + sort: 'sort', + user_id: 'user_id', + user: 'user' } end end diff --git a/lib/getstream_ruby/generated/models/query_feeds_request.rb b/lib/getstream_ruby/generated/models/query_feeds_request.rb index 79f5656..1af0247 100644 --- a/lib/getstream_ruby/generated/models/query_feeds_request.rb +++ b/lib/getstream_ruby/generated/models/query_feeds_request.rb @@ -9,6 +9,9 @@ module Models class QueryFeedsRequest < GetStream::BaseModel # Model attributes + # @!attribute enrich_own_fields + # @return [Boolean] + attr_accessor :enrich_own_fields # @!attribute limit # @return [Integer] attr_accessor :limit @@ -31,6 +34,7 @@ class QueryFeedsRequest < GetStream::BaseModel # Initialize with attributes def initialize(attributes = {}) super(attributes) + @enrich_own_fields = attributes[:enrich_own_fields] || attributes['enrich_own_fields'] || nil @limit = attributes[:limit] || attributes['limit'] || nil @next = attributes[:next] || attributes['next'] || nil @prev = attributes[:prev] || attributes['prev'] || nil @@ -42,6 +46,7 @@ def initialize(attributes = {}) # Override field mappings for JSON serialization def self.json_field_mappings { + enrich_own_fields: 'enrich_own_fields', limit: 'limit', next: 'next', prev: 'prev', diff --git a/lib/getstream_ruby/generated/models/query_moderation_rules_response.rb b/lib/getstream_ruby/generated/models/query_moderation_rules_response.rb index e9ce6d0..e75607e 100644 --- a/lib/getstream_ruby/generated/models/query_moderation_rules_response.rb +++ b/lib/getstream_ruby/generated/models/query_moderation_rules_response.rb @@ -16,7 +16,7 @@ class QueryModerationRulesResponse < GetStream::BaseModel # @return [Array] Available harm labels for closed caption rules attr_accessor :closed_caption_labels # @!attribute keyframe_labels - # @return [Array] Available harm labels for keyframe rules + # @return [Array] Deprecated: use keyframe_label_classifications instead. Available L1 harm labels for keyframe rules attr_accessor :keyframe_labels # @!attribute rules # @return [Array] List of moderation rules @@ -24,6 +24,9 @@ class QueryModerationRulesResponse < GetStream::BaseModel # @!attribute default_llm_labels # @return [Hash] Default LLM label descriptions attr_accessor :default_llm_labels + # @!attribute keyframe_label_classifications + # @return [Hash>] L1 to L2 mapping of keyframe harm label classifications + attr_accessor :keyframe_label_classifications # @!attribute next # @return [String] attr_accessor :next @@ -39,6 +42,7 @@ def initialize(attributes = {}) @keyframe_labels = attributes[:keyframe_labels] || attributes['keyframe_labels'] @rules = attributes[:rules] || attributes['rules'] @default_llm_labels = attributes[:default_llm_labels] || attributes['default_llm_labels'] + @keyframe_label_classifications = attributes[:keyframe_label_classifications] || attributes['keyframe_label_classifications'] @next = attributes[:next] || attributes['next'] || nil @prev = attributes[:prev] || attributes['prev'] || nil end @@ -51,6 +55,7 @@ def self.json_field_mappings keyframe_labels: 'keyframe_labels', rules: 'rules', default_llm_labels: 'default_llm_labels', + keyframe_label_classifications: 'keyframe_label_classifications', next: 'next', prev: 'prev' } diff --git a/lib/getstream_ruby/generated/models/query_pinned_activities_request.rb b/lib/getstream_ruby/generated/models/query_pinned_activities_request.rb index 4bd5d18..e933d65 100644 --- a/lib/getstream_ruby/generated/models/query_pinned_activities_request.rb +++ b/lib/getstream_ruby/generated/models/query_pinned_activities_request.rb @@ -9,6 +9,9 @@ module Models class QueryPinnedActivitiesRequest < GetStream::BaseModel # Model attributes + # @!attribute enrich_own_fields + # @return [Boolean] + attr_accessor :enrich_own_fields # @!attribute limit # @return [Integer] attr_accessor :limit @@ -28,6 +31,7 @@ class QueryPinnedActivitiesRequest < GetStream::BaseModel # Initialize with attributes def initialize(attributes = {}) super(attributes) + @enrich_own_fields = attributes[:enrich_own_fields] || attributes['enrich_own_fields'] || nil @limit = attributes[:limit] || attributes['limit'] || nil @next = attributes[:next] || attributes['next'] || nil @prev = attributes[:prev] || attributes['prev'] || nil @@ -38,6 +42,7 @@ def initialize(attributes = {}) # Override field mappings for JSON serialization def self.json_field_mappings { + enrich_own_fields: 'enrich_own_fields', limit: 'limit', next: 'next', prev: 'prev', diff --git a/lib/getstream_ruby/generated/models/query_team_usage_stats_request.rb b/lib/getstream_ruby/generated/models/query_team_usage_stats_request.rb new file mode 100644 index 0000000..1a008c0 --- /dev/null +++ b/lib/getstream_ruby/generated/models/query_team_usage_stats_request.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Request payload for querying team-level usage statistics from the warehouse database + class QueryTeamUsageStatsRequest < GetStream::BaseModel + + # Model attributes + # @!attribute end_date + # @return [String] End date in YYYY-MM-DD format. Used with start_date for custom date range. Returns daily breakdown. + attr_accessor :end_date + # @!attribute limit + # @return [Integer] Maximum number of teams to return per page (default: 30, max: 30) + attr_accessor :limit + # @!attribute month + # @return [String] Month in YYYY-MM format (e.g., '2026-01'). Mutually exclusive with start_date/end_date. Returns aggregated monthly values. + attr_accessor :month + # @!attribute next + # @return [String] Cursor for pagination to fetch next page of teams + attr_accessor :next + # @!attribute start_date + # @return [String] Start date in YYYY-MM-DD format. Used with end_date for custom date range. Returns daily breakdown. + attr_accessor :start_date + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @end_date = attributes[:end_date] || attributes['end_date'] || nil + @limit = attributes[:limit] || attributes['limit'] || nil + @month = attributes[:month] || attributes['month'] || nil + @next = attributes[:next] || attributes['next'] || nil + @start_date = attributes[:start_date] || attributes['start_date'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + end_date: 'end_date', + limit: 'limit', + month: 'month', + next: 'next', + start_date: 'start_date' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/query_team_usage_stats_response.rb b/lib/getstream_ruby/generated/models/query_team_usage_stats_response.rb new file mode 100644 index 0000000..377cbec --- /dev/null +++ b/lib/getstream_ruby/generated/models/query_team_usage_stats_response.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Response containing team-level usage statistics + class QueryTeamUsageStatsResponse < GetStream::BaseModel + + # Model attributes + # @!attribute duration + # @return [String] Duration of the request in milliseconds + attr_accessor :duration + # @!attribute teams + # @return [Array] Array of team usage statistics + attr_accessor :teams + # @!attribute next + # @return [String] Cursor for pagination to fetch next page + attr_accessor :next + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @duration = attributes[:duration] || attributes['duration'] + @teams = attributes[:teams] || attributes['teams'] + @next = attributes[:next] || attributes['next'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + duration: 'duration', + teams: 'teams', + next: 'next' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/read_collections_response.rb b/lib/getstream_ruby/generated/models/read_collections_response.rb index 2845c58..89f1b12 100644 --- a/lib/getstream_ruby/generated/models/read_collections_response.rb +++ b/lib/getstream_ruby/generated/models/read_collections_response.rb @@ -15,19 +15,29 @@ class ReadCollectionsResponse < GetStream::BaseModel # @!attribute collections # @return [Array] List of collections matching the query attr_accessor :collections + # @!attribute next + # @return [String] Cursor for next page (when listing without collection_refs) + attr_accessor :next + # @!attribute prev + # @return [String] Cursor for previous page (when listing without collection_refs) + attr_accessor :prev # Initialize with attributes def initialize(attributes = {}) super(attributes) @duration = attributes[:duration] || attributes['duration'] @collections = attributes[:collections] || attributes['collections'] + @next = attributes[:next] || attributes['next'] || nil + @prev = attributes[:prev] || attributes['prev'] || nil end # Override field mappings for JSON serialization def self.json_field_mappings { duration: 'duration', - collections: 'collections' + collections: 'collections', + next: 'next', + prev: 'prev' } end end diff --git a/lib/getstream_ruby/generated/models/remove_user_group_members_request.rb b/lib/getstream_ruby/generated/models/remove_user_group_members_request.rb new file mode 100644 index 0000000..e01b1df --- /dev/null +++ b/lib/getstream_ruby/generated/models/remove_user_group_members_request.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Request body for removing members from a user group + class RemoveUserGroupMembersRequest < GetStream::BaseModel + + # Model attributes + # @!attribute member_ids + # @return [Array] List of user IDs to remove + attr_accessor :member_ids + # @!attribute team_id + # @return [String] + attr_accessor :team_id + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @member_ids = attributes[:member_ids] || attributes['member_ids'] + @team_id = attributes[:team_id] || attributes['team_id'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + member_ids: 'member_ids', + team_id: 'team_id' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/remove_user_group_members_response.rb b/lib/getstream_ruby/generated/models/remove_user_group_members_response.rb new file mode 100644 index 0000000..c78add5 --- /dev/null +++ b/lib/getstream_ruby/generated/models/remove_user_group_members_response.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Response for removing members from a user group + class RemoveUserGroupMembersResponse < GetStream::BaseModel + + # Model attributes + # @!attribute duration + # @return [String] + attr_accessor :duration + # @!attribute user_group + # @return [UserGroupResponse] + attr_accessor :user_group + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @duration = attributes[:duration] || attributes['duration'] + @user_group = attributes[:user_group] || attributes['user_group'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + duration: 'duration', + user_group: 'user_group' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/restore_feed_group_request.rb b/lib/getstream_ruby/generated/models/restore_feed_group_request.rb new file mode 100644 index 0000000..55581de --- /dev/null +++ b/lib/getstream_ruby/generated/models/restore_feed_group_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class RestoreFeedGroupRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/restore_feed_group_response.rb b/lib/getstream_ruby/generated/models/restore_feed_group_response.rb new file mode 100644 index 0000000..0d82a0e --- /dev/null +++ b/lib/getstream_ruby/generated/models/restore_feed_group_response.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class RestoreFeedGroupResponse < GetStream::BaseModel + + # Model attributes + # @!attribute duration + # @return [String] + attr_accessor :duration + # @!attribute feed_group + # @return [FeedGroupResponse] + attr_accessor :feed_group + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @duration = attributes[:duration] || attributes['duration'] + @feed_group = attributes[:feed_group] || attributes['feed_group'] + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + duration: 'duration', + feed_group: 'feed_group' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/rule_builder_condition.rb b/lib/getstream_ruby/generated/models/rule_builder_condition.rb index f7b5ed2..16d4739 100644 --- a/lib/getstream_ruby/generated/models/rule_builder_condition.rb +++ b/lib/getstream_ruby/generated/models/rule_builder_condition.rb @@ -21,6 +21,9 @@ class RuleBuilderCondition < GetStream::BaseModel # @!attribute call_type_rule_params # @return [CallTypeRuleParameters] attr_accessor :call_type_rule_params + # @!attribute call_violation_count_params + # @return [CallViolationCountParameters] + attr_accessor :call_violation_count_params # @!attribute closed_caption_rule_params # @return [ClosedCaptionRuleParameters] attr_accessor :closed_caption_rule_params @@ -77,6 +80,7 @@ def initialize(attributes = {}) @type = attributes[:type] || attributes['type'] || nil @call_custom_property_params = attributes[:call_custom_property_params] || attributes['call_custom_property_params'] || nil @call_type_rule_params = attributes[:call_type_rule_params] || attributes['call_type_rule_params'] || nil + @call_violation_count_params = attributes[:call_violation_count_params] || attributes['call_violation_count_params'] || nil @closed_caption_rule_params = attributes[:closed_caption_rule_params] || attributes['closed_caption_rule_params'] || nil @content_count_rule_params = attributes[:content_count_rule_params] || attributes['content_count_rule_params'] || nil @content_flag_count_rule_params = attributes[:content_flag_count_rule_params] || attributes['content_flag_count_rule_params'] || nil @@ -102,6 +106,7 @@ def self.json_field_mappings type: 'type', call_custom_property_params: 'call_custom_property_params', call_type_rule_params: 'call_type_rule_params', + call_violation_count_params: 'call_violation_count_params', closed_caption_rule_params: 'closed_caption_rule_params', content_count_rule_params: 'content_count_rule_params', content_flag_count_rule_params: 'content_flag_count_rule_params', diff --git a/lib/getstream_ruby/generated/models/search_result_message.rb b/lib/getstream_ruby/generated/models/search_result_message.rb index 348034f..c54004c 100644 --- a/lib/getstream_ruby/generated/models/search_result_message.rb +++ b/lib/getstream_ruby/generated/models/search_result_message.rb @@ -111,6 +111,9 @@ class SearchResultMessage < GetStream::BaseModel # @!attribute show_in_channel # @return [Boolean] attr_accessor :show_in_channel + # @!attribute mentioned_roles + # @return [Array] + attr_accessor :mentioned_roles # @!attribute thread_participants # @return [Array] attr_accessor :thread_participants @@ -188,6 +191,7 @@ def initialize(attributes = {}) @poll_id = attributes[:poll_id] || attributes['poll_id'] || nil @quoted_message_id = attributes[:quoted_message_id] || attributes['quoted_message_id'] || nil @show_in_channel = attributes[:show_in_channel] || attributes['show_in_channel'] || nil + @mentioned_roles = attributes[:mentioned_roles] || attributes['mentioned_roles'] || nil @thread_participants = attributes[:thread_participants] || attributes['thread_participants'] || nil @channel = attributes[:channel] || attributes['channel'] || nil @draft = attributes[:draft] || attributes['draft'] || nil @@ -240,6 +244,7 @@ def self.json_field_mappings poll_id: 'poll_id', quoted_message_id: 'quoted_message_id', show_in_channel: 'show_in_channel', + mentioned_roles: 'mentioned_roles', thread_participants: 'thread_participants', channel: 'channel', draft: 'draft', diff --git a/lib/getstream_ruby/generated/models/search_user_groups_response.rb b/lib/getstream_ruby/generated/models/search_user_groups_response.rb new file mode 100644 index 0000000..424a14d --- /dev/null +++ b/lib/getstream_ruby/generated/models/search_user_groups_response.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Response for searching user groups + class SearchUserGroupsResponse < GetStream::BaseModel + + # Model attributes + # @!attribute duration + # @return [String] + attr_accessor :duration + # @!attribute user_groups + # @return [Array] List of matching user groups + attr_accessor :user_groups + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @duration = attributes[:duration] || attributes['duration'] + @user_groups = attributes[:user_groups] || attributes['user_groups'] + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + duration: 'duration', + user_groups: 'user_groups' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/team_usage_stats.rb b/lib/getstream_ruby/generated/models/team_usage_stats.rb new file mode 100644 index 0000000..0b8b25b --- /dev/null +++ b/lib/getstream_ruby/generated/models/team_usage_stats.rb @@ -0,0 +1,111 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Usage statistics for a single team containing all 16 metrics + class TeamUsageStats < GetStream::BaseModel + + # Model attributes + # @!attribute team + # @return [String] Team identifier (empty string for users not assigned to any team) + attr_accessor :team + # @!attribute concurrent_connections + # @return [MetricStats] + attr_accessor :concurrent_connections + # @!attribute concurrent_users + # @return [MetricStats] + attr_accessor :concurrent_users + # @!attribute image_moderations_daily + # @return [MetricStats] + attr_accessor :image_moderations_daily + # @!attribute messages_daily + # @return [MetricStats] + attr_accessor :messages_daily + # @!attribute messages_last_24_hours + # @return [MetricStats] + attr_accessor :messages_last_24_hours + # @!attribute messages_last_30_days + # @return [MetricStats] + attr_accessor :messages_last_30_days + # @!attribute messages_month_to_date + # @return [MetricStats] + attr_accessor :messages_month_to_date + # @!attribute messages_total + # @return [MetricStats] + attr_accessor :messages_total + # @!attribute translations_daily + # @return [MetricStats] + attr_accessor :translations_daily + # @!attribute users_daily + # @return [MetricStats] + attr_accessor :users_daily + # @!attribute users_engaged_last_30_days + # @return [MetricStats] + attr_accessor :users_engaged_last_30_days + # @!attribute users_engaged_month_to_date + # @return [MetricStats] + attr_accessor :users_engaged_month_to_date + # @!attribute users_last_24_hours + # @return [MetricStats] + attr_accessor :users_last_24_hours + # @!attribute users_last_30_days + # @return [MetricStats] + attr_accessor :users_last_30_days + # @!attribute users_month_to_date + # @return [MetricStats] + attr_accessor :users_month_to_date + # @!attribute users_total + # @return [MetricStats] + attr_accessor :users_total + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @team = attributes[:team] || attributes['team'] + @concurrent_connections = attributes[:concurrent_connections] || attributes['concurrent_connections'] + @concurrent_users = attributes[:concurrent_users] || attributes['concurrent_users'] + @image_moderations_daily = attributes[:image_moderations_daily] || attributes['image_moderations_daily'] + @messages_daily = attributes[:messages_daily] || attributes['messages_daily'] + @messages_last_24_hours = attributes[:messages_last_24_hours] || attributes['messages_last_24_hours'] + @messages_last_30_days = attributes[:messages_last_30_days] || attributes['messages_last_30_days'] + @messages_month_to_date = attributes[:messages_month_to_date] || attributes['messages_month_to_date'] + @messages_total = attributes[:messages_total] || attributes['messages_total'] + @translations_daily = attributes[:translations_daily] || attributes['translations_daily'] + @users_daily = attributes[:users_daily] || attributes['users_daily'] + @users_engaged_last_30_days = attributes[:users_engaged_last_30_days] || attributes['users_engaged_last_30_days'] + @users_engaged_month_to_date = attributes[:users_engaged_month_to_date] || attributes['users_engaged_month_to_date'] + @users_last_24_hours = attributes[:users_last_24_hours] || attributes['users_last_24_hours'] + @users_last_30_days = attributes[:users_last_30_days] || attributes['users_last_30_days'] + @users_month_to_date = attributes[:users_month_to_date] || attributes['users_month_to_date'] + @users_total = attributes[:users_total] || attributes['users_total'] + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + team: 'team', + concurrent_connections: 'concurrent_connections', + concurrent_users: 'concurrent_users', + image_moderations_daily: 'image_moderations_daily', + messages_daily: 'messages_daily', + messages_last_24_hours: 'messages_last_24_hours', + messages_last_30_days: 'messages_last_30_days', + messages_month_to_date: 'messages_month_to_date', + messages_total: 'messages_total', + translations_daily: 'translations_daily', + users_daily: 'users_daily', + users_engaged_last_30_days: 'users_engaged_last_30_days', + users_engaged_month_to_date: 'users_engaged_month_to_date', + users_last_24_hours: 'users_last_24_hours', + users_last_30_days: 'users_last_30_days', + users_month_to_date: 'users_month_to_date', + users_total: 'users_total' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/track_activity_metrics_event.rb b/lib/getstream_ruby/generated/models/track_activity_metrics_event.rb new file mode 100644 index 0000000..e2030cb --- /dev/null +++ b/lib/getstream_ruby/generated/models/track_activity_metrics_event.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # A single metric event to track for an activity + class TrackActivityMetricsEvent < GetStream::BaseModel + + # Model attributes + # @!attribute activity_id + # @return [String] The ID of the activity to track the metric for + attr_accessor :activity_id + # @!attribute metric + # @return [String] The metric name (e.g. views, clicks, impressions). Alphanumeric and underscores only. + attr_accessor :metric + # @!attribute delta + # @return [Integer] The amount to increment (positive) or decrement (negative). Defaults to 1. The absolute value counts against rate limits. + attr_accessor :delta + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @activity_id = attributes[:activity_id] || attributes['activity_id'] + @metric = attributes[:metric] || attributes['metric'] + @delta = attributes[:delta] || attributes['delta'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + activity_id: 'activity_id', + metric: 'metric', + delta: 'delta' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/track_activity_metrics_event_result.rb b/lib/getstream_ruby/generated/models/track_activity_metrics_event_result.rb new file mode 100644 index 0000000..1f81716 --- /dev/null +++ b/lib/getstream_ruby/generated/models/track_activity_metrics_event_result.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Result of tracking a single metric event + class TrackActivityMetricsEventResult < GetStream::BaseModel + + # Model attributes + # @!attribute activity_id + # @return [String] The activity ID from the request + attr_accessor :activity_id + # @!attribute allowed + # @return [Boolean] Whether the metric was counted (false if rate-limited) + attr_accessor :allowed + # @!attribute metric + # @return [String] The metric name from the request + attr_accessor :metric + # @!attribute error + # @return [String] Error message if processing failed + attr_accessor :error + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @activity_id = attributes[:activity_id] || attributes['activity_id'] + @allowed = attributes[:allowed] || attributes['allowed'] + @metric = attributes[:metric] || attributes['metric'] + @error = attributes[:error] || attributes['error'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + activity_id: 'activity_id', + allowed: 'allowed', + metric: 'metric', + error: 'error' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/track_activity_metrics_request.rb b/lib/getstream_ruby/generated/models/track_activity_metrics_request.rb new file mode 100644 index 0000000..d13696b --- /dev/null +++ b/lib/getstream_ruby/generated/models/track_activity_metrics_request.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Batch request to track metric events for activities. Rate-limited per user/IP per activity per metric. + class TrackActivityMetricsRequest < GetStream::BaseModel + + # Model attributes + # @!attribute events + # @return [Array] List of metric events to track (max 100 per request) + attr_accessor :events + # @!attribute user_id + # @return [String] + attr_accessor :user_id + # @!attribute user + # @return [UserRequest] + attr_accessor :user + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @events = attributes[:events] || attributes['events'] + @user_id = attributes[:user_id] || attributes['user_id'] || nil + @user = attributes[:user] || attributes['user'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + events: 'events', + user_id: 'user_id', + user: 'user' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/track_activity_metrics_response.rb b/lib/getstream_ruby/generated/models/track_activity_metrics_response.rb new file mode 100644 index 0000000..5f9e6fd --- /dev/null +++ b/lib/getstream_ruby/generated/models/track_activity_metrics_response.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Response containing results for each tracked metric event + class TrackActivityMetricsResponse < GetStream::BaseModel + + # Model attributes + # @!attribute duration + # @return [String] + attr_accessor :duration + # @!attribute results + # @return [Array] Results for each event in the request, in the same order + attr_accessor :results + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @duration = attributes[:duration] || attributes['duration'] + @results = attributes[:results] || attributes['results'] + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + duration: 'duration', + results: 'results' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/undelete_message_request.rb b/lib/getstream_ruby/generated/models/undelete_message_request.rb new file mode 100644 index 0000000..bf746b1 --- /dev/null +++ b/lib/getstream_ruby/generated/models/undelete_message_request.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class UndeleteMessageRequest < GetStream::BaseModel + + # Model attributes + # @!attribute undeleted_by + # @return [String] ID of the user who is undeleting the message + attr_accessor :undeleted_by + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @undeleted_by = attributes[:undeleted_by] || attributes['undeleted_by'] + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + undeleted_by: 'undeleted_by' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/undelete_message_response.rb b/lib/getstream_ruby/generated/models/undelete_message_response.rb new file mode 100644 index 0000000..ab348cb --- /dev/null +++ b/lib/getstream_ruby/generated/models/undelete_message_response.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Basic response information + class UndeleteMessageResponse < GetStream::BaseModel + + # Model attributes + # @!attribute duration + # @return [String] Duration of the request in milliseconds + attr_accessor :duration + # @!attribute message + # @return [MessageResponse] + attr_accessor :message + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @duration = attributes[:duration] || attributes['duration'] + @message = attributes[:message] || attributes['message'] + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + duration: 'duration', + message: 'message' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/unfollow_batch_request.rb b/lib/getstream_ruby/generated/models/unfollow_batch_request.rb index 157eb6b..be57444 100644 --- a/lib/getstream_ruby/generated/models/unfollow_batch_request.rb +++ b/lib/getstream_ruby/generated/models/unfollow_batch_request.rb @@ -15,19 +15,24 @@ class UnfollowBatchRequest < GetStream::BaseModel # @!attribute delete_notification_activity # @return [Boolean] Whether to delete the corresponding notification activity (default: false) attr_accessor :delete_notification_activity + # @!attribute enrich_own_fields + # @return [Boolean] If true, enriches the follow's source_feed and target_feed with own_* fields (own_follows, own_followings, own_capabilities, own_membership). Defaults to false for performance. + attr_accessor :enrich_own_fields # Initialize with attributes def initialize(attributes = {}) super(attributes) @follows = attributes[:follows] || attributes['follows'] @delete_notification_activity = attributes[:delete_notification_activity] || attributes['delete_notification_activity'] || nil + @enrich_own_fields = attributes[:enrich_own_fields] || attributes['enrich_own_fields'] || nil end # Override field mappings for JSON serialization def self.json_field_mappings { follows: 'follows', - delete_notification_activity: 'delete_notification_activity' + delete_notification_activity: 'delete_notification_activity', + enrich_own_fields: 'enrich_own_fields' } end end diff --git a/lib/getstream_ruby/generated/models/unfollow_request.rb b/lib/getstream_ruby/generated/models/unfollow_request.rb new file mode 100644 index 0000000..83c3221 --- /dev/null +++ b/lib/getstream_ruby/generated/models/unfollow_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class UnfollowRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/unpin_activity_request.rb b/lib/getstream_ruby/generated/models/unpin_activity_request.rb new file mode 100644 index 0000000..101a8d3 --- /dev/null +++ b/lib/getstream_ruby/generated/models/unpin_activity_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class UnpinActivityRequest < GetStream::BaseModel + # Empty model - inherits all functionality from BaseModel + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/update_activity_partial_request.rb b/lib/getstream_ruby/generated/models/update_activity_partial_request.rb index 8888b3c..05590f7 100644 --- a/lib/getstream_ruby/generated/models/update_activity_partial_request.rb +++ b/lib/getstream_ruby/generated/models/update_activity_partial_request.rb @@ -12,6 +12,9 @@ class UpdateActivityPartialRequest < GetStream::BaseModel # @!attribute copy_custom_to_notification # @return [Boolean] Whether to copy custom data to the notification activity (only applies when handle_mention_notifications creates notifications) attr_accessor :copy_custom_to_notification + # @!attribute enrich_own_fields + # @return [Boolean] If true, enriches the activity's current_feed with own_* fields (own_follows, own_followings, own_capabilities, own_membership). Defaults to false for performance. + attr_accessor :enrich_own_fields # @!attribute handle_mention_notifications # @return [Boolean] If true, creates notification activities for newly mentioned users and deletes notifications for users no longer mentioned attr_accessor :handle_mention_notifications @@ -35,6 +38,7 @@ class UpdateActivityPartialRequest < GetStream::BaseModel def initialize(attributes = {}) super(attributes) @copy_custom_to_notification = attributes[:copy_custom_to_notification] || attributes['copy_custom_to_notification'] || nil + @enrich_own_fields = attributes[:enrich_own_fields] || attributes['enrich_own_fields'] || nil @handle_mention_notifications = attributes[:handle_mention_notifications] || attributes['handle_mention_notifications'] || nil @run_activity_processors = attributes[:run_activity_processors] || attributes['run_activity_processors'] || nil @user_id = attributes[:user_id] || attributes['user_id'] || nil @@ -47,6 +51,7 @@ def initialize(attributes = {}) def self.json_field_mappings { copy_custom_to_notification: 'copy_custom_to_notification', + enrich_own_fields: 'enrich_own_fields', handle_mention_notifications: 'handle_mention_notifications', run_activity_processors: 'run_activity_processors', user_id: 'user_id', diff --git a/lib/getstream_ruby/generated/models/update_activity_request.rb b/lib/getstream_ruby/generated/models/update_activity_request.rb index 6d03d9b..483f923 100644 --- a/lib/getstream_ruby/generated/models/update_activity_request.rb +++ b/lib/getstream_ruby/generated/models/update_activity_request.rb @@ -12,6 +12,9 @@ class UpdateActivityRequest < GetStream::BaseModel # @!attribute copy_custom_to_notification # @return [Boolean] Whether to copy custom data to the notification activity (only applies when handle_mention_notifications creates notifications) attr_accessor :copy_custom_to_notification + # @!attribute enrich_own_fields + # @return [Boolean] If true, enriches the activity's current_feed with own_* fields (own_follows, own_followings, own_capabilities, own_membership). Defaults to false for performance. + attr_accessor :enrich_own_fields # @!attribute expires_at # @return [DateTime] Time when the activity will expire attr_accessor :expires_at @@ -77,6 +80,7 @@ class UpdateActivityRequest < GetStream::BaseModel def initialize(attributes = {}) super(attributes) @copy_custom_to_notification = attributes[:copy_custom_to_notification] || attributes['copy_custom_to_notification'] || nil + @enrich_own_fields = attributes[:enrich_own_fields] || attributes['enrich_own_fields'] || nil @expires_at = attributes[:expires_at] || attributes['expires_at'] || nil @handle_mention_notifications = attributes[:handle_mention_notifications] || attributes['handle_mention_notifications'] || nil @poll_id = attributes[:poll_id] || attributes['poll_id'] || nil @@ -103,6 +107,7 @@ def initialize(attributes = {}) def self.json_field_mappings { copy_custom_to_notification: 'copy_custom_to_notification', + enrich_own_fields: 'enrich_own_fields', expires_at: 'expires_at', handle_mention_notifications: 'handle_mention_notifications', poll_id: 'poll_id', diff --git a/lib/getstream_ruby/generated/models/update_app_request.rb b/lib/getstream_ruby/generated/models/update_app_request.rb index 6644078..91d7b24 100644 --- a/lib/getstream_ruby/generated/models/update_app_request.rb +++ b/lib/getstream_ruby/generated/models/update_app_request.rb @@ -54,9 +54,15 @@ class UpdateAppRequest < GetStream::BaseModel # @!attribute migrate_permissions_to_v2 # @return [Boolean] attr_accessor :migrate_permissions_to_v2 + # @!attribute moderation_analytics_enabled + # @return [Boolean] + attr_accessor :moderation_analytics_enabled # @!attribute moderation_enabled # @return [Boolean] attr_accessor :moderation_enabled + # @!attribute moderation_s3_image_access_role_arn + # @return [String] + attr_accessor :moderation_s3_image_access_role_arn # @!attribute moderation_webhook_url # @return [String] attr_accessor :moderation_webhook_url @@ -169,7 +175,9 @@ def initialize(attributes = {}) @image_moderation_enabled = attributes[:image_moderation_enabled] || attributes['image_moderation_enabled'] || nil @max_aggregated_activities_length = attributes[:max_aggregated_activities_length] || attributes['max_aggregated_activities_length'] || nil @migrate_permissions_to_v2 = attributes[:migrate_permissions_to_v2] || attributes['migrate_permissions_to_v2'] || nil + @moderation_analytics_enabled = attributes[:moderation_analytics_enabled] || attributes['moderation_analytics_enabled'] || nil @moderation_enabled = attributes[:moderation_enabled] || attributes['moderation_enabled'] || nil + @moderation_s3_image_access_role_arn = attributes[:moderation_s3_image_access_role_arn] || attributes['moderation_s3_image_access_role_arn'] || nil @moderation_webhook_url = attributes[:moderation_webhook_url] || attributes['moderation_webhook_url'] || nil @multi_tenant_enabled = attributes[:multi_tenant_enabled] || attributes['multi_tenant_enabled'] || nil @permission_version = attributes[:permission_version] || attributes['permission_version'] || nil @@ -221,7 +229,9 @@ def self.json_field_mappings image_moderation_enabled: 'image_moderation_enabled', max_aggregated_activities_length: 'max_aggregated_activities_length', migrate_permissions_to_v2: 'migrate_permissions_to_v2', + moderation_analytics_enabled: 'moderation_analytics_enabled', moderation_enabled: 'moderation_enabled', + moderation_s3_image_access_role_arn: 'moderation_s3_image_access_role_arn', moderation_webhook_url: 'moderation_webhook_url', multi_tenant_enabled: 'multi_tenant_enabled', permission_version: 'permission_version', diff --git a/lib/getstream_ruby/generated/models/update_feed_request.rb b/lib/getstream_ruby/generated/models/update_feed_request.rb index e40f389..0e73c92 100644 --- a/lib/getstream_ruby/generated/models/update_feed_request.rb +++ b/lib/getstream_ruby/generated/models/update_feed_request.rb @@ -15,6 +15,9 @@ class UpdateFeedRequest < GetStream::BaseModel # @!attribute description # @return [String] Description of the feed attr_accessor :description + # @!attribute enrich_own_fields + # @return [Boolean] If true, enriches the feed with own_* fields (own_follows, own_followings, own_capabilities, own_membership). Defaults to false for performance. + attr_accessor :enrich_own_fields # @!attribute name # @return [String] Name of the feed attr_accessor :name @@ -30,6 +33,7 @@ def initialize(attributes = {}) super(attributes) @created_by_id = attributes[:created_by_id] || attributes['created_by_id'] || nil @description = attributes[:description] || attributes['description'] || nil + @enrich_own_fields = attributes[:enrich_own_fields] || attributes['enrich_own_fields'] || nil @name = attributes[:name] || attributes['name'] || nil @filter_tags = attributes[:filter_tags] || attributes['filter_tags'] || nil @custom = attributes[:custom] || attributes['custom'] || nil @@ -40,6 +44,7 @@ def self.json_field_mappings { created_by_id: 'created_by_id', description: 'description', + enrich_own_fields: 'enrich_own_fields', name: 'name', filter_tags: 'filter_tags', custom: 'custom' diff --git a/lib/getstream_ruby/generated/models/update_follow_request.rb b/lib/getstream_ruby/generated/models/update_follow_request.rb index 8c53e45..1615e1e 100644 --- a/lib/getstream_ruby/generated/models/update_follow_request.rb +++ b/lib/getstream_ruby/generated/models/update_follow_request.rb @@ -21,6 +21,9 @@ class UpdateFollowRequest < GetStream::BaseModel # @!attribute create_notification_activity # @return [Boolean] Whether to create a notification activity for this follow attr_accessor :create_notification_activity + # @!attribute enrich_own_fields + # @return [Boolean] If true, enriches the follow's source_feed and target_feed with own_* fields (own_follows, own_followings, own_capabilities, own_membership). Defaults to false for performance. + attr_accessor :enrich_own_fields # @!attribute follower_role # @return [String] attr_accessor :follower_role @@ -44,6 +47,7 @@ def initialize(attributes = {}) @target = attributes[:target] || attributes['target'] @copy_custom_to_notification = attributes[:copy_custom_to_notification] || attributes['copy_custom_to_notification'] || nil @create_notification_activity = attributes[:create_notification_activity] || attributes['create_notification_activity'] || nil + @enrich_own_fields = attributes[:enrich_own_fields] || attributes['enrich_own_fields'] || nil @follower_role = attributes[:follower_role] || attributes['follower_role'] || nil @push_preference = attributes[:push_preference] || attributes['push_preference'] || nil @skip_push = attributes[:skip_push] || attributes['skip_push'] || nil @@ -58,6 +62,7 @@ def self.json_field_mappings target: 'target', copy_custom_to_notification: 'copy_custom_to_notification', create_notification_activity: 'create_notification_activity', + enrich_own_fields: 'enrich_own_fields', follower_role: 'follower_role', push_preference: 'push_preference', skip_push: 'skip_push', diff --git a/lib/getstream_ruby/generated/models/update_user_group_request.rb b/lib/getstream_ruby/generated/models/update_user_group_request.rb new file mode 100644 index 0000000..793c3e0 --- /dev/null +++ b/lib/getstream_ruby/generated/models/update_user_group_request.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Request body for updating a user group + class UpdateUserGroupRequest < GetStream::BaseModel + + # Model attributes + # @!attribute description + # @return [String] The new description for the group + attr_accessor :description + # @!attribute name + # @return [String] The new name of the user group + attr_accessor :name + # @!attribute team_id + # @return [String] + attr_accessor :team_id + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @description = attributes[:description] || attributes['description'] || nil + @name = attributes[:name] || attributes['name'] || nil + @team_id = attributes[:team_id] || attributes['team_id'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + description: 'description', + name: 'name', + team_id: 'team_id' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/update_user_group_response.rb b/lib/getstream_ruby/generated/models/update_user_group_response.rb new file mode 100644 index 0000000..9e98bbf --- /dev/null +++ b/lib/getstream_ruby/generated/models/update_user_group_response.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Response for updating a user group + class UpdateUserGroupResponse < GetStream::BaseModel + + # Model attributes + # @!attribute duration + # @return [String] + attr_accessor :duration + # @!attribute user_group + # @return [UserGroupResponse] + attr_accessor :user_group + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @duration = attributes[:duration] || attributes['duration'] + @user_group = attributes[:user_group] || attributes['user_group'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + duration: 'duration', + user_group: 'user_group' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/upsert_activities_request.rb b/lib/getstream_ruby/generated/models/upsert_activities_request.rb index 1662749..9cbf1ba 100644 --- a/lib/getstream_ruby/generated/models/upsert_activities_request.rb +++ b/lib/getstream_ruby/generated/models/upsert_activities_request.rb @@ -12,17 +12,22 @@ class UpsertActivitiesRequest < GetStream::BaseModel # @!attribute activities # @return [Array] List of activities to create or update attr_accessor :activities + # @!attribute enrich_own_fields + # @return [Boolean] If true, enriches the activities' current_feed with own_* fields (own_follows, own_followings, own_capabilities, own_membership). Defaults to false for performance. + attr_accessor :enrich_own_fields # Initialize with attributes def initialize(attributes = {}) super(attributes) @activities = attributes[:activities] || attributes['activities'] + @enrich_own_fields = attributes[:enrich_own_fields] || attributes['enrich_own_fields'] || nil end # Override field mappings for JSON serialization def self.json_field_mappings { - activities: 'activities' + activities: 'activities', + enrich_own_fields: 'enrich_own_fields' } end end diff --git a/lib/getstream_ruby/generated/models/user_group.rb b/lib/getstream_ruby/generated/models/user_group.rb new file mode 100644 index 0000000..6328ecd --- /dev/null +++ b/lib/getstream_ruby/generated/models/user_group.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class UserGroup < GetStream::BaseModel + + # Model attributes + # @!attribute app_pk + # @return [Integer] + attr_accessor :app_pk + # @!attribute created_at + # @return [DateTime] + attr_accessor :created_at + # @!attribute id + # @return [String] + attr_accessor :id + # @!attribute name + # @return [String] + attr_accessor :name + # @!attribute updated_at + # @return [DateTime] + attr_accessor :updated_at + # @!attribute created_by + # @return [String] + attr_accessor :created_by + # @!attribute description + # @return [String] + attr_accessor :description + # @!attribute team_id + # @return [String] + attr_accessor :team_id + # @!attribute members + # @return [Array] + attr_accessor :members + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @app_pk = attributes[:app_pk] || attributes['app_pk'] + @created_at = attributes[:created_at] || attributes['created_at'] + @id = attributes[:id] || attributes['id'] + @name = attributes[:name] || attributes['name'] + @updated_at = attributes[:updated_at] || attributes['updated_at'] + @created_by = attributes[:created_by] || attributes['created_by'] || nil + @description = attributes[:description] || attributes['description'] || nil + @team_id = attributes[:team_id] || attributes['team_id'] || nil + @members = attributes[:members] || attributes['members'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + app_pk: 'app_pk', + created_at: 'created_at', + id: 'id', + name: 'name', + updated_at: 'updated_at', + created_by: 'created_by', + description: 'description', + team_id: 'team_id', + members: 'members' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/user_group_created_event.rb b/lib/getstream_ruby/generated/models/user_group_created_event.rb new file mode 100644 index 0000000..cbe7234 --- /dev/null +++ b/lib/getstream_ruby/generated/models/user_group_created_event.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Emitted when a user group is created. + class UserGroupCreatedEvent < GetStream::BaseModel + + # Model attributes + # @!attribute created_at + # @return [DateTime] Date/time of creation + attr_accessor :created_at + # @!attribute custom + # @return [Object] + attr_accessor :custom + # @!attribute type + # @return [String] The type of event: "user_group.created" in this case + attr_accessor :type + # @!attribute received_at + # @return [DateTime] + attr_accessor :received_at + # @!attribute user + # @return [UserResponseCommonFields] + attr_accessor :user + # @!attribute user_group + # @return [UserGroup] + attr_accessor :user_group + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @created_at = attributes[:created_at] || attributes['created_at'] + @custom = attributes[:custom] || attributes['custom'] + @type = attributes[:type] || attributes['type'] || "user_group.created" + @received_at = attributes[:received_at] || attributes['received_at'] || nil + @user = attributes[:user] || attributes['user'] || nil + @user_group = attributes[:user_group] || attributes['user_group'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + created_at: 'created_at', + custom: 'custom', + type: 'type', + received_at: 'received_at', + user: 'user', + user_group: 'user_group' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/user_group_deleted_event.rb b/lib/getstream_ruby/generated/models/user_group_deleted_event.rb new file mode 100644 index 0000000..b09fc27 --- /dev/null +++ b/lib/getstream_ruby/generated/models/user_group_deleted_event.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Emitted when a user group is deleted. + class UserGroupDeletedEvent < GetStream::BaseModel + + # Model attributes + # @!attribute created_at + # @return [DateTime] Date/time of creation + attr_accessor :created_at + # @!attribute custom + # @return [Object] + attr_accessor :custom + # @!attribute type + # @return [String] The type of event: "user_group.deleted" in this case + attr_accessor :type + # @!attribute received_at + # @return [DateTime] + attr_accessor :received_at + # @!attribute user + # @return [UserResponseCommonFields] + attr_accessor :user + # @!attribute user_group + # @return [UserGroup] + attr_accessor :user_group + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @created_at = attributes[:created_at] || attributes['created_at'] + @custom = attributes[:custom] || attributes['custom'] + @type = attributes[:type] || attributes['type'] || "user_group.deleted" + @received_at = attributes[:received_at] || attributes['received_at'] || nil + @user = attributes[:user] || attributes['user'] || nil + @user_group = attributes[:user_group] || attributes['user_group'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + created_at: 'created_at', + custom: 'custom', + type: 'type', + received_at: 'received_at', + user: 'user', + user_group: 'user_group' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/user_group_member.rb b/lib/getstream_ruby/generated/models/user_group_member.rb new file mode 100644 index 0000000..75aef41 --- /dev/null +++ b/lib/getstream_ruby/generated/models/user_group_member.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class UserGroupMember < GetStream::BaseModel + + # Model attributes + # @!attribute app_pk + # @return [Integer] + attr_accessor :app_pk + # @!attribute created_at + # @return [DateTime] + attr_accessor :created_at + # @!attribute group_id + # @return [String] + attr_accessor :group_id + # @!attribute is_admin + # @return [Boolean] + attr_accessor :is_admin + # @!attribute user_id + # @return [String] + attr_accessor :user_id + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @app_pk = attributes[:app_pk] || attributes['app_pk'] + @created_at = attributes[:created_at] || attributes['created_at'] + @group_id = attributes[:group_id] || attributes['group_id'] + @is_admin = attributes[:is_admin] || attributes['is_admin'] + @user_id = attributes[:user_id] || attributes['user_id'] + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + app_pk: 'app_pk', + created_at: 'created_at', + group_id: 'group_id', + is_admin: 'is_admin', + user_id: 'user_id' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/user_group_member_added_event.rb b/lib/getstream_ruby/generated/models/user_group_member_added_event.rb new file mode 100644 index 0000000..7efeccd --- /dev/null +++ b/lib/getstream_ruby/generated/models/user_group_member_added_event.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Emitted when members are added to a user group. + class UserGroupMemberAddedEvent < GetStream::BaseModel + + # Model attributes + # @!attribute created_at + # @return [DateTime] Date/time of creation + attr_accessor :created_at + # @!attribute members + # @return [Array] The user IDs that were added + attr_accessor :members + # @!attribute custom + # @return [Object] + attr_accessor :custom + # @!attribute type + # @return [String] The type of event: "user_group.member_added" in this case + attr_accessor :type + # @!attribute received_at + # @return [DateTime] + attr_accessor :received_at + # @!attribute user + # @return [UserResponseCommonFields] + attr_accessor :user + # @!attribute user_group + # @return [UserGroup] + attr_accessor :user_group + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @created_at = attributes[:created_at] || attributes['created_at'] + @members = attributes[:members] || attributes['members'] + @custom = attributes[:custom] || attributes['custom'] + @type = attributes[:type] || attributes['type'] || "user_group.member_added" + @received_at = attributes[:received_at] || attributes['received_at'] || nil + @user = attributes[:user] || attributes['user'] || nil + @user_group = attributes[:user_group] || attributes['user_group'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + created_at: 'created_at', + members: 'members', + custom: 'custom', + type: 'type', + received_at: 'received_at', + user: 'user', + user_group: 'user_group' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/user_group_member_removed_event.rb b/lib/getstream_ruby/generated/models/user_group_member_removed_event.rb new file mode 100644 index 0000000..c6edf41 --- /dev/null +++ b/lib/getstream_ruby/generated/models/user_group_member_removed_event.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Emitted when members are removed from a user group. + class UserGroupMemberRemovedEvent < GetStream::BaseModel + + # Model attributes + # @!attribute created_at + # @return [DateTime] Date/time of creation + attr_accessor :created_at + # @!attribute members + # @return [Array] The user IDs that were removed + attr_accessor :members + # @!attribute custom + # @return [Object] + attr_accessor :custom + # @!attribute type + # @return [String] The type of event: "user_group.member_removed" in this case + attr_accessor :type + # @!attribute received_at + # @return [DateTime] + attr_accessor :received_at + # @!attribute user + # @return [UserResponseCommonFields] + attr_accessor :user + # @!attribute user_group + # @return [UserGroup] + attr_accessor :user_group + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @created_at = attributes[:created_at] || attributes['created_at'] + @members = attributes[:members] || attributes['members'] + @custom = attributes[:custom] || attributes['custom'] + @type = attributes[:type] || attributes['type'] || "user_group.member_removed" + @received_at = attributes[:received_at] || attributes['received_at'] || nil + @user = attributes[:user] || attributes['user'] || nil + @user_group = attributes[:user_group] || attributes['user_group'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + created_at: 'created_at', + members: 'members', + custom: 'custom', + type: 'type', + received_at: 'received_at', + user: 'user', + user_group: 'user_group' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/user_group_response.rb b/lib/getstream_ruby/generated/models/user_group_response.rb new file mode 100644 index 0000000..2d7d8c0 --- /dev/null +++ b/lib/getstream_ruby/generated/models/user_group_response.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # + class UserGroupResponse < GetStream::BaseModel + + # Model attributes + # @!attribute created_at + # @return [DateTime] + attr_accessor :created_at + # @!attribute id + # @return [String] + attr_accessor :id + # @!attribute name + # @return [String] + attr_accessor :name + # @!attribute updated_at + # @return [DateTime] + attr_accessor :updated_at + # @!attribute created_by + # @return [String] + attr_accessor :created_by + # @!attribute description + # @return [String] + attr_accessor :description + # @!attribute team_id + # @return [String] + attr_accessor :team_id + # @!attribute members + # @return [Array] + attr_accessor :members + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @created_at = attributes[:created_at] || attributes['created_at'] + @id = attributes[:id] || attributes['id'] + @name = attributes[:name] || attributes['name'] + @updated_at = attributes[:updated_at] || attributes['updated_at'] + @created_by = attributes[:created_by] || attributes['created_by'] || nil + @description = attributes[:description] || attributes['description'] || nil + @team_id = attributes[:team_id] || attributes['team_id'] || nil + @members = attributes[:members] || attributes['members'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + created_at: 'created_at', + id: 'id', + name: 'name', + updated_at: 'updated_at', + created_by: 'created_by', + description: 'description', + team_id: 'team_id', + members: 'members' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/models/user_group_updated_event.rb b/lib/getstream_ruby/generated/models/user_group_updated_event.rb new file mode 100644 index 0000000..3ebb5c2 --- /dev/null +++ b/lib/getstream_ruby/generated/models/user_group_updated_event.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +module GetStream + module Generated + module Models + # Emitted when a user group is updated. + class UserGroupUpdatedEvent < GetStream::BaseModel + + # Model attributes + # @!attribute created_at + # @return [DateTime] Date/time of creation + attr_accessor :created_at + # @!attribute custom + # @return [Object] + attr_accessor :custom + # @!attribute type + # @return [String] The type of event: "user_group.updated" in this case + attr_accessor :type + # @!attribute received_at + # @return [DateTime] + attr_accessor :received_at + # @!attribute user + # @return [UserResponseCommonFields] + attr_accessor :user + # @!attribute user_group + # @return [UserGroup] + attr_accessor :user_group + + # Initialize with attributes + def initialize(attributes = {}) + super(attributes) + @created_at = attributes[:created_at] || attributes['created_at'] + @custom = attributes[:custom] || attributes['custom'] + @type = attributes[:type] || attributes['type'] || "user_group.updated" + @received_at = attributes[:received_at] || attributes['received_at'] || nil + @user = attributes[:user] || attributes['user'] || nil + @user_group = attributes[:user_group] || attributes['user_group'] || nil + end + + # Override field mappings for JSON serialization + def self.json_field_mappings + { + created_at: 'created_at', + custom: 'custom', + type: 'type', + received_at: 'received_at', + user: 'user', + user_group: 'user_group' + } + end + end + end + end +end diff --git a/lib/getstream_ruby/generated/moderation_client.rb b/lib/getstream_ruby/generated/moderation_client.rb index 0468613..80d7fd9 100644 --- a/lib/getstream_ruby/generated/moderation_client.rb +++ b/lib/getstream_ruby/generated/moderation_client.rb @@ -113,6 +113,23 @@ def check(check_request) ) end + # Verifies that the configured IAM role ARN can access private S3 images for moderation. Optionally accepts a stream+s3:// URL to check access to a specific object. + # + # @param check_s3_access_request [CheckS3AccessRequest] + # @return [Models::CheckS3AccessResponse] + def check_s3_access(check_s3_access_request) + path = '/api/v2/moderation/check_s3_access' + # Build request body + body = check_s3_access_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + # Create a new moderation configuration or update an existing one. Configure settings for content filtering, AI analysis, toxicity detection, and other moderation features. # # @param upsert_config_request [UpsertConfigRequest] diff --git a/lib/getstream_ruby/generated/video_client.rb b/lib/getstream_ruby/generated/video_client.rb new file mode 100644 index 0000000..6e25c98 --- /dev/null +++ b/lib/getstream_ruby/generated/video_client.rb @@ -0,0 +1,1385 @@ +# frozen_string_literal: true + +# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT. + +# Load all models at once +Dir[File.join(__dir__, "models", "*.rb")].sort.each { |file| require_relative file } + +module GetStream + module Generated + # Video API client with generated methods + class VideoClient + def initialize(client) + @client = client + end + # Get the current status of all active calls including metrics and summary information + # + # @return [Models::GetActiveCallsStatusResponse] + def get_active_calls_status() + path = '/api/v2/video/active_calls_status' + + # Make the API request + @client.make_request( + :get, + path + ) + end + + # + # + # @param query_user_feedback_request [QueryUserFeedbackRequest] + # @param full [Boolean] + # @return [Models::QueryUserFeedbackResponse] + def query_user_feedback(query_user_feedback_request, full = nil) + path = '/api/v2/video/call/feedback' + # Build query parameters + query_params = {} + query_params['full'] = full unless full.nil? + # Build request body + body = query_user_feedback_request + + # Make the API request + @client.make_request( + :post, + path, + query_params: query_params, + body: body + ) + end + + # Query call members with filter query + # + # @param query_call_members_request [QueryCallMembersRequest] + # @return [Models::QueryCallMembersResponse] + def query_call_members(query_call_members_request) + path = '/api/v2/video/call/members' + # Build request body + body = query_call_members_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # + # + # @param query_call_stats_request [QueryCallStatsRequest] + # @return [Models::QueryCallStatsResponse] + def query_call_stats(query_call_stats_request) + path = '/api/v2/video/call/stats' + # Build request body + body = query_call_stats_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # + # + # @param _type [String] + # @param _id [String] + # @param members_limit [Integer] + # @param ring [Boolean] + # @param notify [Boolean] + # @param video [Boolean] + # @return [Models::GetCallResponse] + def get_call(_type, _id, members_limit = nil, ring = nil, notify = nil, video = nil) + path = '/api/v2/video/call/{type}/{id}' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build query parameters + query_params = {} + query_params['members_limit'] = members_limit unless members_limit.nil? + query_params['ring'] = ring unless ring.nil? + query_params['notify'] = notify unless notify.nil? + query_params['video'] = video unless video.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Sends events:- call.updated + # + # @param _type [String] + # @param _id [String] + # @param update_call_request [UpdateCallRequest] + # @return [Models::UpdateCallResponse] + def update_call(_type, _id, update_call_request) + path = '/api/v2/video/call/{type}/{id}' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = update_call_request + + # Make the API request + @client.make_request( + :patch, + path, + body: body + ) + end + + # Gets or creates a new callSends events:- call.created- call.notification- call.ring + # + # @param _type [String] + # @param _id [String] + # @param get_or_create_call_request [GetOrCreateCallRequest] + # @return [Models::GetOrCreateCallResponse] + def get_or_create_call(_type, _id, get_or_create_call_request) + path = '/api/v2/video/call/{type}/{id}' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = get_or_create_call_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Block a user, preventing them from joining the call until they are unblocked.Sends events:- call.blocked_user + # + # @param _type [String] + # @param _id [String] + # @param block_user_request [BlockUserRequest] + # @return [Models::BlockUserResponse] + def block_user(_type, _id, block_user_request) + path = '/api/v2/video/call/{type}/{id}/block' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = block_user_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Sends a closed caption event to the callSends events:- call.closed_caption + # + # @param _type [String] + # @param _id [String] + # @param send_closed_caption_request [SendClosedCaptionRequest] + # @return [Models::SendClosedCaptionResponse] + def send_closed_caption(_type, _id, send_closed_caption_request) + path = '/api/v2/video/call/{type}/{id}/closed_captions' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = send_closed_caption_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Sends events:- call.deleted + # + # @param _type [String] + # @param _id [String] + # @param delete_call_request [DeleteCallRequest] + # @return [Models::DeleteCallResponse] + def delete_call(_type, _id, delete_call_request) + path = '/api/v2/video/call/{type}/{id}/delete' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = delete_call_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Sends custom event to the callSends events:- custom + # + # @param _type [String] + # @param _id [String] + # @param send_call_event_request [SendCallEventRequest] + # @return [Models::SendCallEventResponse] + def send_call_event(_type, _id, send_call_event_request) + path = '/api/v2/video/call/{type}/{id}/event' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = send_call_event_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Sends events:- call.user_feedback_submitted + # + # @param _type [String] + # @param _id [String] + # @param collect_user_feedback_request [CollectUserFeedbackRequest] + # @return [Models::CollectUserFeedbackResponse] + def collect_user_feedback(_type, _id, collect_user_feedback_request) + path = '/api/v2/video/call/{type}/{id}/feedback' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = collect_user_feedback_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Sends events:- call.live_started + # + # @param _type [String] + # @param _id [String] + # @param go_live_request [GoLiveRequest] + # @return [Models::GoLiveResponse] + def go_live(_type, _id, go_live_request) + path = '/api/v2/video/call/{type}/{id}/go_live' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = go_live_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Kicks a user from the call. Optionally block the user from rejoining by setting block=true.Sends events:- call.blocked_user- call.kicked_user + # + # @param _type [String] + # @param _id [String] + # @param kick_user_request [KickUserRequest] + # @return [Models::KickUserResponse] + def kick_user(_type, _id, kick_user_request) + path = '/api/v2/video/call/{type}/{id}/kick' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = kick_user_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Sends events:- call.ended + # + # @param _type [String] + # @param _id [String] + # @return [Models::EndCallResponse] + def end_call(_type, _id) + path = '/api/v2/video/call/{type}/{id}/mark_ended' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + + # Make the API request + @client.make_request( + :post, + path + ) + end + + # Sends events:- call.member_added- call.member_removed- call.member_updated + # + # @param _type [String] + # @param _id [String] + # @param update_call_members_request [UpdateCallMembersRequest] + # @return [Models::UpdateCallMembersResponse] + def update_call_members(_type, _id, update_call_members_request) + path = '/api/v2/video/call/{type}/{id}/members' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = update_call_members_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Mutes users in a call + # + # @param _type [String] + # @param _id [String] + # @param mute_users_request [MuteUsersRequest] + # @return [Models::MuteUsersResponse] + def mute_users(_type, _id, mute_users_request) + path = '/api/v2/video/call/{type}/{id}/mute_users' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = mute_users_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Returns a list of participants connected to the call + # + # @param _id [String] + # @param _type [String] + # @param query_call_participants_request [QueryCallParticipantsRequest] + # @param limit [Integer] + # @return [Models::QueryCallParticipantsResponse] + def query_call_participants(_id, _type, query_call_participants_request, limit = nil) + path = '/api/v2/video/call/{type}/{id}/participants' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + path = path.gsub('{type}', _type.to_s) + # Build query parameters + query_params = {} + query_params['limit'] = limit unless limit.nil? + # Build request body + body = query_call_participants_request + + # Make the API request + @client.make_request( + :post, + path, + query_params: query_params, + body: body + ) + end + + # Pins a track for all users in the call. + # + # @param _type [String] + # @param _id [String] + # @param pin_request [PinRequest] + # @return [Models::PinResponse] + def video_pin(_type, _id, pin_request) + path = '/api/v2/video/call/{type}/{id}/pin' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = pin_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Lists recordings + # + # @param _type [String] + # @param _id [String] + # @return [Models::ListRecordingsResponse] + def list_recordings(_type, _id) + path = '/api/v2/video/call/{type}/{id}/recordings' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + + # Make the API request + @client.make_request( + :get, + path + ) + end + + # Starts recordingSends events:- call.recording_started + # + # @param _type [String] + # @param _id [String] + # @param recording_type [String] + # @param start_recording_request [StartRecordingRequest] + # @return [Models::StartRecordingResponse] + def start_recording(_type, _id, recording_type, start_recording_request) + path = '/api/v2/video/call/{type}/{id}/recordings/{recording_type}/start' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + path = path.gsub('{recording_type}', recording_type.to_s) + # Build request body + body = start_recording_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Stops recordingSends events:- call.recording_stopped + # + # @param _type [String] + # @param _id [String] + # @param recording_type [String] + # @param stop_recording_request [StopRecordingRequest] + # @return [Models::StopRecordingResponse] + def stop_recording(_type, _id, recording_type, stop_recording_request) + path = '/api/v2/video/call/{type}/{id}/recordings/{recording_type}/stop' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + path = path.gsub('{recording_type}', recording_type.to_s) + # Build request body + body = stop_recording_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # + # + # @param _type [String] + # @param _id [String] + # @param session_id [String] + # @return [Models::GetCallReportResponse] + def get_call_report(_type, _id, session_id = nil) + path = '/api/v2/video/call/{type}/{id}/report' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build query parameters + query_params = {} + query_params['session_id'] = session_id unless session_id.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Sends a ring notification to the provided users who are not already in the call. All users should be members of the callSends events:- call.ring + # + # @param _type [String] + # @param _id [String] + # @param ring_call_request [RingCallRequest] + # @return [Models::RingCallResponse] + def ring_call(_type, _id, ring_call_request) + path = '/api/v2/video/call/{type}/{id}/ring' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = ring_call_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Starts RTMP broadcasts for the provided RTMP destinations + # + # @param _type [String] + # @param _id [String] + # @param start_rtmp_broadcasts_request [StartRTMPBroadcastsRequest] + # @return [Models::StartRTMPBroadcastsResponse] + def start_rtmp_broadcasts(_type, _id, start_rtmp_broadcasts_request) + path = '/api/v2/video/call/{type}/{id}/rtmp_broadcasts' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = start_rtmp_broadcasts_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Stop all RTMP broadcasts for the provided call + # + # @param _type [String] + # @param _id [String] + # @return [Models::StopAllRTMPBroadcastsResponse] + def stop_all_rtmp_broadcasts(_type, _id) + path = '/api/v2/video/call/{type}/{id}/rtmp_broadcasts/stop' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + + # Make the API request + @client.make_request( + :post, + path + ) + end + + # Stop RTMP broadcasts for the provided RTMP destinations + # + # @param _type [String] + # @param _id [String] + # @param name [String] + # @param stop_rtmp_broadcasts_request [StopRTMPBroadcastsRequest] + # @return [Models::StopRTMPBroadcastsResponse] + def stop_rtmp_broadcast(_type, _id, name, stop_rtmp_broadcasts_request) + path = '/api/v2/video/call/{type}/{id}/rtmp_broadcasts/{name}/stop' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + path = path.gsub('{name}', name.to_s) + # Build request body + body = stop_rtmp_broadcasts_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # + # + # @param _type [String] + # @param _id [String] + # @param session [String] + # @param user [String] + # @param user_session [String] + # @param since [DateTime] + # @param _until [DateTime] + # @return [Models::GetCallParticipantSessionMetricsResponse] + def get_call_participant_session_metrics(_type, _id, session, user, user_session, since = nil, _until = nil) + path = '/api/v2/video/call/{type}/{id}/session/{session}/participant/{user}/{user_session}/details/track' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + path = path.gsub('{session}', session.to_s) + path = path.gsub('{user}', user.to_s) + path = path.gsub('{user_session}', user_session.to_s) + # Build query parameters + query_params = {} + query_params['since'] = since unless since.nil? + query_params['until'] = _until unless _until.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # + # + # @param _type [String] + # @param _id [String] + # @param session [String] + # @param limit [Integer] + # @param prev [String] + # @param _next [String] + # @param filter_conditions [Object] + # @return [Models::QueryCallParticipantSessionsResponse] + def query_call_participant_sessions(_type, _id, session, limit = nil, prev = nil, _next = nil, filter_conditions = nil) + path = '/api/v2/video/call/{type}/{id}/session/{session}/participant_sessions' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + path = path.gsub('{session}', session.to_s) + # Build query parameters + query_params = {} + query_params['limit'] = limit unless limit.nil? + query_params['prev'] = prev unless prev.nil? + query_params['next'] = _next unless _next.nil? + query_params['filter_conditions'] = filter_conditions unless filter_conditions.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Starts HLS broadcasting + # + # @param _type [String] + # @param _id [String] + # @return [Models::StartHLSBroadcastingResponse] + def start_hls_broadcasting(_type, _id) + path = '/api/v2/video/call/{type}/{id}/start_broadcasting' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + + # Make the API request + @client.make_request( + :post, + path + ) + end + + # Starts closed captions + # + # @param _type [String] + # @param _id [String] + # @param start_closed_captions_request [StartClosedCaptionsRequest] + # @return [Models::StartClosedCaptionsResponse] + def start_closed_captions(_type, _id, start_closed_captions_request) + path = '/api/v2/video/call/{type}/{id}/start_closed_captions' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = start_closed_captions_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Starts frame by frame recordingSends events:- call.frame_recording_started + # + # @param _type [String] + # @param _id [String] + # @param start_frame_recording_request [StartFrameRecordingRequest] + # @return [Models::StartFrameRecordingResponse] + def start_frame_recording(_type, _id, start_frame_recording_request) + path = '/api/v2/video/call/{type}/{id}/start_frame_recording' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = start_frame_recording_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Starts transcription + # + # @param _type [String] + # @param _id [String] + # @param start_transcription_request [StartTranscriptionRequest] + # @return [Models::StartTranscriptionResponse] + def start_transcription(_type, _id, start_transcription_request) + path = '/api/v2/video/call/{type}/{id}/start_transcription' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = start_transcription_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Stops HLS broadcasting + # + # @param _type [String] + # @param _id [String] + # @return [Models::StopHLSBroadcastingResponse] + def stop_hls_broadcasting(_type, _id) + path = '/api/v2/video/call/{type}/{id}/stop_broadcasting' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + + # Make the API request + @client.make_request( + :post, + path + ) + end + + # Stops closed captionsSends events:- call.transcription_stopped + # + # @param _type [String] + # @param _id [String] + # @param stop_closed_captions_request [StopClosedCaptionsRequest] + # @return [Models::StopClosedCaptionsResponse] + def stop_closed_captions(_type, _id, stop_closed_captions_request) + path = '/api/v2/video/call/{type}/{id}/stop_closed_captions' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = stop_closed_captions_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Stops frame recordingSends events:- call.frame_recording_stopped + # + # @param _type [String] + # @param _id [String] + # @return [Models::StopFrameRecordingResponse] + def stop_frame_recording(_type, _id) + path = '/api/v2/video/call/{type}/{id}/stop_frame_recording' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + + # Make the API request + @client.make_request( + :post, + path + ) + end + + # Sends events:- call.updated + # + # @param _type [String] + # @param _id [String] + # @param stop_live_request [StopLiveRequest] + # @return [Models::StopLiveResponse] + def stop_live(_type, _id, stop_live_request) + path = '/api/v2/video/call/{type}/{id}/stop_live' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = stop_live_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Stops transcriptionSends events:- call.transcription_stopped + # + # @param _type [String] + # @param _id [String] + # @param stop_transcription_request [StopTranscriptionRequest] + # @return [Models::StopTranscriptionResponse] + def stop_transcription(_type, _id, stop_transcription_request) + path = '/api/v2/video/call/{type}/{id}/stop_transcription' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = stop_transcription_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Lists transcriptions + # + # @param _type [String] + # @param _id [String] + # @return [Models::ListTranscriptionsResponse] + def list_transcriptions(_type, _id) + path = '/api/v2/video/call/{type}/{id}/transcriptions' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + + # Make the API request + @client.make_request( + :get, + path + ) + end + + # Removes the block for a user on a call. The user will be able to join the call again.Sends events:- call.unblocked_user + # + # @param _type [String] + # @param _id [String] + # @param unblock_user_request [UnblockUserRequest] + # @return [Models::UnblockUserResponse] + def unblock_user(_type, _id, unblock_user_request) + path = '/api/v2/video/call/{type}/{id}/unblock' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = unblock_user_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Unpins a track for all users in the call. + # + # @param _type [String] + # @param _id [String] + # @param unpin_request [UnpinRequest] + # @return [Models::UnpinResponse] + def video_unpin(_type, _id, unpin_request) + path = '/api/v2/video/call/{type}/{id}/unpin' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = unpin_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Updates user permissionsSends events:- call.permissions_updated + # + # @param _type [String] + # @param _id [String] + # @param update_user_permissions_request [UpdateUserPermissionsRequest] + # @return [Models::UpdateUserPermissionsResponse] + def update_user_permissions(_type, _id, update_user_permissions_request) + path = '/api/v2/video/call/{type}/{id}/user_permissions' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + # Build request body + body = update_user_permissions_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Deletes recording + # + # @param _type [String] + # @param _id [String] + # @param session [String] + # @param filename [String] + # @return [Models::DeleteRecordingResponse] + def delete_recording(_type, _id, session, filename) + path = '/api/v2/video/call/{type}/{id}/{session}/recordings/{filename}' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + path = path.gsub('{session}', session.to_s) + path = path.gsub('{filename}', filename.to_s) + + # Make the API request + @client.make_request( + :delete, + path + ) + end + + # Deletes transcription + # + # @param _type [String] + # @param _id [String] + # @param session [String] + # @param filename [String] + # @return [Models::DeleteTranscriptionResponse] + def delete_transcription(_type, _id, session, filename) + path = '/api/v2/video/call/{type}/{id}/{session}/transcriptions/{filename}' + # Replace path parameters + path = path.gsub('{type}', _type.to_s) + path = path.gsub('{id}', _id.to_s) + path = path.gsub('{session}', session.to_s) + path = path.gsub('{filename}', filename.to_s) + + # Make the API request + @client.make_request( + :delete, + path + ) + end + + # + # + # @param call_type [String] + # @param call_id [String] + # @param session [String] + # @param start_time [DateTime] + # @param end_time [DateTime] + # @param exclude_publishers [Boolean] + # @param exclude_subscribers [Boolean] + # @param exclude_sfus [Boolean] + # @return [Models::QueryCallStatsMapResponse] + def get_call_stats_map(call_type, call_id, session, start_time = nil, end_time = nil, exclude_publishers = nil, exclude_subscribers = nil, exclude_sfus = nil) + path = '/api/v2/video/call_stats/{call_type}/{call_id}/{session}/map' + # Replace path parameters + path = path.gsub('{call_type}', call_type.to_s) + path = path.gsub('{call_id}', call_id.to_s) + path = path.gsub('{session}', session.to_s) + # Build query parameters + query_params = {} + query_params['start_time'] = start_time unless start_time.nil? + query_params['end_time'] = end_time unless end_time.nil? + query_params['exclude_publishers'] = exclude_publishers unless exclude_publishers.nil? + query_params['exclude_subscribers'] = exclude_subscribers unless exclude_subscribers.nil? + query_params['exclude_sfus'] = exclude_sfus unless exclude_sfus.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # + # + # @param call_type [String] + # @param call_id [String] + # @param session [String] + # @param user [String] + # @param user_session [String] + # @param since [String] + # @param _until [String] + # @param max_points [Integer] + # @return [Models::GetCallSessionParticipantStatsDetailsResponse] + def get_call_session_participant_stats_details(call_type, call_id, session, user, user_session, since = nil, _until = nil, max_points = nil) + path = '/api/v2/video/call_stats/{call_type}/{call_id}/{session}/participant/{user}/{user_session}/details' + # Replace path parameters + path = path.gsub('{call_type}', call_type.to_s) + path = path.gsub('{call_id}', call_id.to_s) + path = path.gsub('{session}', session.to_s) + path = path.gsub('{user}', user.to_s) + path = path.gsub('{user_session}', user_session.to_s) + # Build query parameters + query_params = {} + query_params['since'] = since unless since.nil? + query_params['until'] = _until unless _until.nil? + query_params['max_points'] = max_points unless max_points.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # + # + # @param call_type [String] + # @param call_id [String] + # @param session [String] + # @param limit [Integer] + # @param prev [String] + # @param _next [String] + # @param sort [Array] + # @param filter_conditions [Object] + # @return [Models::QueryCallSessionParticipantStatsResponse] + def query_call_session_participant_stats(call_type, call_id, session, limit = nil, prev = nil, _next = nil, sort = nil, filter_conditions = nil) + path = '/api/v2/video/call_stats/{call_type}/{call_id}/{session}/participants' + # Replace path parameters + path = path.gsub('{call_type}', call_type.to_s) + path = path.gsub('{call_id}', call_id.to_s) + path = path.gsub('{session}', session.to_s) + # Build query parameters + query_params = {} + query_params['limit'] = limit unless limit.nil? + query_params['prev'] = prev unless prev.nil? + query_params['next'] = _next unless _next.nil? + query_params['sort'] = sort unless sort.nil? + query_params['filter_conditions'] = filter_conditions unless filter_conditions.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # + # + # @param call_type [String] + # @param call_id [String] + # @param session [String] + # @param user [String] + # @param user_session [String] + # @param start_time [String] + # @param end_time [String] + # @param severity [Array] + # @return [Models::QueryCallSessionParticipantStatsTimelineResponse] + def get_call_session_participant_stats_timeline(call_type, call_id, session, user, user_session, start_time = nil, end_time = nil, severity = nil) + path = '/api/v2/video/call_stats/{call_type}/{call_id}/{session}/participants/{user}/{user_session}/timeline' + # Replace path parameters + path = path.gsub('{call_type}', call_type.to_s) + path = path.gsub('{call_id}', call_id.to_s) + path = path.gsub('{session}', session.to_s) + path = path.gsub('{user}', user.to_s) + path = path.gsub('{user_session}', user_session.to_s) + # Build query parameters + query_params = {} + query_params['start_time'] = start_time unless start_time.nil? + query_params['end_time'] = end_time unless end_time.nil? + query_params['severity'] = severity unless severity.nil? + + # Make the API request + @client.make_request( + :get, + path, + query_params: query_params + ) + end + + # Query calls with filter query + # + # @param query_calls_request [QueryCallsRequest] + # @return [Models::QueryCallsResponse] + def query_calls(query_calls_request) + path = '/api/v2/video/calls' + # Build request body + body = query_calls_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # + # + # @return [Models::ListCallTypeResponse] + def list_call_types() + path = '/api/v2/video/calltypes' + + # Make the API request + @client.make_request( + :get, + path + ) + end + + # + # + # @param create_call_type_request [CreateCallTypeRequest] + # @return [Models::CreateCallTypeResponse] + def create_call_type(create_call_type_request) + path = '/api/v2/video/calltypes' + # Build request body + body = create_call_type_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # + # + # @param name [String] + # @return [Models::Response] + def delete_call_type(name) + path = '/api/v2/video/calltypes/{name}' + # Replace path parameters + path = path.gsub('{name}', name.to_s) + + # Make the API request + @client.make_request( + :delete, + path + ) + end + + # + # + # @param name [String] + # @return [Models::GetCallTypeResponse] + def get_call_type(name) + path = '/api/v2/video/calltypes/{name}' + # Replace path parameters + path = path.gsub('{name}', name.to_s) + + # Make the API request + @client.make_request( + :get, + path + ) + end + + # + # + # @param name [String] + # @param update_call_type_request [UpdateCallTypeRequest] + # @return [Models::UpdateCallTypeResponse] + def update_call_type(name, update_call_type_request) + path = '/api/v2/video/calltypes/{name}' + # Replace path parameters + path = path.gsub('{name}', name.to_s) + # Build request body + body = update_call_type_request + + # Make the API request + @client.make_request( + :put, + path, + body: body + ) + end + + # Returns the list of all edges available for video calls. + # + # @return [Models::GetEdgesResponse] + def get_edges() + path = '/api/v2/video/edges' + + # Make the API request + @client.make_request( + :get, + path + ) + end + + # List all SIP Inbound Routing Rules for the application + # + # @return [Models::ListSIPInboundRoutingRuleResponse] + def list_sip_inbound_routing_rule() + path = '/api/v2/video/sip/inbound_routing_rules' + + # Make the API request + @client.make_request( + :get, + path + ) + end + + # Create a new SIP Inbound Routing Rule with either direct routing or PIN routing configuration + # + # @param sip_inbound_routing_rule_request [SIPInboundRoutingRuleRequest] + # @return [Models::SIPInboundRoutingRuleResponse] + def create_sip_inbound_routing_rule(sip_inbound_routing_rule_request) + path = '/api/v2/video/sip/inbound_routing_rules' + # Build request body + body = sip_inbound_routing_rule_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Delete a SIP Inbound Routing Rule for the application + # + # @param _id [String] + # @return [Models::DeleteSIPInboundRoutingRuleResponse] + def delete_sip_inbound_routing_rule(_id) + path = '/api/v2/video/sip/inbound_routing_rules/{id}' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + + # Make the API request + @client.make_request( + :delete, + path + ) + end + + # Update an existing SIP Inbound Routing Rule with new configuration + # + # @param _id [String] + # @param update_sip_inbound_routing_rule_request [UpdateSIPInboundRoutingRuleRequest] + # @return [Models::UpdateSIPInboundRoutingRuleResponse] + def update_sip_inbound_routing_rule(_id, update_sip_inbound_routing_rule_request) + path = '/api/v2/video/sip/inbound_routing_rules/{id}' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = update_sip_inbound_routing_rule_request + + # Make the API request + @client.make_request( + :put, + path, + body: body + ) + end + + # List all SIP trunks for the application + # + # @return [Models::ListSIPTrunksResponse] + def list_sip_trunks() + path = '/api/v2/video/sip/inbound_trunks' + + # Make the API request + @client.make_request( + :get, + path + ) + end + + # Create a new SIP trunk for the application + # + # @param create_sip_trunk_request [CreateSIPTrunkRequest] + # @return [Models::CreateSIPTrunkResponse] + def create_sip_trunk(create_sip_trunk_request) + path = '/api/v2/video/sip/inbound_trunks' + # Build request body + body = create_sip_trunk_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # Delete a SIP trunk for the application + # + # @param _id [String] + # @return [Models::DeleteSIPTrunkResponse] + def delete_sip_trunk(_id) + path = '/api/v2/video/sip/inbound_trunks/{id}' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + + # Make the API request + @client.make_request( + :delete, + path + ) + end + + # Update a SIP trunk for the application + # + # @param _id [String] + # @param update_sip_trunk_request [UpdateSIPTrunkRequest] + # @return [Models::UpdateSIPTrunkResponse] + def update_sip_trunk(_id, update_sip_trunk_request) + path = '/api/v2/video/sip/inbound_trunks/{id}' + # Replace path parameters + path = path.gsub('{id}', _id.to_s) + # Build request body + body = update_sip_trunk_request + + # Make the API request + @client.make_request( + :put, + path, + body: body + ) + end + + # Resolve SIP inbound routing based on trunk number, caller number, and challenge authentication + # + # @param resolve_sip_inbound_request [ResolveSipInboundRequest] + # @return [Models::ResolveSipInboundResponse] + def resolve_sip_inbound(resolve_sip_inbound_request) + path = '/api/v2/video/sip/resolve' + # Build request body + body = resolve_sip_inbound_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + # + # + # @param query_aggregate_call_stats_request [QueryAggregateCallStatsRequest] + # @return [Models::QueryAggregateCallStatsResponse] + def query_aggregate_call_stats(query_aggregate_call_stats_request) + path = '/api/v2/video/stats' + # Build request body + body = query_aggregate_call_stats_request + + # Make the API request + @client.make_request( + :post, + path, + body: body + ) + end + + end + end +end \ No newline at end of file diff --git a/lib/getstream_ruby/generated/webhook.rb b/lib/getstream_ruby/generated/webhook.rb index 017a64e..266f1f4 100644 --- a/lib/getstream_ruby/generated/webhook.rb +++ b/lib/getstream_ruby/generated/webhook.rb @@ -102,6 +102,7 @@ require_relative 'models/feed_deleted_event' require_relative 'models/feed_group_changed_event' require_relative 'models/feed_group_deleted_event' +require_relative 'models/feed_group_restored_event' require_relative 'models/feed_member_added_event' require_relative 'models/feed_member_removed_event' require_relative 'models/feed_member_updated_event' @@ -152,6 +153,11 @@ require_relative 'models/user_deactivated_event' require_relative 'models/user_deleted_event' require_relative 'models/user_flagged_event' +require_relative 'models/user_group_created_event' +require_relative 'models/user_group_deleted_event' +require_relative 'models/user_group_member_added_event' +require_relative 'models/user_group_member_removed_event' +require_relative 'models/user_group_updated_event' require_relative 'models/user_messages_deleted_event' require_relative 'models/user_muted_event' require_relative 'models/user_reactivated_event' @@ -272,6 +278,7 @@ module Webhook EVENT_TYPE_FEEDS_FEED_UPDATED = 'feeds.feed.updated' EVENT_TYPE_FEEDS_FEED_GROUP_CHANGED = 'feeds.feed_group.changed' EVENT_TYPE_FEEDS_FEED_GROUP_DELETED = 'feeds.feed_group.deleted' + EVENT_TYPE_FEEDS_FEED_GROUP_RESTORED = 'feeds.feed_group.restored' EVENT_TYPE_FEEDS_FEED_MEMBER_ADDED = 'feeds.feed_member.added' EVENT_TYPE_FEEDS_FEED_MEMBER_REMOVED = 'feeds.feed_member.removed' EVENT_TYPE_FEEDS_FEED_MEMBER_UPDATED = 'feeds.feed_member.updated' @@ -323,6 +330,11 @@ module Webhook EVENT_TYPE_USER_UNMUTED = 'user.unmuted' EVENT_TYPE_USER_UNREAD_MESSAGE_REMINDER = 'user.unread_message_reminder' EVENT_TYPE_USER_UPDATED = 'user.updated' + EVENT_TYPE_USER_GROUP_CREATED = 'user_group.created' + EVENT_TYPE_USER_GROUP_DELETED = 'user_group.deleted' + EVENT_TYPE_USER_GROUP_MEMBER_ADDED = 'user_group.member_added' + EVENT_TYPE_USER_GROUP_MEMBER_REMOVED = 'user_group.member_removed' + EVENT_TYPE_USER_GROUP_UPDATED = 'user_group.updated' # Extract the event type from a raw webhook payload. # @@ -586,6 +598,8 @@ def self.parse_webhook_event(raw_event) StreamChat::FeedGroupChangedEvent when 'feeds.feed_group.deleted' StreamChat::FeedGroupDeletedEvent + when 'feeds.feed_group.restored' + StreamChat::FeedGroupRestoredEvent when 'feeds.feed_member.added' StreamChat::FeedMemberAddedEvent when 'feeds.feed_member.removed' @@ -688,6 +702,16 @@ def self.parse_webhook_event(raw_event) StreamChat::UserUnreadReminderEvent when 'user.updated' StreamChat::UserUpdatedEvent + when 'user_group.created' + StreamChat::UserGroupCreatedEvent + when 'user_group.deleted' + StreamChat::UserGroupDeletedEvent + when 'user_group.member_added' + StreamChat::UserGroupMemberAddedEvent + when 'user_group.member_removed' + StreamChat::UserGroupMemberRemovedEvent + when 'user_group.updated' + StreamChat::UserGroupUpdatedEvent else nil end diff --git a/lib/getstream_ruby/version.rb b/lib/getstream_ruby/version.rb index 014e963..3173497 100644 --- a/lib/getstream_ruby/version.rb +++ b/lib/getstream_ruby/version.rb @@ -2,6 +2,6 @@ module GetStreamRuby - VERSION = '2.1.0' + VERSION = '3.0.0.beta.1' end diff --git a/spec/integration/base_integration_test.rb b/spec/integration/base_integration_test.rb index cca3e90..90efac3 100644 --- a/spec/integration/base_integration_test.rb +++ b/spec/integration/base_integration_test.rb @@ -4,6 +4,7 @@ require 'securerandom' require 'dotenv' require_relative '../../lib/getstream_ruby' +require_relative 'suite_cleanup' # Base class for integration tests with common setup and cleanup class BaseIntegrationTest diff --git a/spec/integration/chat_channel_integration_spec.rb b/spec/integration/chat_channel_integration_spec.rb new file mode 100644 index 0000000..7bd3158 --- /dev/null +++ b/spec/integration/chat_channel_integration_spec.rb @@ -0,0 +1,974 @@ +# frozen_string_literal: true + +require 'rspec' +require 'securerandom' +require 'json' +require 'tempfile' +require_relative 'chat_test_helpers' + +RSpec.describe 'Chat Channel Integration', type: :integration do + + include ChatTestHelpers + + before(:all) do + + init_chat_client + # Create shared test users for all subtests + @shared_user_ids, _resp = create_test_users(4) + @creator_id = @shared_user_ids[0] + @member_id_1 = @shared_user_ids[1] + @member_id_2 = @shared_user_ids[2] + @member_id_3 = @shared_user_ids[3] + + end + + after(:all) do + + cleanup_chat_resources + + end + + # --------------------------------------------------------------------------- + # Channel API wrappers (beyond what ChatTestHelpers provides) + # --------------------------------------------------------------------------- + + def update_channel(type, id, body) + @client.make_request(:post, "/api/v2/chat/channels/#{type}/#{id}", body: body) + end + + def update_channel_partial(type, id, body) + @client.make_request(:patch, "/api/v2/chat/channels/#{type}/#{id}", body: body) + end + + def delete_channels_batch(body) + @client.make_request(:post, '/api/v2/chat/channels/delete', body: body) + end + + def hide_channel(type, id, body) + @client.make_request(:post, "/api/v2/chat/channels/#{type}/#{id}/hide", body: body) + end + + def show_channel(type, id, body) + @client.make_request(:post, "/api/v2/chat/channels/#{type}/#{id}/show", body: body) + end + + def truncate_channel(type, id, body = {}) + @client.make_request(:post, "/api/v2/chat/channels/#{type}/#{id}/truncate", body: body) + end + + def mark_read(type, id, body) + @client.make_request(:post, "/api/v2/chat/channels/#{type}/#{id}/read", body: body) + end + + def mark_unread(type, id, body) + @client.make_request(:post, "/api/v2/chat/channels/#{type}/#{id}/unread", body: body) + end + + def send_event(type, id, body) + @client.make_request(:post, "/api/v2/chat/channels/#{type}/#{id}/event", body: body) + end + + def mute_channel(body) + @client.make_request(:post, '/api/v2/chat/moderation/mute/channel', body: body) + end + + def unmute_channel(body) + @client.make_request(:post, '/api/v2/chat/moderation/unmute/channel', body: body) + end + + def update_member_partial(type, id, body) + user_id = body.delete(:user_id) || body.delete('user_id') + @client.make_request( + :patch, + "/api/v2/chat/channels/#{type}/#{id}/member", + query_params: { 'user_id' => user_id }, + body: body, + ) + end + + def query_members_api(payload) + @client.make_request( + :get, + '/api/v2/chat/members', + query_params: { 'payload' => JSON.generate(payload) }, + ) + end + + def upload_channel_file(type, id, file_upload_request) + @client.make_request(:post, "/api/v2/chat/channels/#{type}/#{id}/file", body: file_upload_request) + end + + def delete_channel_file(type, id, url) + @client.make_request(:delete, "/api/v2/chat/channels/#{type}/#{id}/file", query_params: { 'url' => url }) + end + + def upload_channel_image(type, id, image_upload_request) + @client.make_request(:post, "/api/v2/chat/channels/#{type}/#{id}/image", body: image_upload_request) + end + + def delete_channel_image(type, id, url) + @client.make_request(:delete, "/api/v2/chat/channels/#{type}/#{id}/image", query_params: { 'url' => url }) + end + + # --------------------------------------------------------------------------- + # Tests + # --------------------------------------------------------------------------- + + describe 'CreateChannelWithID' do + + it 'creates channel and verifies via QueryChannels' do + + _type, channel_id, _resp = create_test_channel(@creator_id) + + resp = query_channels( + filter_conditions: { 'id' => channel_id }, + ) + expect(resp.channels).not_to be_nil + expect(resp.channels).not_to be_empty + ch = resp.channels.first.to_h + expect(ch.dig('channel', 'id')).to eq(channel_id) + expect(ch.dig('channel', 'type')).to eq('messaging') + + end + + end + + describe 'CreateChannelWithMembers' do + + it 'creates channel with 3 members and verifies count' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, + [@creator_id, @member_id_1, @member_id_2], + ) + + resp = get_or_create_channel('messaging', channel_id) + expect(resp.members).not_to be_nil + expect(resp.members.length).to be >= 3 + + end + + end + + describe 'CreateDistinctChannel' do + + it 'creates distinct channel and verifies same CID on second call' do + + members = [ + { user_id: @creator_id }, + { user_id: @member_id_1 }, + ] + + resp = @client.make_request( + :post, + '/api/v2/chat/channels/messaging/query', + body: { + data: { + created_by_id: @creator_id, + members: members, + }, + }, + ) + expect(resp.channel).not_to be_nil + cid_1 = resp.channel.to_h['cid'] + + # Call again with same members โ€” should return same channel + resp_2 = @client.make_request( + :post, + '/api/v2/chat/channels/messaging/query', + body: { + data: { + created_by_id: @creator_id, + members: members, + }, + }, + ) + cid_2 = resp_2.channel.to_h['cid'] + expect(cid_1).to eq(cid_2) + + # Cleanup: hard delete + ch_id = resp.channel.to_h['id'] + @created_channel_cids << "messaging:#{ch_id}" unless @created_channel_cids.include?("messaging:#{ch_id}") + + end + + end + + describe 'QueryChannels' do + + it 'creates channel and queries by type+id' do + + _type, channel_id, _resp = create_test_channel(@creator_id) + + resp = query_channels( + filter_conditions: { 'type' => 'messaging', 'id' => channel_id }, + ) + expect(resp.channels).not_to be_nil + expect(resp.channels).not_to be_empty + expect(resp.channels.first.to_h.dig('channel', 'id')).to eq(channel_id) + + end + + end + + describe 'UpdateChannel' do + + it 'updates with custom data and message, verifies custom field' do + + _type, channel_id, _resp = create_test_channel(@creator_id) + + resp = update_channel('messaging', channel_id, + data: { custom: { color: 'blue' } }, + message: { text: 'Channel updated!', user_id: @creator_id }) + expect(resp.channel).not_to be_nil + ch = resp.channel.to_h + custom = ch['custom'] || {} + expect(custom['color']).to eq('blue') + + end + + end + + describe 'PartialUpdateChannel' do + + it 'sets fields then unsets one' do + + _type, channel_id, _resp = create_test_channel(@creator_id) + + # Set fields + resp = update_channel_partial('messaging', channel_id, + set: { 'color' => 'red', 'description' => 'A test channel' }) + expect(resp.channel).not_to be_nil + ch = resp.channel.to_h + custom = ch['custom'] || {} + expect(custom['color']).to eq('red') + + # Unset fields + resp_2 = update_channel_partial('messaging', channel_id, unset: ['color']) + expect(resp_2.channel).not_to be_nil + ch_2 = resp_2.channel.to_h + custom_2 = ch_2['custom'] || {} + expect(custom_2).not_to have_key('color') + + end + + end + + describe 'DeleteChannel' do + + it 'soft deletes channel and verifies response' do + + channel_id = "test-del-#{SecureRandom.hex(6)}" + get_or_create_channel('messaging', channel_id, + data: { created_by_id: @creator_id }) + @created_channel_cids << "messaging:#{channel_id}" + + resp = delete_channel('messaging', channel_id) + expect(resp.channel).not_to be_nil + + end + + end + + describe 'HardDeleteChannels' do + + it 'hard deletes 2 channels via batch and polls task' do + + _type_1, channel_id_1, _resp_1 = create_test_channel(@creator_id) + _type_2, channel_id_2, _resp_2 = create_test_channel(@creator_id) + + cid_1 = "messaging:#{channel_id_1}" + cid_2 = "messaging:#{channel_id_2}" + + # Remove from tracked list since batch delete will handle it + @created_channel_cids.delete(cid_1) + @created_channel_cids.delete(cid_2) + + resp = delete_channels_batch(cids: [cid_1, cid_2], hard_delete: true) + expect(resp.task_id).not_to be_nil + + result = wait_for_task(resp.task_id) + expect(result.status).to eq('completed') + + end + + end + + describe 'AddRemoveMembers' do + + it 'adds 2 members, verifies count; removes 1, verifies removed' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_id_1] + ) + + # Add members + update_channel('messaging', channel_id, + add_members: [{ user_id: @member_id_2 }, { user_id: @member_id_3 }]) + + # Verify members added + resp = get_or_create_channel('messaging', channel_id) + expect(resp.members.length).to be >= 4 + + # Remove a member + update_channel('messaging', channel_id, remove_members: [@member_id_3]) + + # Verify member removed + resp_2 = get_or_create_channel('messaging', channel_id) + member_ids = resp_2.members.map { |m| m.to_h['user_id'] || m.to_h.dig('user', 'id') } + expect(member_ids).not_to include(@member_id_3) + + end + + end + + describe 'QueryMembers' do + + it 'creates channel with 3 members and queries members' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_id_1, @member_id_2] + ) + + resp = query_members_api( + type: 'messaging', + id: channel_id, + filter_conditions: {}, + ) + expect(resp.members).not_to be_nil + expect(resp.members.length).to be >= 3 + + end + + end + + describe 'InviteAcceptReject' do + + it 'creates channel with invites, accepts one, rejects one' do + + channel_id = "test-inv-#{SecureRandom.hex(6)}" + + get_or_create_channel('messaging', channel_id, + data: { + created_by_id: @creator_id, + members: [{ user_id: @creator_id }], + invites: [{ user_id: @member_id_1 }, { user_id: @member_id_2 }], + }) + @created_channel_cids << "messaging:#{channel_id}" + + # Accept invite + update_channel('messaging', channel_id, + accept_invite: true, + user_id: @member_id_1) + + # Reject invite + update_channel('messaging', channel_id, + reject_invite: true, + user_id: @member_id_2) + + end + + end + + describe 'HideShowChannel' do + + it 'hides channel for user, then shows' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_id_1] + ) + + # Hide + hide_channel('messaging', channel_id, user_id: @member_id_1) + + # Show + show_channel('messaging', channel_id, user_id: @member_id_1) + + end + + end + + describe 'TruncateChannel' do + + it 'sends 3 messages, truncates, verifies empty' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_id_1] + ) + + send_test_message('messaging', channel_id, @creator_id, 'Message 1') + send_test_message('messaging', channel_id, @creator_id, 'Message 2') + send_test_message('messaging', channel_id, @creator_id, 'Message 3') + + truncate_channel('messaging', channel_id) + + resp = get_or_create_channel('messaging', channel_id) + messages = resp.messages || [] + expect(messages).to be_empty + + end + + end + + describe 'FreezeUnfreezeChannel' do + + it 'sets frozen=true, verifies; sets frozen=false, verifies' do + + _type, channel_id, _resp = create_test_channel(@creator_id) + + # Freeze + resp = update_channel_partial('messaging', channel_id, set: { 'frozen' => true }) + expect(resp.channel.to_h['frozen']).to eq(true) + + # Unfreeze + resp_2 = update_channel_partial('messaging', channel_id, set: { 'frozen' => false }) + expect(resp_2.channel.to_h['frozen']).to eq(false) + + end + + end + + describe 'MarkReadUnread' do + + it 'sends message, marks read, marks unread' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_id_1] + ) + + msg_id = send_test_message('messaging', channel_id, @creator_id, 'Message to mark read') + + # Mark read + mark_read('messaging', channel_id, user_id: @member_id_1) + + # Mark unread from this message + mark_unread('messaging', channel_id, user_id: @member_id_1, message_id: msg_id) + + end + + end + + describe 'MuteUnmuteChannel' do + + it 'mutes channel, verifies via query with muted=true; unmutes' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_id_1] + ) + cid = "messaging:#{channel_id}" + + # Mute + mute_resp = mute_channel(channel_cids: [cid], user_id: @member_id_1) + expect(mute_resp).not_to be_nil + expect(mute_resp.channel_mute).not_to be_nil + expect(mute_resp.channel_mute.to_h.dig('channel', 'cid')).to eq(cid) + + # Verify via QueryChannels with muted=true + q_resp = query_channels( + filter_conditions: { 'muted' => true, 'cid' => cid }, + user_id: @member_id_1, + ) + expect(q_resp.channels.length).to eq(1) + expect(q_resp.channels.first.to_h.dig('channel', 'cid')).to eq(cid) + + # Unmute + unmute_channel(channel_cids: [cid], user_id: @member_id_1) + + # Verify unmuted + q_resp_2 = query_channels( + filter_conditions: { 'muted' => false, 'cid' => cid }, + user_id: @member_id_1, + ) + expect(q_resp_2.channels.length).to eq(1) + + end + + end + + describe 'MemberPartialUpdate' do + + it 'sets custom fields on member; unsets one' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_id_1] + ) + + # Set custom fields + resp = update_member_partial('messaging', channel_id, + user_id: @member_id_1, + set: { 'role_label' => 'moderator', 'score' => 42 }) + expect(resp.channel_member).not_to be_nil + member_h = resp.channel_member.to_h + custom = member_h['custom'] || {} + expect(custom['role_label']).to eq('moderator') + + # Unset a custom field + resp_2 = update_member_partial('messaging', channel_id, + user_id: @member_id_1, + unset: ['score']) + expect(resp_2.channel_member).not_to be_nil + member_h_2 = resp_2.channel_member.to_h + custom_2 = member_h_2['custom'] || {} + expect(custom_2).not_to have_key('score') + + end + + end + + describe 'AssignRoles' do + + it 'assigns channel_moderator role, verifies via QueryMembers' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_id_1] + ) + + # Assign role + update_channel('messaging', channel_id, + assign_roles: [{ user_id: @member_id_1, channel_role: 'channel_moderator' }]) + + # Verify via QueryMembers + q_resp = query_members_api( + type: 'messaging', + id: channel_id, + filter_conditions: { 'id' => @member_id_1 }, + ) + expect(q_resp.members).not_to be_empty + expect(q_resp.members.first.to_h['channel_role']).to eq('channel_moderator') + + end + + end + + describe 'AddDemoteModerators' do + + it 'adds moderator, verifies; demotes, verifies back to member' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_id_1] + ) + + # Add moderator + update_channel('messaging', channel_id, add_moderators: [@member_id_1]) + + # Verify role + q_resp = query_members_api( + type: 'messaging', + id: channel_id, + filter_conditions: { 'id' => @member_id_1 }, + ) + expect(q_resp.members).not_to be_empty + expect(q_resp.members.first.to_h['channel_role']).to eq('channel_moderator') + + # Demote + update_channel('messaging', channel_id, demote_moderators: [@member_id_1]) + + # Verify back to member + q_resp_2 = query_members_api( + type: 'messaging', + id: channel_id, + filter_conditions: { 'id' => @member_id_1 }, + ) + expect(q_resp_2.members).not_to be_empty + expect(q_resp_2.members.first.to_h['channel_role']).to eq('channel_member') + + end + + end + + describe 'MarkUnreadWithThread' do + + it 'creates thread and marks unread from thread' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_id_1] + ) + + # Send parent message + parent_id = send_test_message('messaging', channel_id, @creator_id, 'Parent for mark unread thread') + + # Send reply to create a thread + send_message('messaging', channel_id, + message: { text: 'Reply in thread', user_id: @creator_id, parent_id: parent_id }) + + # Mark unread from thread + mark_unread('messaging', channel_id, + user_id: @member_id_1, + thread_id: parent_id) + + end + + end + + describe 'TruncateWithOptions' do + + it 'truncates with message, skip_push, hard_delete' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_id_1] + ) + + send_test_message('messaging', channel_id, @creator_id, 'Truncate msg 1') + send_test_message('messaging', channel_id, @creator_id, 'Truncate msg 2') + + truncate_channel('messaging', channel_id, + message: { text: 'Channel was truncated', user_id: @creator_id }, + skip_push: true, + hard_delete: true) + + end + + end + + describe 'PinUnpinChannel' do + + it 'pins channel, verifies via query; unpins, verifies' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_id_1] + ) + cid = "messaging:#{channel_id}" + + # Pin + update_member_partial('messaging', channel_id, + user_id: @member_id_1, + set: { 'pinned' => true }) + + # Verify pinned + q_resp = query_channels( + filter_conditions: { 'pinned' => true, 'cid' => cid }, + user_id: @member_id_1, + ) + expect(q_resp.channels.length).to eq(1) + expect(q_resp.channels.first.to_h.dig('channel', 'cid')).to eq(cid) + + # Unpin + update_member_partial('messaging', channel_id, + user_id: @member_id_1, + set: { 'pinned' => false }) + + # Verify unpinned + q_resp_2 = query_channels( + filter_conditions: { 'pinned' => false, 'cid' => cid }, + user_id: @member_id_1, + ) + expect(q_resp_2.channels.length).to eq(1) + + end + + end + + describe 'ArchiveUnarchiveChannel' do + + it 'archives channel, verifies via query; unarchives, verifies' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_id_1] + ) + cid = "messaging:#{channel_id}" + + # Archive + update_member_partial('messaging', channel_id, + user_id: @member_id_1, + set: { 'archived' => true }) + + # Verify archived + q_resp = query_channels( + filter_conditions: { 'archived' => true, 'cid' => cid }, + user_id: @member_id_1, + ) + expect(q_resp.channels.length).to eq(1) + expect(q_resp.channels.first.to_h.dig('channel', 'cid')).to eq(cid) + + # Unarchive + update_member_partial('messaging', channel_id, + user_id: @member_id_1, + set: { 'archived' => false }) + + # Verify unarchived + q_resp_2 = query_channels( + filter_conditions: { 'archived' => false, 'cid' => cid }, + user_id: @member_id_1, + ) + expect(q_resp_2.channels.length).to eq(1) + + end + + end + + describe 'AddMembersWithRoles' do + + it 'adds members with specific channel roles, verifies' do + + _type, channel_id, _resp = create_test_channel(@creator_id) + + new_user_ids, _resp = create_test_users(2) + mod_user_id = new_user_ids[0] + member_user_id = new_user_ids[1] + + # Add members with specific roles + update_channel('messaging', channel_id, + add_members: [ + { user_id: mod_user_id, channel_role: 'channel_moderator' }, + { user_id: member_user_id, channel_role: 'channel_member' }, + ]) + + # Query to verify roles + q_resp = query_members_api( + type: 'messaging', + id: channel_id, + filter_conditions: { 'id' => { '$in' => new_user_ids } }, + ) + + role_map = {} + q_resp.members.each do |m| + + mh = m.to_h + uid = mh['user_id'] || mh.dig('user', 'id') + role_map[uid] = mh['channel_role'] + + end + + expect(role_map[mod_user_id]).to eq('channel_moderator') + expect(role_map[member_user_id]).to eq('channel_member') + + end + + end + + describe 'MessageCount' do + + it 'sends message, queries channel, verifies message_count >= 1' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_id_1] + ) + + send_test_message('messaging', channel_id, @creator_id, 'hello world') + + q_resp = query_channels( + filter_conditions: { 'cid' => "messaging:#{channel_id}" }, + user_id: @creator_id, + ) + expect(q_resp.channels.length).to eq(1) + + channel_h = q_resp.channels.first.to_h['channel'] || {} + msg_count = channel_h['message_count'] + # message_count may be nil if disabled on channel type + expect(msg_count).to be_nil.or be >= 1 + + end + + end + + describe 'SendChannelEvent' do + + it 'sends typing.start event' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_id_1] + ) + + send_event('messaging', channel_id, + event: { type: 'typing.start', user_id: @creator_id }) + + end + + end + + describe 'FilterTags' do + + it 'adds filter tags, removes filter tag' do + + _type, channel_id, _resp = create_test_channel(@creator_id) + + # Add filter tags + update_channel('messaging', channel_id, + add_filter_tags: %w[sports news]) + + # Verify tags were added + resp = get_or_create_channel('messaging', channel_id) + expect(resp.channel).not_to be_nil + + # Remove a filter tag + update_channel('messaging', channel_id, + remove_filter_tags: ['sports']) + + end + + end + + describe 'MessageCountDisabled' do + + it 'disables count_messages via config_overrides, verifies message_count nil' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_id_1] + ) + + # Disable count_messages + update_channel_partial('messaging', channel_id, + set: { + 'config_overrides' => { 'count_messages' => false }, + }) + + send_test_message('messaging', channel_id, @creator_id, 'hello world disabled count') + + q_resp = query_channels( + filter_conditions: { 'cid' => "messaging:#{channel_id}" }, + user_id: @creator_id, + ) + expect(q_resp.channels.length).to eq(1) + + channel_h = q_resp.channels.first.to_h['channel'] || {} + expect(channel_h['message_count']).to be_nil + + end + + end + + describe 'MarkUnreadWithTimestamp' do + + it 'sends message, gets timestamp, marks unread from timestamp' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_id_1] + ) + + # Send message to get a valid timestamp + resp = send_message('messaging', channel_id, + message: { text: 'test message for timestamp unread', user_id: @creator_id }) + created_at = resp.message.to_h['created_at'] + expect(created_at).not_to be_nil + + # API may return created_at as nanosecond epoch integer; convert to RFC 3339 string + ts = if created_at.is_a?(Numeric) + Time.at(0, created_at, :nanosecond).utc.strftime('%Y-%m-%dT%H:%M:%S.%9NZ') + else + created_at.to_s + end + + # Mark unread from timestamp + mark_unread('messaging', channel_id, + user_id: @member_id_1, + message_timestamp: ts) + + end + + end + + describe 'HideForCreator' do + + it 'creates channel with hide_for_creator=true, verifies hidden' do + + channel_id = "test-hide-#{SecureRandom.hex(6)}" + + get_or_create_channel('messaging', channel_id, + hide_for_creator: true, + data: { + created_by_id: @creator_id, + members: [ + { user_id: @creator_id }, + { user_id: @member_id_1 }, + ], + }) + @created_channel_cids << "messaging:#{channel_id}" + + # Channel should be hidden for creator + q_resp = query_channels( + filter_conditions: { 'cid' => "messaging:#{channel_id}" }, + user_id: @creator_id, + ) + expect(q_resp.channels).to be_empty + + end + + end + + describe 'UploadAndDeleteFile' do + + it 'uploads a text file, verifies URL, deletes file' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id] + ) + + # Save original file upload config and clear restrictions + app_resp = @client.common.get_app + original_config = app_resp.app.file_upload_config + @client.common.update_app( + GetStream::Generated::Models::UpdateAppRequest.new( + file_upload_config: GetStream::Generated::Models::FileUploadConfig.new( + allowed_file_extensions: [], + blocked_file_extensions: [], + allowed_mime_types: [], + blocked_mime_types: [], + ), + ), + ) + sleep 2 + + # Create a temp file + tmpfile = Tempfile.new(['chat-test-', '.txt']) + tmpfile.write('hello world test file content') + tmpfile.close + + begin + upload_resp = upload_channel_file( + 'messaging', channel_id, + GetStream::Generated::Models::FileUploadRequest.new( + file: tmpfile.path, + user: GetStream::Generated::Models::OnlyUserID.new(id: @creator_id), + ) + ) + expect(upload_resp.file).not_to be_nil + file_url = upload_resp.file + expect(file_url).to include('http') + + # Delete file + delete_channel_file('messaging', channel_id, file_url) + ensure + tmpfile.unlink + # Restore original file upload config + @client.common.update_app( + GetStream::Generated::Models::UpdateAppRequest.new( + file_upload_config: original_config, + ), + ) + end + + end + + end + + describe 'UploadAndDeleteImage' do + + it 'uploads an image file, verifies URL, deletes image' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id] + ) + + # Use existing test image + image_path = File.join(__dir__, 'upload-test.png') + skip('upload-test.png not found') unless File.exist?(image_path) + + upload_resp = upload_channel_image( + 'messaging', channel_id, + GetStream::Generated::Models::ImageUploadRequest.new( + file: image_path, + user: GetStream::Generated::Models::OnlyUserID.new(id: @creator_id), + ) + ) + expect(upload_resp.file).not_to be_nil + image_url = upload_resp.file + expect(image_url).to include('http') + + # Delete image + delete_channel_image('messaging', channel_id, image_url) + + end + + end + +end diff --git a/spec/integration/chat_client_integration_spec.rb b/spec/integration/chat_client_integration_spec.rb new file mode 100644 index 0000000..e03a654 --- /dev/null +++ b/spec/integration/chat_client_integration_spec.rb @@ -0,0 +1,350 @@ +# frozen_string_literal: true + +require 'rspec' +require 'securerandom' +require 'json' +require_relative 'chat_test_helpers' + +RSpec.describe 'Chat Client Integration', type: :integration do + + include ChatTestHelpers + + before(:all) do + + init_chat_client + @shared_user_ids, _resp = create_test_users(3) + @creator_id = @shared_user_ids[0] + @member_a = @shared_user_ids[1] + @member_b = @shared_user_ids[2] + + end + + after(:all) do + + cleanup_chat_resources + + end + + # --------------------------------------------------------------------------- + # QueryChannels via generated client + # --------------------------------------------------------------------------- + + describe 'QueryChannels' do + + it 'queries channels using the generated chat client' do + + _type, channel_id, _resp = create_test_channel(@creator_id) + + resp = @client.chat.query_channels( + GetStream::Generated::Models::QueryChannelsRequest.new( + filter_conditions: { 'id' => channel_id }, + ), + ) + expect(resp.channels).not_to be_nil + expect(resp.channels).not_to be_empty + ch = resp.channels.first.to_h + expect(ch.dig('channel', 'id')).to eq(channel_id) + + end + + end + + # --------------------------------------------------------------------------- + # GetOrCreateChannel via generated client + # --------------------------------------------------------------------------- + + describe 'GetOrCreateChannel' do + + it 'creates and retrieves a channel using the generated chat client' do + + channel_id = "test-ch-#{SecureRandom.hex(6)}" + @created_channel_cids << "messaging:#{channel_id}" + + resp = @client.chat.get_or_create_channel( + 'messaging', channel_id, + GetStream::Generated::Models::ChannelGetOrCreateRequest.new( + data: { created_by_id: @creator_id }, + ) + ) + expect(resp.channel).not_to be_nil + expect(resp.channel.to_h['id']).to eq(channel_id) + + end + + end + + # --------------------------------------------------------------------------- + # UpdateChannel via generated client + # --------------------------------------------------------------------------- + + describe 'UpdateChannel' do + + it 'updates channel with members and custom data' do + + _type, channel_id, _resp = create_test_channel(@creator_id) + + resp = @client.chat.update_channel( + 'messaging', channel_id, + GetStream::Generated::Models::UpdateChannelRequest.new( + add_members: [{ user_id: @member_a }, { user_id: @member_b }], + data: { custom: { color: 'green' } }, + ) + ) + expect(resp.channel).not_to be_nil + expect(resp.members.length).to be >= 2 + + end + + end + + # --------------------------------------------------------------------------- + # UpdateChannelPartial via generated client + # --------------------------------------------------------------------------- + + describe 'UpdateChannelPartial' do + + it 'sets and unsets channel fields' do + + _type, channel_id, _resp = create_test_channel(@creator_id) + + resp = @client.chat.update_channel_partial( + 'messaging', channel_id, + GetStream::Generated::Models::UpdateChannelPartialRequest.new( + set: { 'color' => 'blue', 'topic' => 'testing' }, + ) + ) + ch = resp.channel.to_h + custom = ch['custom'] || {} + expect(custom['color']).to eq('blue') + + resp_b = @client.chat.update_channel_partial( + 'messaging', channel_id, + GetStream::Generated::Models::UpdateChannelPartialRequest.new( + unset: ['color'], + ) + ) + ch_b = resp_b.channel.to_h + custom_b = ch_b['custom'] || {} + expect(custom_b).not_to have_key('color') + + end + + end + + # --------------------------------------------------------------------------- + # SendMessage via generated client + # --------------------------------------------------------------------------- + + describe 'SendMessage' do + + it 'sends a message using the generated chat client' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_a] + ) + + resp = @client.chat.send_message( + 'messaging', channel_id, + GetStream::Generated::Models::SendMessageRequest.new( + message: { text: 'Hello from generated client', user_id: @creator_id }, + ) + ) + expect(resp.message).not_to be_nil + expect(resp.message.to_h['text']).to eq('Hello from generated client') + + end + + end + + # --------------------------------------------------------------------------- + # HideChannel and ShowChannel via generated client + # --------------------------------------------------------------------------- + + describe 'HideShowChannel' do + + it 'hides and shows a channel using the generated chat client' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_a] + ) + + @client.chat.hide_channel( + 'messaging', channel_id, + GetStream::Generated::Models::HideChannelRequest.new(user_id: @member_a) + ) + + @client.chat.show_channel( + 'messaging', channel_id, + GetStream::Generated::Models::ShowChannelRequest.new(user_id: @member_a) + ) + + end + + end + + # --------------------------------------------------------------------------- + # TruncateChannel via generated client + # --------------------------------------------------------------------------- + + describe 'TruncateChannel' do + + it 'truncates a channel using the generated chat client' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_a] + ) + + send_test_message('messaging', channel_id, @creator_id, 'Message to truncate') + + @client.chat.truncate_channel( + 'messaging', channel_id, + GetStream::Generated::Models::TruncateChannelRequest.new(hard_delete: true) + ) + + resp = @client.chat.get_or_create_channel( + 'messaging', channel_id, + GetStream::Generated::Models::ChannelGetOrCreateRequest.new + ) + messages = resp.messages || [] + expect(messages).to be_empty + + end + + end + + # --------------------------------------------------------------------------- + # SendEvent via generated client + # --------------------------------------------------------------------------- + + describe 'SendEvent' do + + it 'sends a typing event using the generated chat client' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_a] + ) + + resp = @client.chat.send_event( + 'messaging', channel_id, + GetStream::Generated::Models::SendEventRequest.new( + event: { type: 'typing.start', user_id: @creator_id }, + ) + ) + expect(resp).not_to be_nil + + end + + end + + # --------------------------------------------------------------------------- + # DeleteChannel via generated client + # --------------------------------------------------------------------------- + + describe 'DeleteChannel' do + + it 'soft deletes a channel using the generated chat client' do + + channel_id = "test-del-#{SecureRandom.hex(6)}" + @client.chat.get_or_create_channel( + 'messaging', channel_id, + GetStream::Generated::Models::ChannelGetOrCreateRequest.new( + data: { created_by_id: @creator_id }, + ) + ) + # Don't track since we are deleting it + resp = @client.chat.delete_channel('messaging', channel_id) + expect(resp.channel).not_to be_nil + + end + + end + + # --------------------------------------------------------------------------- + # DeleteChannels (batch) via generated client + # --------------------------------------------------------------------------- + + describe 'DeleteChannels' do + + it 'batch hard deletes channels using the generated chat client' do + + _type_a, channel_id_a, _resp_a = create_test_channel(@creator_id) + _type_b, channel_id_b, _resp_b = create_test_channel(@creator_id) + + cid_a = "messaging:#{channel_id_a}" + cid_b = "messaging:#{channel_id_b}" + + @created_channel_cids.delete(cid_a) + @created_channel_cids.delete(cid_b) + + resp = @client.chat.delete_channels( + GetStream::Generated::Models::DeleteChannelsRequest.new( + cids: [cid_a, cid_b], + hard_delete: true, + ), + ) + expect(resp.task_id).not_to be_nil + + result = wait_for_task(resp.task_id) + expect(result.status).to eq('completed') + + end + + end + + # --------------------------------------------------------------------------- + # ListChannelTypes via generated client + # --------------------------------------------------------------------------- + + describe 'ListChannelTypes' do + + it 'lists channel types using the generated chat client' do + + resp = @client.chat.list_channel_types + resp_h = resp.to_h + expect(resp_h['channel_types']).not_to be_nil + expect(resp_h['channel_types']).not_to be_empty + + end + + end + + # --------------------------------------------------------------------------- + # GetChannelType via generated client + # --------------------------------------------------------------------------- + + describe 'GetChannelType' do + + it 'gets the messaging channel type using the generated chat client' do + + resp = @client.chat.get_channel_type('messaging') + expect(resp.name).to eq('messaging') + + end + + end + + # --------------------------------------------------------------------------- + # MarkRead via generated client + # --------------------------------------------------------------------------- + + describe 'MarkRead' do + + it 'marks a channel as read using the generated chat client' do + + _type, channel_id, _resp = create_test_channel_with_members( + @creator_id, [@creator_id, @member_a] + ) + + send_test_message('messaging', channel_id, @creator_id, 'Read me') + + resp = @client.chat.mark_read( + 'messaging', channel_id, + GetStream::Generated::Models::MarkReadRequest.new(user_id: @member_a) + ) + expect(resp).not_to be_nil + + end + + end + +end diff --git a/spec/integration/chat_message_integration_spec.rb b/spec/integration/chat_message_integration_spec.rb new file mode 100644 index 0000000..0980d22 --- /dev/null +++ b/spec/integration/chat_message_integration_spec.rb @@ -0,0 +1,717 @@ +# frozen_string_literal: true + +require 'rspec' +require 'securerandom' +require 'json' +require_relative 'chat_test_helpers' + +RSpec.describe 'Chat Message Integration', type: :integration do + + include ChatTestHelpers + + before(:all) do + + init_chat_client + # Create shared test users for all subtests + @shared_user_ids, _resp = create_test_users(3) + @user_1 = @shared_user_ids[0] + @user_2 = @shared_user_ids[1] + @user_3 = @shared_user_ids[2] + + end + + after(:all) do + + cleanup_chat_resources + + end + + # --------------------------------------------------------------------------- + # Message API wrappers + # --------------------------------------------------------------------------- + + def get_message(message_id) + @client.make_request(:get, "/api/v2/chat/messages/#{message_id}") + end + + def get_many_messages(type, id, message_ids) + @client.make_request( + :get, + "/api/v2/chat/channels/#{type}/#{id}/messages", + query_params: { 'ids' => message_ids.join(',') }, + ) + end + + def update_message(message_id, body) + @client.make_request(:post, "/api/v2/chat/messages/#{message_id}", body: body) + end + + def update_message_partial(message_id, body) + @client.make_request(:put, "/api/v2/chat/messages/#{message_id}", body: body) + end + + def delete_message(message_id, query_params = {}) + @client.make_request(:delete, "/api/v2/chat/messages/#{message_id}", query_params: query_params) + end + + def send_msg(type, id, body) + @client.make_request(:post, "/api/v2/chat/channels/#{type}/#{id}/message", body: body) + end + + def translate_message(message_id, body) + @client.make_request(:post, "/api/v2/chat/messages/#{message_id}/translate", body: body) + end + + def get_replies(parent_id, **query_params) + @client.make_request(:get, "/api/v2/chat/messages/#{parent_id}/replies", query_params: query_params) + end + + def search_messages(body) + @client.make_request(:get, '/api/v2/chat/search', query_params: { 'payload' => JSON.generate(body) }) + end + + def commit_message(message_id) + @client.make_request(:post, "/api/v2/chat/messages/#{message_id}/commit") + end + + def query_message_history(body) + @client.make_request(:post, '/api/v2/chat/messages/history', body: body) + end + + def hide_channel(type, id, body) + @client.make_request(:post, "/api/v2/chat/channels/#{type}/#{id}/hide", body: body) + end + + def undelete_message(message_id, body) + @client.make_request(:post, "/api/v2/chat/messages/#{message_id}/undelete", body: body) + end + + # --------------------------------------------------------------------------- + # Tests + # --------------------------------------------------------------------------- + + describe 'SendAndGetMessage' do + + it 'sends message, gets by ID, verifies text' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + + msg_text = "Hello from integration test #{SecureRandom.hex(8)}" + send_resp = send_msg('messaging', channel_id, + message: { text: msg_text, user_id: @user_1 }) + expect(send_resp.message).not_to be_nil + msg_id = send_resp.message.id + expect(msg_id).not_to be_nil + expect(send_resp.message.to_h['text']).to eq(msg_text) + + # Get message by ID + get_resp = get_message(msg_id) + expect(get_resp.message).not_to be_nil + expect(get_resp.message.to_h['id']).to eq(msg_id) + expect(get_resp.message.to_h['text']).to eq(msg_text) + + end + + end + + describe 'GetManyMessages' do + + it 'sends 3 messages, gets all 3 by IDs' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + + id_1 = send_test_message('messaging', channel_id, @user_1, 'Msg 1') + id_2 = send_test_message('messaging', channel_id, @user_1, 'Msg 2') + id_3 = send_test_message('messaging', channel_id, @user_1, 'Msg 3') + + resp = get_many_messages('messaging', channel_id, [id_1, id_2, id_3]) + expect(resp.messages).not_to be_nil + expect(resp.messages.length).to eq(3) + + end + + end + + describe 'UpdateMessage' do + + it 'sends message, updates text, verifies' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + msg_id = send_test_message('messaging', channel_id, @user_1, 'Original text') + + updated_text = "Updated text #{SecureRandom.hex(8)}" + resp = update_message(msg_id, message: { text: updated_text, user_id: @user_1 }) + expect(resp.message).not_to be_nil + expect(resp.message.to_h['text']).to eq(updated_text) + + end + + end + + describe 'PartialUpdateMessage' do + + it 'sets custom fields; unsets one' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + msg_id = send_test_message('messaging', channel_id, @user_1, 'Partial update test') + + # Set custom fields + resp = update_message_partial(msg_id, + set: { 'priority' => 'high', 'status' => 'reviewed' }, + user_id: @user_1) + expect(resp.message).not_to be_nil + + # Unset custom field + resp_2 = update_message_partial(msg_id, + unset: ['status'], + user_id: @user_1) + expect(resp_2.message).not_to be_nil + + end + + end + + describe 'DeleteMessage' do + + it 'soft deletes, verifies type=deleted' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + msg_id = send_test_message('messaging', channel_id, @user_1, 'Message to delete') + + resp = delete_message(msg_id) + expect(resp.message).not_to be_nil + expect(resp.message.to_h['type']).to eq('deleted') + + end + + end + + describe 'HardDeleteMessage' do + + it 'hard deletes, verifies type=deleted' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + msg_id = send_test_message('messaging', channel_id, @user_1, 'Message to hard delete') + + resp = delete_message(msg_id, { 'hard' => 'true' }) + expect(resp.message).not_to be_nil + expect(resp.message.to_h['type']).to eq('deleted') + + end + + end + + describe 'PinUnpinMessage' do + + it 'sends pinned message; unpins via partial update' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + + # Send a pinned message + send_resp = send_msg('messaging', channel_id, + message: { text: 'Pinned message', user_id: @user_1, pinned: true }) + expect(send_resp.message).not_to be_nil + msg_id = send_resp.message.id + expect(send_resp.message.to_h['pinned']).to eq(true) + + # Unpin via partial update + resp = update_message_partial(msg_id, + set: { 'pinned' => false }, + user_id: @user_1) + expect(resp.message).not_to be_nil + expect(resp.message.to_h['pinned']).to eq(false) + + end + + end + + describe 'TranslateMessage' do + + it 'translates to Spanish, verifies i18n field' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + msg_id = send_test_message('messaging', channel_id, @user_1, 'Hello, how are you?') + + resp = translate_message(msg_id, language: 'es') + expect(resp.message).not_to be_nil + i18n = resp.message.to_h['i18n'] + expect(i18n).not_to be_nil + + end + + end + + describe 'ThreadReply' do + + it 'sends parent, sends reply with parent_id, gets replies' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1, @user_2]) + + # Send parent message + parent_id = send_test_message('messaging', channel_id, @user_1, 'Parent message for thread') + + # Send reply + reply_resp = send_msg('messaging', channel_id, + message: { text: 'Reply to parent', user_id: @user_2, parent_id: parent_id }) + expect(reply_resp.message).not_to be_nil + expect(reply_resp.message.id).not_to be_nil + + # Get replies + replies_resp = get_replies(parent_id) + expect(replies_resp.messages).not_to be_nil + expect(replies_resp.messages.length).to be >= 1 + + end + + end + + describe 'SearchMessages' do + + it 'sends message with unique term, waits, searches, verifies found' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + + search_term = "uniquesearch#{SecureRandom.hex(8)}" + send_test_message('messaging', channel_id, @user_1, "This message contains #{search_term} for testing") + + # Wait for indexing + sleep(2) + + resp = search_messages( + query: search_term, + filter_conditions: { 'cid' => "messaging:#{channel_id}" }, + ) + expect(resp.results).not_to be_nil + expect(resp.results).not_to be_empty + + end + + end + + describe 'SilentMessage' do + + it 'sends with silent=true, verifies' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + + resp = send_msg('messaging', channel_id, + message: { text: 'This is a silent message', user_id: @user_1, silent: true }) + expect(resp.message).not_to be_nil + expect(resp.message.to_h['silent']).to eq(true) + + end + + end + + describe 'PendingMessage' do + + it 'sends pending, commits, verifies (skip if not enabled)' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + + begin + send_resp = send_msg('messaging', channel_id, + message: { text: 'Pending message text', user_id: @user_1 }, + pending: true, + skip_push: true) + rescue GetStreamRuby::APIError => e + if e.message.include?('pending messages not enabled') || e.message.include?('feature flag') + skip('Pending messages feature not enabled for this app') + end + raise + end + + expect(send_resp.message).not_to be_nil + msg_id = send_resp.message.id + expect(msg_id).not_to be_nil + + # Commit the pending message + commit_resp = commit_message(msg_id) + expect(commit_resp.message).not_to be_nil + expect(commit_resp.message.to_h['id']).to eq(msg_id) + + end + + end + + describe 'QueryMessageHistory' do + + it 'sends, updates twice, queries history, verifies entries (skip if not enabled)' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1, @user_2]) + + # Send initial message + send_resp = send_msg('messaging', channel_id, + message: { text: 'initial text', user_id: @user_1, + custom: { 'custom_field' => 'custom value' } }) + msg_id = send_resp.message.id + + # Update by user1 + update_message(msg_id, message: { text: 'updated text', user_id: @user_1, + custom: { 'custom_field' => 'updated custom value' } }) + + # Update by user2 + update_message(msg_id, message: { text: 'updated text 2', user_id: @user_2 }) + + # Query message history + begin + hist_resp = query_message_history( + filter: { 'message_id' => msg_id }, + sort: [], + ) + rescue GetStreamRuby::APIError => e + if e.message.include?('feature flag') || e.message.include?('not enabled') + skip('QueryMessageHistory feature not enabled for this app') + end + raise + end + + expect(hist_resp.message_history).not_to be_nil + expect(hist_resp.message_history.length).to be >= 2 + + # Verify history entries reference the correct message + hist_resp.message_history.each do |entry| + + h = entry.to_h + expect(h['message_id']).to eq(msg_id) + + end + + # Verify text values (descending by default: most recent first) + expect(hist_resp.message_history.first.to_h['text']).to eq('updated text 2') + expect(hist_resp.message_history.last.to_h['text']).to eq('initial text') + + end + + end + + describe 'QueryMessageHistorySort' do + + it 'queries history with ascending sort' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + + send_resp = send_msg('messaging', channel_id, + message: { text: 'sort initial', user_id: @user_1 }) + msg_id = send_resp.message.id + + update_message(msg_id, message: { text: 'sort updated 1', user_id: @user_1 }) + update_message(msg_id, message: { text: 'sort updated 2', user_id: @user_1 }) + + begin + hist_resp = query_message_history( + filter: { 'message_id' => msg_id }, + sort: [{ 'field' => 'message_updated_at', 'direction' => 1 }], + ) + rescue GetStreamRuby::APIError => e + if e.message.include?('feature flag') || e.message.include?('not enabled') + skip('QueryMessageHistory feature not enabled for this app') + end + raise + end + + expect(hist_resp.message_history).not_to be_nil + expect(hist_resp.message_history.length).to be >= 2 + + # Ascending: oldest first + expect(hist_resp.message_history[0].to_h['text']).to eq('sort initial') + + end + + end + + describe 'SkipEnrichUrl' do + + it 'sends with URL and skip_enrich_url=true, verifies no attachments' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + + send_resp = send_msg('messaging', channel_id, + message: { text: 'Check out https://getstream.io for more info', user_id: @user_1 }, + skip_enrich_url: true) + expect(send_resp.message).not_to be_nil + attachments = send_resp.message.to_h['attachments'] || [] + expect(attachments).to be_empty + + # Verify via GetMessage that attachments remain empty + sleep(1) + get_resp = get_message(send_resp.message.id) + attachments_2 = get_resp.message.to_h['attachments'] || [] + expect(attachments_2).to be_empty + + end + + end + + describe 'KeepChannelHidden' do + + it 'hides channel, sends with keep_channel_hidden=true, verifies still hidden' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + cid = "messaging:#{channel_id}" + + # Hide the channel + hide_channel('messaging', channel_id, user_id: @user_1) + + # Send a message with keep_channel_hidden=true + send_msg('messaging', channel_id, + message: { text: 'Hidden message', user_id: @user_1 }, + keep_channel_hidden: true) + + # Query channels โ€” the channel should still be hidden + q_resp = query_channels( + filter_conditions: { 'cid' => cid }, + user_id: @user_1, + ) + expect(q_resp.channels).to be_empty + + end + + end + + describe 'UndeleteMessage' do + + it 'soft deletes, undeletes, verifies restored' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + msg_id = send_test_message('messaging', channel_id, @user_1, 'Message to undelete') + + # Soft delete + delete_message(msg_id) + + # Verify deleted + get_resp = get_message(msg_id) + expect(get_resp.message.to_h['type']).to eq('deleted') + + # Undelete + begin + undel_resp = undelete_message(msg_id, undeleted_by: @user_1) + rescue GetStreamRuby::APIError => e + if e.message.include?('undeleted_by') || e.message.include?('required field') + skip('UndeleteMessage requires undeleted_by field not yet in generated request struct') + end + raise + end + expect(undel_resp.message).not_to be_nil + expect(undel_resp.message.to_h['type']).not_to eq('deleted') + expect(undel_resp.message.to_h['text']).to eq('Message to undelete') + + end + + end + + describe 'RestrictedVisibility' do + + it 'sends with restricted_visibility list (skip if not enabled)' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1, @user_2]) + + begin + send_resp = send_msg('messaging', channel_id, + message: { text: 'Secret message', user_id: @user_1, + restricted_visibility: [@user_1] }) + rescue GetStreamRuby::APIError => e + if e.message.include?('private messaging is not allowed') || e.message.include?('not enabled') + skip('RestrictedVisibility (private messaging) is not enabled for this app') + end + raise + end + + expect(send_resp.message.to_h['restricted_visibility']).to eq([@user_1]) + + end + + end + + describe 'DeleteMessageForMe' do + + it 'deletes message with delete_for_me=true' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + msg_id = send_test_message('messaging', channel_id, @user_1, 'test message to delete for me') + + delete_message(msg_id, { 'delete_for_me' => 'true', 'deleted_by' => @user_1 }) + + end + + end + + describe 'PinExpiration' do + + it 'pins with 3s expiry, waits 4s, verifies expired' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1, @user_2]) + msg_id = send_test_message('messaging', channel_id, @user_2, 'Message to pin with expiry') + + # Pin with 3 second expiration + expiry = (Time.now.utc + 3).strftime('%Y-%m-%dT%H:%M:%S.%6NZ') + pin_resp = update_message_partial(msg_id, + set: { 'pinned' => true, 'pin_expires' => expiry }, + user_id: @user_1) + expect(pin_resp.message).not_to be_nil + expect(pin_resp.message.to_h['pinned']).to eq(true) + + # Wait for pin to expire + sleep(4) + + # Verify pin expired + get_resp = get_message(msg_id) + expect(get_resp.message.to_h['pinned']).to eq(false) + + end + + end + + describe 'SystemMessage' do + + it 'sends with type=system, verifies' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + + resp = send_msg('messaging', channel_id, + message: { text: 'User joined the channel', user_id: @user_1, type: 'system' }) + expect(resp.message).not_to be_nil + expect(resp.message.to_h['type']).to eq('system') + + end + + end + + describe 'PendingFalse' do + + it 'sends with pending=false, verifies immediately available' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + + send_resp = send_msg('messaging', channel_id, + message: { text: 'Non-pending message', user_id: @user_1 }, + pending: false) + expect(send_resp.message).not_to be_nil + + # Get the message to verify it's immediately available + get_resp = get_message(send_resp.message.id) + expect(get_resp.message.to_h['text']).to eq('Non-pending message') + + end + + end + + describe 'SearchWithMessageFilters' do + + it 'searches using message_filter_conditions' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + + search_term = "filterable#{SecureRandom.hex(8)}" + send_test_message('messaging', channel_id, @user_1, "This has #{search_term} text") + send_test_message('messaging', channel_id, @user_1, "This also has #{search_term} text") + + # Wait for indexing + sleep(2) + + resp = search_messages( + filter_conditions: { 'cid' => "messaging:#{channel_id}" }, + message_filter_conditions: { 'text' => { '$q' => search_term } }, + ) + expect(resp.results).not_to be_nil + expect(resp.results.length).to be >= 2 + + end + + end + + describe 'SearchQueryAndMessageFiltersError' do + + it 'verifies error when using both query and message_filter_conditions' do + + params = { + filter_conditions: { 'members' => { '$in' => [@user_1] } }, + query: 'test', + message_filter_conditions: { 'text' => { '$q' => 'test' } }, + } + expect { search_messages(**params) }.to raise_error(GetStreamRuby::APIError) + + end + + end + + describe 'SearchOffsetAndSortError' do + + it 'verifies error when using offset with sort' do + + # The API may or may not reject offset+sort. Verify either an error or a valid response. + + resp = search_messages( + filter_conditions: { 'members' => { '$in' => [@user_1] } }, + query: 'test', + offset: 1, + sort: [{ 'field' => 'created_at', 'direction' => -1 }], + ) + # If no error, the API accepts the combination โ€” verify a valid response + expect(resp).not_to be_nil + rescue GetStreamRuby::APIError + # Expected error โ€” test passes + + end + + end + + describe 'SearchOffsetAndNextError' do + + it 'verifies error when using offset with next' do + + params = { + filter_conditions: { 'members' => { '$in' => [@user_1] } }, + query: 'test', + offset: 1, + next: SecureRandom.hex(5), + } + expect { search_messages(**params) }.to raise_error(GetStreamRuby::APIError) + + end + + end + + describe 'ChannelRoleInMember' do + + it 'creates channel with roles, sends messages, verifies member.channel_role in response' do + + role_user_ids, _resp = create_test_users(2) + member_user_id = role_user_ids[0] + mod_user_id = role_user_ids[1] + + channel_id = "test-ch-#{SecureRandom.hex(6)}" + @client.make_request( + :post, + "/api/v2/chat/channels/messaging/#{channel_id}/query", + body: { + data: { + created_by_id: member_user_id, + members: [ + { user_id: member_user_id, channel_role: 'channel_member' }, + { user_id: mod_user_id, channel_role: 'channel_moderator' }, + ], + }, + }, + ) + @created_channel_cids << "messaging:#{channel_id}" + + # Send message from channel_member + resp_member = send_msg('messaging', channel_id, + message: { text: 'message from channel_member', user_id: member_user_id }) + expect(resp_member.message).not_to be_nil + member_data = resp_member.message.to_h['member'] || {} + expect(member_data['channel_role']).to eq('channel_member') + + # Send message from channel_moderator + resp_mod = send_msg('messaging', channel_id, + message: { text: 'message from channel_moderator', user_id: mod_user_id }) + expect(resp_mod.message).not_to be_nil + mod_data = resp_mod.message.to_h['member'] || {} + expect(mod_data['channel_role']).to eq('channel_moderator') + + end + + end + +end diff --git a/spec/integration/chat_misc_integration_spec.rb b/spec/integration/chat_misc_integration_spec.rb new file mode 100644 index 0000000..99eea9d --- /dev/null +++ b/spec/integration/chat_misc_integration_spec.rb @@ -0,0 +1,775 @@ +# frozen_string_literal: true + +require 'rspec' +require 'securerandom' +require 'json' +require_relative 'chat_test_helpers' + +RSpec.describe 'Chat Misc Integration', type: :integration do + + include ChatTestHelpers + + before(:all) do + + init_chat_client + @shared_user_ids, _resp = create_test_users(4) + @user_1 = @shared_user_ids[0] + @user_2 = @shared_user_ids[1] + @user_3 = @shared_user_ids[2] + @user_4 = @shared_user_ids[3] + @created_blocklist_names = [] + @created_command_names = [] + @created_channel_type_names = [] + @created_role_names = [] + + end + + after(:all) do + + # Clean up blocklists + @created_blocklist_names&.each do |name| + + @client.common.delete_block_list(name) + rescue StandardError => e + puts "Warning: Failed to delete blocklist #{name}: #{e.message}" + + end + + # Clean up commands + @created_command_names&.each do |name| + + @client.make_request(:delete, "/api/v2/chat/commands/#{name}") + rescue StandardError => e + puts "Warning: Failed to delete command #{name}: #{e.message}" + + end + + # Clean up channel types (with retry due to eventual consistency) + @created_channel_type_names&.each do |name| + + 3.times do |i| + + @client.make_request(:delete, "/api/v2/chat/channeltypes/#{name}") + break + rescue StandardError => e + puts "Warning: Failed to delete channel type #{name} (attempt #{i + 1}): #{e.message}" + sleep(1) + + end + + end + + # Clean up roles + @created_role_names&.each do |name| + + 3.times do |i| + + @client.common.delete_role(name) + break + rescue StandardError => e + puts "Warning: Failed to delete role #{name} (attempt #{i + 1}): #{e.message}" + sleep(1) + + end + + end + + cleanup_chat_resources + + end + + # --------------------------------------------------------------------------- + # Devices + # --------------------------------------------------------------------------- + + describe 'CreateListDeleteDevice' do + + it 'creates a firebase device, lists it, deletes it, and verifies gone' do + + device_id = "integration-test-device-#{random_string(12)}" + + # Create device + @client.common.create_device( + GetStream::Generated::Models::CreateDeviceRequest.new( + id: device_id, + push_provider: 'firebase', + user_id: @user_1, + ), + ) + + # List devices + list_resp = @client.common.list_devices(@user_1) + devices = list_resp.devices || [] + found = devices.any? do |d| + + h = d.is_a?(Hash) ? d : d.to_h + + h['id'] == device_id + + end + expect(found).to be(true), 'Created device should appear in list' + + # Delete device + @client.common.delete_device(device_id, @user_1) + + # Verify deleted + list_resp_2 = @client.common.list_devices(@user_1) + devices_2 = list_resp_2.devices || [] + still_found = devices_2.any? do |d| + + h = d.is_a?(Hash) ? d : d.to_h + + h['id'] == device_id + + end + expect(still_found).to be(false), 'Device should be deleted' + rescue GetStreamRuby::APIError => e + if e.message.include?('push provider') || e.message.include?('no push') + skip('Push providers not configured for this app') + end + raise + + end + + end + + # --------------------------------------------------------------------------- + # Blocklists + # --------------------------------------------------------------------------- + + describe 'CreateListDeleteBlocklist' do + + it 'creates a custom blocklist, lists it, verifies found, and deletes it' do + + blocklist_name = "test-blocklist-#{random_string(8)}" + + # Create blocklist + @client.common.create_block_list( + GetStream::Generated::Models::CreateBlockListRequest.new( + name: blocklist_name, + words: %w[badword1 badword2 badword3], + ), + ) + @created_blocklist_names << blocklist_name + + # Get blocklist and verify + get_resp = @client.common.get_block_list(blocklist_name) + expect(get_resp.blocklist).not_to be_nil + bl_h = get_resp.blocklist.to_h + expect(bl_h['name']).to eq(blocklist_name) + expect(bl_h['words'].length).to eq(3) + + # Update blocklist + @client.common.update_block_list( + blocklist_name, + GetStream::Generated::Models::UpdateBlockListRequest.new( + words: %w[badword1 badword2 badword3 badword4], + ), + ) + + # Verify update + get_resp_2 = @client.common.get_block_list(blocklist_name) + bl_h_2 = get_resp_2.blocklist.to_h + expect(bl_h_2['words'].length).to eq(4) + + # List blocklists and verify found + list_resp = @client.common.list_block_lists + blocklists = list_resp.blocklists || [] + found = blocklists.any? do |bl| + + h = bl.is_a?(Hash) ? bl : bl.to_h + h['name'] == blocklist_name + + end + expect(found).to be(true), 'Created blocklist should appear in list' + + # Delete a separate blocklist to test deletion + del_name = "test-del-bl-#{random_string(8)}" + @client.common.create_block_list( + GetStream::Generated::Models::CreateBlockListRequest.new( + name: del_name, + words: %w[word1], + ), + ) + @created_blocklist_names << del_name + @client.common.delete_block_list(del_name) + @created_blocklist_names.delete(del_name) + + end + + end + + # --------------------------------------------------------------------------- + # Commands + # --------------------------------------------------------------------------- + + describe 'CreateListDeleteCommand' do + + it 'creates a custom command, lists it, verifies found, and deletes it' do + + cmd_name = "testcmd#{random_string(6)}" + + # Create command + resp = @client.make_request(:post, '/api/v2/chat/commands', body: { + name: cmd_name, + description: 'A test command', + }) + expect(resp).not_to be_nil + @created_command_names << cmd_name + + # Get command + get_resp = @client.make_request(:get, "/api/v2/chat/commands/#{cmd_name}") + expect(get_resp.name).to eq(cmd_name) + expect(get_resp.description).to eq('A test command') + + # Update command + @client.make_request(:put, "/api/v2/chat/commands/#{cmd_name}", body: { + description: 'Updated test command', + }) + + # Verify update + get_resp_2 = @client.make_request(:get, "/api/v2/chat/commands/#{cmd_name}") + expect(get_resp_2.description).to eq('Updated test command') + + # List commands + list_resp = @client.make_request(:get, '/api/v2/chat/commands') + commands = list_resp.commands || [] + found = commands.any? do |c| + + h = c.is_a?(Hash) ? c : c.to_h + h['name'] == cmd_name + + end + expect(found).to be(true), 'Created command should appear in list' + + # Delete a separate command + del_name = "testdelcmd#{random_string(6)}" + @client.make_request(:post, '/api/v2/chat/commands', body: { + name: del_name, + description: 'Command to delete', + }) + del_resp = @client.make_request(:delete, "/api/v2/chat/commands/#{del_name}") + expect(del_resp).not_to be_nil + + end + + end + + # --------------------------------------------------------------------------- + # Channel Types + # --------------------------------------------------------------------------- + + describe 'CreateUpdateDeleteChannelType' do + + it 'creates a channel type, updates settings, verifies, and deletes' do + + type_name = "testtype#{random_string(6)}" + + # Create channel type with a lower max_message_length so the update below + # can demonstrate the value actually changes. The test app plan caps at + # 4000, so stay within that ceiling to avoid silent truncation. + create_resp = @client.make_request(:post, '/api/v2/chat/channeltypes', body: { + name: type_name, + automod: 'disabled', + automod_behavior: 'flag', + max_message_length: 3000, + }) + expect(create_resp.name).to eq(type_name) + @created_channel_type_names << type_name + + # Wait for eventual consistency + sleep(2) + + # Get channel type + get_resp = @client.make_request(:get, "/api/v2/chat/channeltypes/#{type_name}") + expect(get_resp.name).to eq(type_name) + + # Update channel type โ€” raise to 4000 (plan maximum) to verify the + # update is applied. Assert on the update response directly: it is read + # from the writing server's local cache (always fresh) so we avoid the + # eventual consistency window that makes a re-fetch flaky. + update_resp = @client.make_request(:put, "/api/v2/chat/channeltypes/#{type_name}", body: { + automod: 'disabled', + automod_behavior: 'flag', + max_message_length: 4000, + typing_events: false, + }) + expect(update_resp.max_message_length).to eq(4000) + + # Delete a separate channel type + del_name = "testdeltype#{random_string(6)}" + @client.make_request(:post, '/api/v2/chat/channeltypes', body: { + name: del_name, + automod: 'disabled', + automod_behavior: 'flag', + max_message_length: 4000, + }) + @created_channel_type_names << del_name + + sleep(2) + + delete_err = nil + 5.times do |_i| + + @client.make_request(:delete, "/api/v2/chat/channeltypes/#{del_name}") + @created_channel_type_names.delete(del_name) + delete_err = nil + break + rescue StandardError => e + delete_err = e + sleep(2) + + end + expect(delete_err).to be_nil, "Channel type deletion should succeed: #{delete_err&.message}" + + end + + end + + describe 'ListChannelTypes' do + + it 'lists all channel types and verifies default types present' do + + resp = @client.make_request(:get, '/api/v2/chat/channeltypes') + expect(resp.channel_types).not_to be_nil + + types_h = resp.channel_types.to_h + expect(types_h.key?('messaging')).to be(true), "Default 'messaging' type should be present" + + end + + end + + # --------------------------------------------------------------------------- + # Permissions & Roles + # --------------------------------------------------------------------------- + + describe 'ListPermissions' do + + it 'lists all permissions and verifies non-empty' do + + resp = @client.common.list_permissions + expect(resp.permissions).not_to be_nil + expect(resp.permissions.length).to be > 0 + + end + + end + + describe 'CreatePermission' do + + it 'creates a custom role, lists it, and verifies custom flag' do + + role_name = "testrole#{random_string(6)}" + + # Create role + @client.common.create_role( + GetStream::Generated::Models::CreateRoleRequest.new(name: role_name), + ) + @created_role_names << role_name + + # List roles and verify + list_resp = @client.common.list_roles + roles = list_resp.roles || [] + found = roles.any? do |r| + + h = r.is_a?(Hash) ? r : r.to_h + h['name'] == role_name && h['custom'] == true + + end + expect(found).to be(true), 'Created role should appear in list as custom' + + end + + end + + describe 'GetPermission' do + + it 'gets a specific permission by ID' do + + resp = @client.common.get_permission('create-channel') + expect(resp.permission).not_to be_nil + perm_h = resp.permission.to_h + expect(perm_h['id']).to eq('create-channel') + expect(perm_h['action']).not_to be_nil + expect(perm_h['action']).not_to be_empty + + end + + end + + # --------------------------------------------------------------------------- + # Banned Users + # --------------------------------------------------------------------------- + + describe 'QueryBannedUsers' do + + it 'bans a user in channel, queries banned users, and verifies' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1, @user_2]) + cid = "messaging:#{channel_id}" + + # Ban user in channel + @client.moderation.ban( + GetStream::Generated::Models::BanRequest.new( + target_user_id: @user_2, + banned_by_id: @user_1, + channel_cid: cid, + reason: 'test ban reason', + timeout: 60, + ), + ) + + # Query banned users + payload = JSON.generate({ filter_conditions: { 'channel_cid' => { '$eq' => cid } } }) + resp = @client.make_request( + :get, + '/api/v2/chat/query_banned_users', + query_params: { 'payload' => payload }, + ) + bans = resp.bans || [] + expect(bans.length).to be >= 1 + + ban_h = bans[0].is_a?(Hash) ? bans[0] : bans[0].to_h + expect(ban_h['reason']).to eq('test ban reason') + + # Unban + @client.moderation.unban( + GetStream::Generated::Models::UnbanRequest.new, + @user_2, + cid, + ) + + # Verify ban is gone + payload = JSON.generate({ filter_conditions: { 'channel_cid' => { '$eq' => cid } } }) + resp_2 = @client.make_request( + :get, + '/api/v2/chat/query_banned_users', + query_params: { 'payload' => payload }, + ) + bans_2 = resp_2.bans || [] + expect(bans_2.length).to eq(0), 'Bans should be empty after unban' + + end + + end + + # --------------------------------------------------------------------------- + # Mute/Unmute User + # --------------------------------------------------------------------------- + + describe 'MuteUnmuteUser' do + + it 'mutes user, verifies via query, and unmutes' do + + # Mute user + mute_resp = @client.moderation.mute( + GetStream::Generated::Models::MuteRequest.new( + target_ids: [@user_3], + user_id: @user_1, + ), + ) + expect(mute_resp.mutes).not_to be_nil + expect(mute_resp.mutes.length).to be >= 1 + + mute_h = mute_resp.mutes[0].is_a?(Hash) ? mute_resp.mutes[0] : mute_resp.mutes[0].to_h + expect(mute_h['target']).not_to be_nil + + # Verify via QueryUsers that user has mutes + q_resp = @client.common.query_users(JSON.generate({ + filter_conditions: { 'id' => { '$eq' => @user_1 } }, + })) + expect(q_resp.users).not_to be_nil + expect(q_resp.users.length).to be >= 1 + user_h = q_resp.users[0].is_a?(Hash) ? q_resp.users[0] : q_resp.users[0].to_h + expect(user_h['mutes']).not_to be_nil + expect(user_h['mutes'].length).to be >= 1 + + # Unmute + @client.moderation.unmute( + GetStream::Generated::Models::UnmuteRequest.new( + target_ids: [@user_3], + user_id: @user_1, + ), + ) + + end + + end + + # --------------------------------------------------------------------------- + # App Settings + # --------------------------------------------------------------------------- + + describe 'GetAppSettings' do + + it 'gets app settings and verifies response' do + + resp = @client.common.get_app + expect(resp).not_to be_nil + expect(resp.app).not_to be_nil + app_h = resp.app.to_h + expect(app_h['name']).not_to be_nil + expect(app_h['name']).not_to be_empty + + end + + end + + # --------------------------------------------------------------------------- + # Export Channels + # --------------------------------------------------------------------------- + + describe 'ExportChannels' do + + it 'exports channel messages and polls task until completed' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + send_test_message('messaging', channel_id, @user_1, "Message for export test #{SecureRandom.hex(4)}") + + cid = "messaging:#{channel_id}" + + # Export channels + export_resp = @client.make_request(:post, '/api/v2/chat/export_channels', body: { + channels: [{ cid: cid }], + }) + expect(export_resp.task_id).not_to be_nil + expect(export_resp.task_id).not_to be_empty + + # Wait for task + task_result = wait_for_task(export_resp.task_id) + expect(task_result.status).to eq('completed') + + end + + end + + # --------------------------------------------------------------------------- + # Threads + # --------------------------------------------------------------------------- + + describe 'Threads' do + + it 'creates parent + replies, queries threads, and verifies' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1, @user_2]) + channel_cid = "messaging:#{channel_id}" + + # Create thread: parent message + replies + parent_id = send_test_message('messaging', channel_id, @user_1, 'Thread parent message') + + send_message('messaging', channel_id, { + message: { + text: 'First reply in thread', + user_id: @user_2, + parent_id: parent_id, + }, + }) + + send_message('messaging', channel_id, { + message: { + text: 'Second reply in thread', + user_id: @user_1, + parent_id: parent_id, + }, + }) + + # Query threads + resp = @client.make_request(:post, '/api/v2/chat/threads', body: { + user_id: @user_1, + filter: { + 'channel_cid' => { '$eq' => channel_cid }, + }, + }) + expect(resp.threads).not_to be_nil + expect(resp.threads.length).to be >= 1 + + found = resp.threads.any? do |t| + + h = t.is_a?(Hash) ? t : t.to_h + h['parent_message_id'] == parent_id + + end + expect(found).to be(true), 'Thread should appear in query results' + + # Get thread + get_resp = @client.make_request(:get, "/api/v2/chat/threads/#{parent_id}", query_params: { + 'reply_limit' => '10', + }) + thread_h = get_resp.thread.is_a?(Hash) ? get_resp.thread : get_resp.thread.to_h + expect(thread_h['parent_message_id']).to eq(parent_id) + latest_replies = thread_h['latest_replies'] || [] + expect(latest_replies.length).to be >= 2 + + end + + end + + # --------------------------------------------------------------------------- + # Unread Counts + # --------------------------------------------------------------------------- + + describe 'GetUnreadCounts' do + + it 'sends message and gets unread counts for user' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1, @user_2]) + send_test_message('messaging', channel_id, @user_1, "Unread test #{SecureRandom.hex(4)}") + + resp = @client.make_request(:get, '/api/v2/chat/unread', query_params: { + 'user_id' => @user_2, + }) + expect(resp).not_to be_nil + expect(resp.total_unread_count).to be >= 0 + + end + + end + + describe 'GetUnreadCountsBatch' do + + it 'gets unread counts for multiple users' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1, @user_2]) + send_test_message('messaging', channel_id, @user_1, "Batch unread test #{SecureRandom.hex(4)}") + + resp = @client.make_request(:post, '/api/v2/chat/unread_batch', body: { + user_ids: [@user_1, @user_2], + }) + expect(resp).not_to be_nil + expect(resp.counts_by_user).not_to be_nil + counts_h = resp.counts_by_user.to_h + expect(counts_h.key?(@user_1)).to be(true) + expect(counts_h.key?(@user_2)).to be(true) + + end + + end + + # --------------------------------------------------------------------------- + # Reminders + # --------------------------------------------------------------------------- + + describe 'Reminders' do + + it 'creates a reminder, lists it, updates it, and deletes it' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + msg_id = send_test_message('messaging', channel_id, @user_1, "Reminder test #{SecureRandom.hex(4)}") + + remind_at = (Time.now + (24 * 3600)).utc.strftime('%Y-%m-%dT%H:%M:%S.%9NZ') + + # Create reminder + create_resp = @client.make_request(:post, "/api/v2/chat/messages/#{msg_id}/reminders", body: { + user_id: @user_1, + remind_at: remind_at, + }) + expect(create_resp).not_to be_nil + + # Query reminders + query_resp = @client.make_request(:post, '/api/v2/chat/reminders/query', body: { + user_id: @user_1, + filter: { 'message_id' => msg_id }, + sort: [], + }) + reminders = query_resp.reminders || [] + expect(reminders.length).to be >= 1 + + # Update reminder + new_remind_at = (Time.now + (48 * 3600)).utc.strftime('%Y-%m-%dT%H:%M:%S.%9NZ') + update_resp = @client.make_request(:patch, "/api/v2/chat/messages/#{msg_id}/reminders", body: { + user_id: @user_1, + remind_at: new_remind_at, + }) + expect(update_resp).not_to be_nil + + # Delete reminder + @client.make_request(:delete, "/api/v2/chat/messages/#{msg_id}/reminders", query_params: { + 'user_id' => @user_1, + }) + rescue GetStreamRuby::APIError => e + skip('Reminders not enabled for this app') if e.message.include?('not enabled') || e.message.include?('reminder') + raise + + end + + end + + # --------------------------------------------------------------------------- + # Send User Custom Event + # --------------------------------------------------------------------------- + + describe 'SendUserCustomEvent' do + + it 'sends a custom event to a user' do + + resp = @client.make_request(:post, "/api/v2/chat/users/#{@user_1}/event", body: { + event: { + type: 'friendship_request', + message: "Let's be friends!", + }, + }) + expect(resp).not_to be_nil + + end + + end + + # --------------------------------------------------------------------------- + # Query Team Usage Stats + # --------------------------------------------------------------------------- + + describe 'QueryTeamUsageStats' do + + it 'queries team usage stats' do + + resp = @client.make_request(:post, '/api/v2/chat/stats/team_usage', body: {}) + expect(resp).not_to be_nil + rescue GetStreamRuby::APIError => e + if e.message.include?('Token signature') || + e.message.include?('not available') || + e.message.include?('not found') || + e.message.include?('Not Found') + skip('QueryTeamUsageStats not available on this app') + end + raise + + end + + end + + # --------------------------------------------------------------------------- + # Channel Batch Update + # --------------------------------------------------------------------------- + + describe 'ChannelBatchUpdate' do + + it 'batch updates multiple channels at once' do + + _type_1, ch_id_1, _resp_1 = create_test_channel(@user_1) + _type_2, ch_id_2, _resp_2 = create_test_channel(@user_1) + + # Batch update: set a custom field on both channels + cids = ["messaging:#{ch_id_1}", "messaging:#{ch_id_2}"] + + resp = @client.make_request(:post, '/api/v2/chat/channels/batch_update', body: { + set: { 'color' => 'blue' }, + filter: { + 'cid' => { '$in' => cids }, + }, + }) + expect(resp).not_to be_nil + rescue GetStreamRuby::APIError => e + if e.message.include?('not available') || + e.message.include?('Not Found') || + e.message.include?('unknown') || + e.message.include?('not found') + skip('Channel batch update not available') + end + raise + + end + + end + +end diff --git a/spec/integration/chat_moderation_integration_spec.rb b/spec/integration/chat_moderation_integration_spec.rb new file mode 100644 index 0000000..7f290f0 --- /dev/null +++ b/spec/integration/chat_moderation_integration_spec.rb @@ -0,0 +1,254 @@ +# frozen_string_literal: true + +require 'rspec' +require 'securerandom' +require 'json' +require_relative 'chat_test_helpers' + +RSpec.describe 'Chat Moderation Integration', type: :integration do + + include ChatTestHelpers + + before(:all) do + + init_chat_client + @shared_user_ids, _resp = create_test_users(4) + @user_1 = @shared_user_ids[0] + @user_2 = @shared_user_ids[1] + @user_3 = @shared_user_ids[2] + @user_4 = @shared_user_ids[3] + + end + + after(:all) do + + cleanup_chat_resources + + end + + # --------------------------------------------------------------------------- + # Ban / Unban User + # --------------------------------------------------------------------------- + + describe 'BanUnbanUser' do + + it 'bans a user from a channel, verifies, and unbans' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1, @user_2]) + cid = "messaging:#{channel_id}" + + # Ban user in channel + @client.moderation.ban( + GetStream::Generated::Models::BanRequest.new( + target_user_id: @user_2, + banned_by_id: @user_1, + channel_cid: cid, + reason: 'moderation test ban', + timeout: 60, + ), + ) + + # Verify via query banned users + payload = JSON.generate({ filter_conditions: { 'channel_cid' => { '$eq' => cid } } }) + resp = @client.make_request( + :get, + '/api/v2/chat/query_banned_users', + query_params: { 'payload' => payload }, + ) + bans = resp.bans || [] + expect(bans.length).to be >= 1 + + banned_user_ids = bans.map do |b| + + h = b.is_a?(Hash) ? b : b.to_h + target = h['user'] || {} + target = target.to_h unless target.is_a?(Hash) + target['id'] + + end + expect(banned_user_ids).to include(@user_2) + + # Unban user + @client.moderation.unban( + GetStream::Generated::Models::UnbanRequest.new, + @user_2, + cid, + ) + + # Verify ban is removed + payload = JSON.generate({ filter_conditions: { 'channel_cid' => { '$eq' => cid } } }) + resp_2 = @client.make_request( + :get, + '/api/v2/chat/query_banned_users', + query_params: { 'payload' => payload }, + ) + bans_2 = resp_2.bans || [] + banned_ids_after = bans_2.map do |b| + + h = b.is_a?(Hash) ? b : b.to_h + target = h['user'] || {} + target = target.to_h unless target.is_a?(Hash) + target['id'] + + end + expect(banned_ids_after).not_to include(@user_2) + + end + + it 'bans a user app-wide, verifies, and unbans' do + + # Ban user app-wide (no channel_cid) + @client.moderation.ban( + GetStream::Generated::Models::BanRequest.new( + target_user_id: @user_3, + banned_by_id: @user_1, + reason: 'app-wide moderation test ban', + timeout: 60, + ), + ) + + # Verify via query banned users (app-level) + payload = JSON.generate({ filter_conditions: { 'user_id' => { '$eq' => @user_3 } } }) + resp = @client.make_request( + :get, + '/api/v2/chat/query_banned_users', + query_params: { 'payload' => payload }, + ) + bans = resp.bans || [] + expect(bans.length).to be >= 1 + + # Unban user app-wide + @client.moderation.unban( + GetStream::Generated::Models::UnbanRequest.new, + @user_3, + ) + + # Verify ban is removed + payload = JSON.generate({ filter_conditions: { 'user_id' => { '$eq' => @user_3 } } }) + resp_2 = @client.make_request( + :get, + '/api/v2/chat/query_banned_users', + query_params: { 'payload' => payload }, + ) + bans_2 = resp_2.bans || [] + expect(bans_2.length).to eq(0), 'App-wide ban should be removed after unban' + + end + + end + + # --------------------------------------------------------------------------- + # Mute / Unmute User + # --------------------------------------------------------------------------- + + describe 'MuteUnmuteUser' do + + it 'mutes a user, verifies via query, and unmutes' do + + # Mute user + mute_resp = @client.moderation.mute( + GetStream::Generated::Models::MuteRequest.new( + target_ids: [@user_4], + user_id: @user_1, + ), + ) + expect(mute_resp.mutes).not_to be_nil + expect(mute_resp.mutes.length).to be >= 1 + + mute_h = mute_resp.mutes[0].is_a?(Hash) ? mute_resp.mutes[0] : mute_resp.mutes[0].to_h + target = mute_h['target'] || {} + target = target.to_h unless target.is_a?(Hash) + expect(target['id']).to eq(@user_4) + + # Verify via QueryUsers that muter has mutes + q_resp = @client.common.query_users(JSON.generate({ + filter_conditions: { 'id' => { '$eq' => @user_1 } }, + })) + expect(q_resp.users).not_to be_nil + expect(q_resp.users.length).to be >= 1 + user_h = q_resp.users[0].is_a?(Hash) ? q_resp.users[0] : q_resp.users[0].to_h + expect(user_h['mutes']).not_to be_nil + expect(user_h['mutes'].length).to be >= 1 + + muted_ids = user_h['mutes'].map do |m| + + t = m.is_a?(Hash) ? m : m.to_h + tgt = t['target'] || {} + tgt = tgt.to_h unless tgt.is_a?(Hash) + tgt['id'] + + end + expect(muted_ids).to include(@user_4) + + # Unmute user + @client.moderation.unmute( + GetStream::Generated::Models::UnmuteRequest.new( + target_ids: [@user_4], + user_id: @user_1, + ), + ) + + # Verify mute is removed + q_resp_2 = @client.common.query_users(JSON.generate({ + filter_conditions: { 'id' => { '$eq' => @user_1 } }, + })) + user_h_2 = q_resp_2.users[0].is_a?(Hash) ? q_resp_2.users[0] : q_resp_2.users[0].to_h + mutes_after = user_h_2['mutes'] || [] + muted_ids_after = mutes_after.map do |m| + + t = m.is_a?(Hash) ? m : m.to_h + tgt = t['target'] || {} + tgt = tgt.to_h unless tgt.is_a?(Hash) + tgt['id'] + + end + expect(muted_ids_after).not_to include(@user_4) + + end + + end + + # --------------------------------------------------------------------------- + # Flag Message and User + # --------------------------------------------------------------------------- + + describe 'FlagMessageAndUser' do + + it 'flags a message and verifies response' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1, @user_2]) + msg_id = send_test_message('messaging', channel_id, @user_1, "Flaggable message #{SecureRandom.hex(4)}") + + # Flag message + flag_resp = @client.moderation.flag( + GetStream::Generated::Models::FlagRequest.new( + entity_type: 'stream:chat:v1:message', + entity_id: msg_id, + entity_creator_id: @user_1, + reason: 'inappropriate content', + user_id: @user_2, + ), + ) + expect(flag_resp).not_to be_nil + + end + + it 'flags a user and verifies response' do + + # Flag user + flag_resp = @client.moderation.flag( + GetStream::Generated::Models::FlagRequest.new( + entity_type: 'stream:user', + entity_id: @user_3, + entity_creator_id: @user_3, + reason: 'spam behavior', + user_id: @user_1, + ), + ) + expect(flag_resp).not_to be_nil + + end + + end + +end diff --git a/spec/integration/chat_polls_integration_spec.rb b/spec/integration/chat_polls_integration_spec.rb new file mode 100644 index 0000000..c41b388 --- /dev/null +++ b/spec/integration/chat_polls_integration_spec.rb @@ -0,0 +1,189 @@ +# frozen_string_literal: true + +require 'rspec' +require 'securerandom' +require 'json' +require_relative 'chat_test_helpers' + +RSpec.describe 'Chat Polls Integration', type: :integration do + + include ChatTestHelpers + + before(:all) do + + init_chat_client + @shared_user_ids, _resp = create_test_users(2) + @user_1 = @shared_user_ids[0] + @user_2 = @shared_user_ids[1] + @created_poll_ids = [] + + end + + after(:all) do + + # Delete polls before channels/users (polls reference users) + @created_poll_ids&.each do |poll_id| + + @client.common.delete_poll(poll_id, @user_1) + rescue StandardError => e + puts "Warning: Failed to delete poll #{poll_id}: #{e.message}" + + end + + cleanup_chat_resources + + end + + # --------------------------------------------------------------------------- + # Poll API wrappers + # --------------------------------------------------------------------------- + + def create_poll(name, user_id, options: [], enforce_unique_vote: nil, description: nil) + poll_options = options.map do |text| + + GetStream::Generated::Models::PollOptionInput.new(text: text) + + end + + req = GetStream::Generated::Models::CreatePollRequest.new( + name: name, + user_id: user_id, + options: poll_options, + enforce_unique_vote: enforce_unique_vote, + description: description, + ) + + resp = @client.common.create_poll(req) + poll_id = resp.poll.id + @created_poll_ids << poll_id + resp + end + + def get_poll(poll_id) + @client.common.get_poll(poll_id) + end + + def query_polls(filter, user_id) + req = GetStream::Generated::Models::QueryPollsRequest.new(filter: filter) + @client.common.query_polls(req, user_id) + end + + def delete_poll(poll_id, user_id) + @client.common.delete_poll(poll_id, user_id) + end + + def cast_poll_vote(message_id, poll_id, user_id, option_id) + body = { + user_id: user_id, + vote: { option_id: option_id }, + } + @client.make_request( + :post, + "/api/v2/chat/messages/#{message_id}/polls/#{poll_id}/vote", + body: body, + ) + end + + # --------------------------------------------------------------------------- + # Tests + # --------------------------------------------------------------------------- + + describe 'CreateAndQueryPoll' do + + it 'creates a poll with options, gets it, and queries it' do + + poll_name = "Favorite color? #{SecureRandom.hex(4)}" + + # Create poll with options + create_resp = create_poll( + poll_name, + @user_1, + options: %w[Red Blue Green], + enforce_unique_vote: true, + description: 'Pick your favorite color', + ) + expect(create_resp.poll).not_to be_nil + poll_id = create_resp.poll.id + expect(poll_id).not_to be_nil + expect(create_resp.poll.name).to eq(poll_name) + expect(create_resp.poll.enforce_unique_vote).to eq(true) + + poll_h = create_resp.poll.to_h + expect(poll_h['options'].length).to eq(3) + + # Get poll by ID + get_resp = get_poll(poll_id) + expect(get_resp.poll).not_to be_nil + expect(get_resp.poll.id).to eq(poll_id) + expect(get_resp.poll.name).to eq(poll_name) + + # Query polls with filter + query_resp = query_polls({ 'id' => poll_id }, @user_1) + expect(query_resp.polls).not_to be_nil + expect(query_resp.polls.length).to be >= 1 + + found = query_resp.polls.any? do |p| + + h = p.is_a?(Hash) ? p : p.to_h + h['id'] == poll_id + + end + expect(found).to be true + rescue StandardError => e + skip('Polls not enabled for this app') if e.message.include?('Polls') || e.message.include?('polls') + raise + + end + + end + + describe 'CastPollVote' do + + it 'creates a poll, attaches to message, casts vote, and verifies' do + + # Create poll + poll_name = "Vote test #{SecureRandom.hex(4)}" + create_resp = create_poll( + poll_name, + @user_1, + options: %w[Yes No], + enforce_unique_vote: true, + ) + poll_id = create_resp.poll.id + poll_h = create_resp.poll.to_h + option_id = poll_h['options'][0]['id'] + expect(option_id).not_to be_nil + + # Create channel with both users as members + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1, @user_2]) + + # Send message with poll attached + body = { + message: { + text: 'Please vote!', + user_id: @user_1, + poll_id: poll_id, + }, + } + msg_resp = send_message('messaging', channel_id, body) + msg_id = msg_resp.message.id + expect(msg_id).not_to be_nil + + # Cast a vote as user2 + vote_resp = cast_poll_vote(msg_id, poll_id, @user_2, option_id) + expect(vote_resp.vote).not_to be_nil + vote_h = vote_resp.vote.to_h + expect(vote_h['option_id']).to eq(option_id) + + # Verify poll has votes + get_resp = get_poll(poll_id) + expect(get_resp.poll.vote_count).to eq(1) + rescue StandardError => e + skip('Polls not enabled for this app') if e.message.include?('Polls') || e.message.include?('polls') + raise + + end + + end + +end diff --git a/spec/integration/chat_reaction_integration_spec.rb b/spec/integration/chat_reaction_integration_spec.rb new file mode 100644 index 0000000..d24db9a --- /dev/null +++ b/spec/integration/chat_reaction_integration_spec.rb @@ -0,0 +1,137 @@ +# frozen_string_literal: true + +require 'rspec' +require 'securerandom' +require 'json' +require_relative 'chat_test_helpers' + +RSpec.describe 'Chat Reaction Integration', type: :integration do + + include ChatTestHelpers + + before(:all) do + + init_chat_client + @shared_user_ids, _resp = create_test_users(2) + @user_1 = @shared_user_ids[0] + @user_2 = @shared_user_ids[1] + + end + + after(:all) do + + cleanup_chat_resources + + end + + # --------------------------------------------------------------------------- + # Reaction API wrappers + # --------------------------------------------------------------------------- + + def send_reaction(message_id, reaction_type, user_id, enforce_unique: false) + body = { + reaction: { type: reaction_type, user_id: user_id }, + } + body[:enforce_unique] = true if enforce_unique + @client.make_request(:post, "/api/v2/chat/messages/#{message_id}/reaction", body: body) + end + + def get_reactions(message_id) + @client.make_request(:get, "/api/v2/chat/messages/#{message_id}/reactions") + end + + def delete_reaction(message_id, reaction_type, user_id) + @client.make_request( + :delete, + "/api/v2/chat/messages/#{message_id}/reaction/#{reaction_type}", + query_params: { 'user_id' => user_id }, + ) + end + + # --------------------------------------------------------------------------- + # Tests + # --------------------------------------------------------------------------- + + describe 'SendAndGetReactions' do + + it 'sends reactions and gets them back' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1, @user_2]) + msg_id = send_test_message('messaging', channel_id, @user_1, "React to this #{SecureRandom.hex(8)}") + + # Send two reactions from different users + resp_1 = send_reaction(msg_id, 'like', @user_1) + expect(resp_1.reaction).not_to be_nil + expect(resp_1.reaction.to_h['type']).to eq('like') + expect(resp_1.reaction.to_h['user_id']).to eq(@user_1) + + resp_2 = send_reaction(msg_id, 'love', @user_2) + expect(resp_2.reaction).not_to be_nil + expect(resp_2.reaction.to_h['type']).to eq('love') + expect(resp_2.reaction.to_h['user_id']).to eq(@user_2) + + # Get reactions + get_resp = get_reactions(msg_id) + expect(get_resp.reactions).not_to be_nil + expect(get_resp.reactions.length).to be >= 2 + + end + + end + + describe 'DeleteReaction' do + + it 'sends a reaction, deletes it, and verifies removal' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + msg_id = send_test_message('messaging', channel_id, @user_1, "Delete reaction test #{SecureRandom.hex(8)}") + + # Send reaction + send_reaction(msg_id, 'like', @user_1) + + # Delete reaction + del_resp = delete_reaction(msg_id, 'like', @user_1) + expect(del_resp).not_to be_nil + + # Verify reaction is gone + get_resp = get_reactions(msg_id) + user_likes = (get_resp.reactions || []).select do |r| + + h = r.is_a?(Hash) ? r : r.to_h + h['user_id'] == @user_1 && h['type'] == 'like' + + end + expect(user_likes.length).to eq(0) + + end + + end + + describe 'EnforceUniqueReaction' do + + it 'enforces only one reaction per user when enforce_unique is set' do + + _type, channel_id, _resp = create_test_channel_with_members(@user_1, [@user_1]) + msg_id = send_test_message('messaging', channel_id, @user_1, "Unique reaction test #{SecureRandom.hex(8)}") + + # Send first reaction with enforce_unique + send_reaction(msg_id, 'like', @user_1, enforce_unique: true) + + # Send second reaction with enforce_unique โ€” should replace, not duplicate + send_reaction(msg_id, 'love', @user_1, enforce_unique: true) + + # Verify user has only one reaction + get_resp = get_reactions(msg_id) + user_reactions = (get_resp.reactions || []).select do |r| + + h = r.is_a?(Hash) ? r : r.to_h + h['user_id'] == @user_1 + + end + expect(user_reactions.length).to eq(1) + + end + + end + +end diff --git a/spec/integration/chat_test_helpers.rb b/spec/integration/chat_test_helpers.rb new file mode 100644 index 0000000..79b151d --- /dev/null +++ b/spec/integration/chat_test_helpers.rb @@ -0,0 +1,188 @@ +# frozen_string_literal: true + +require 'securerandom' +require 'json' +require 'dotenv' +require_relative '../../lib/getstream_ruby' +require_relative 'suite_cleanup' + +# Shared helpers for chat integration tests. +# Include this module in RSpec describe blocks and call `init_chat_client` +# in a before(:all) hook. +module ChatTestHelpers + + # --------------------------------------------------------------------------- + # Setup / teardown + # --------------------------------------------------------------------------- + + def init_chat_client + Dotenv.load('.env') if File.exist?('.env') + @client = GetStreamRuby.client + @created_user_ids = [] + @created_channel_cids = [] + end + + def retry_on_rate_limit(max_attempts: 3) + attempts = 0 + begin + yield + rescue GetStreamRuby::APIError => e + raise unless e.message.include?('Too many requests') + + attempts += 1 + raise if attempts >= max_attempts + + wait = 61 - Time.now.sec + puts "โณ Rate-limited, waiting #{wait}s for window reset (attempt #{attempts}/#{max_attempts})..." + sleep(wait) + retry + end + end + + def cleanup_chat_resources + # Delete channels (they reference users and must be removed per-spec). + @created_channel_cids&.each do |cid| + + type, id = cid.split(':', 2) + retry_on_rate_limit do + + @client.make_request( + :delete, + "/api/v2/chat/channels/#{type}/#{id}", + query_params: { 'hard_delete' => 'true' }, + ) + + end + rescue StandardError => e + puts "Warning: Failed to delete channel #{cid}: #{e.message}" + + end + + # Register users for deferred deletion at suite end. + # The delete_users endpoint is rate-limited; batching all user deletes into + # a single after(:suite) call (in suite_cleanup.rb) keeps the quota free + # for the DeleteUsers integration test that runs during the suite. + SuiteCleanup.register_users(@created_user_ids) + end + + # --------------------------------------------------------------------------- + # Helper 1: random_string + # --------------------------------------------------------------------------- + + def random_string(length = 8) + SecureRandom.alphanumeric(length) + end + + # --------------------------------------------------------------------------- + # Helper 2: create_test_users + # --------------------------------------------------------------------------- + + def create_test_users(count) + ids = Array.new(count) { "test-user-#{SecureRandom.uuid}" } + users = {} + ids.each do |id| + + users[id] = GetStream::Generated::Models::UserRequest.new( + id: id, + name: "Test User #{id[0..7]}", + role: 'user', + ) + + end + + response = @client.common.update_users( + GetStream::Generated::Models::UpdateUsersRequest.new(users: users), + ) + @created_user_ids.concat(ids) + [ids, response] + end + + # --------------------------------------------------------------------------- + # Helper 3: create_test_channel + # --------------------------------------------------------------------------- + + def create_test_channel(creator_id) + channel_id = "test-ch-#{SecureRandom.hex(6)}" + body = { data: { created_by_id: creator_id } } + response = @client.make_request( + :post, + "/api/v2/chat/channels/messaging/#{channel_id}/query", + body: body, + ) + @created_channel_cids << "messaging:#{channel_id}" + ['messaging', channel_id, response] + end + + # --------------------------------------------------------------------------- + # Helper 4: create_test_channel_with_members + # --------------------------------------------------------------------------- + + def create_test_channel_with_members(creator_id, member_ids) + channel_id = "test-ch-#{SecureRandom.hex(6)}" + members = member_ids.map { |id| { user_id: id } } + body = { data: { created_by_id: creator_id, members: members } } + response = @client.make_request( + :post, + "/api/v2/chat/channels/messaging/#{channel_id}/query", + body: body, + ) + @created_channel_cids << "messaging:#{channel_id}" + ['messaging', channel_id, response] + end + + # --------------------------------------------------------------------------- + # Helper 5: send_test_message + # --------------------------------------------------------------------------- + + def send_test_message(channel_type, channel_id, user_id, text) + body = { message: { text: text, user_id: user_id } } + resp = @client.make_request( + :post, + "/api/v2/chat/channels/#{channel_type}/#{channel_id}/message", + body: body, + ) + resp.message.id + end + + # --------------------------------------------------------------------------- + # Helper 6: wait_for_task + # --------------------------------------------------------------------------- + + def wait_for_task(task_id, max_attempts: 60, interval_seconds: 1) + max_attempts.times do + + result = @client.common.get_task(task_id) + return result if %w[completed failed].include?(result.status) + + sleep(interval_seconds) + + end + raise "Task #{task_id} did not complete after #{max_attempts} attempts" + end + + # --------------------------------------------------------------------------- + # Channel API wrappers (for tests that need direct channel operations) + # --------------------------------------------------------------------------- + + def get_or_create_channel(type, id, body = {}) + @client.make_request(:post, "/api/v2/chat/channels/#{type}/#{id}/query", body: body) + end + + def delete_channel(type, id, hard: false) + query_params = hard ? { 'hard_delete' => 'true' } : {} + retry_on_rate_limit do + + @client.make_request(:delete, "/api/v2/chat/channels/#{type}/#{id}", query_params: query_params) + + end + end + + def query_channels(body) + @client.make_request(:post, '/api/v2/chat/channels', body: body) + end + + def send_message(type, id, body) + @client.make_request(:post, "/api/v2/chat/channels/#{type}/#{id}/message", body: body) + end + +end diff --git a/spec/integration/chat_user_group_integration_spec.rb b/spec/integration/chat_user_group_integration_spec.rb new file mode 100644 index 0000000..e49043a --- /dev/null +++ b/spec/integration/chat_user_group_integration_spec.rb @@ -0,0 +1,288 @@ +# frozen_string_literal: true + +require 'rspec' +require 'securerandom' +require 'json' +require_relative 'chat_test_helpers' + +RSpec.describe 'Chat User Group Integration', type: :integration do + + include ChatTestHelpers + + before(:all) do + + init_chat_client + @created_group_ids = [] + + end + + after(:all) do + + @created_group_ids&.each do |gid| + + @client.common.delete_user_group(gid) + rescue StandardError => e + puts "Warning: Failed to delete user group #{gid}: #{e.message}" + + end + + cleanup_chat_resources + + end + + # --------------------------------------------------------------------------- + # Helper: create a group and track it for cleanup + # --------------------------------------------------------------------------- + + def create_group(id:, name:, description: nil, member_ids: nil) + req = GetStream::Generated::Models::CreateUserGroupRequest.new( + id: id, + name: name, + description: description, + member_ids: member_ids, + ) + resp = @client.common.create_user_group(req) + @created_group_ids << id + resp + rescue GetStreamRuby::APIError => e + skip 'User groups feature not available for this app' if e.message.include?('Not Found') + raise + end + + def delete_group(id) + @client.common.delete_user_group(id) + @created_group_ids.delete(id) + rescue StandardError + @created_group_ids.delete(id) + end + + # --------------------------------------------------------------------------- + # Tests + # --------------------------------------------------------------------------- + + describe 'CreateAndGetUserGroup' do + + it 'creates a group with name and description, then retrieves it by ID' do + + group_id = "test-group-#{SecureRandom.uuid}" + group_name = "Test Group #{group_id[0..14]}" + description = 'A test user group' + + create_resp = create_group(id: group_id, name: group_name, description: description) + expect(create_resp.user_group).not_to be_nil + expect(create_resp.user_group.id).to eq(group_id) + expect(create_resp.user_group.name).to eq(group_name) + expect(create_resp.user_group.description).to eq(description) + + get_resp = @client.common.get_user_group(group_id) + expect(get_resp.user_group).not_to be_nil + expect(get_resp.user_group.id).to eq(group_id) + expect(get_resp.user_group.name).to eq(group_name) + + end + + end + + describe 'CreateUserGroupWithInitialMembers' do + + it 'creates a group with initial member IDs and verifies members are present' do + + user_ids, _resp = create_test_users(2) + group_id = "test-group-#{SecureRandom.uuid}" + + create_resp = create_group(id: group_id, name: "Group With Members #{group_id}", member_ids: user_ids) + expect(create_resp.user_group).not_to be_nil + expect(create_resp.user_group.id).to eq(group_id) + + get_resp = @client.common.get_user_group(group_id) + expect(get_resp.user_group).not_to be_nil + + members = get_resp.user_group.members || [] + found_ids = members.map { |m| m.is_a?(Hash) ? m['user_id'] : m.user_id } + user_ids.each do |uid| + + expect(found_ids).to include(uid) + + end + + end + + end + + describe 'UpdateUserGroup' do + + it 'updates the group name and description, then confirms via GET' do + + group_id = "test-group-#{SecureRandom.uuid}" + create_group(id: group_id, name: "Original Name #{group_id}") + + new_name = "Updated Name #{group_id}" + new_desc = 'Updated description' + update_resp = @client.common.update_user_group( + group_id, + GetStream::Generated::Models::UpdateUserGroupRequest.new( + name: new_name, + description: new_desc, + ), + ) + expect(update_resp.user_group).not_to be_nil + expect(update_resp.user_group.name).to eq(new_name) + expect(update_resp.user_group.description).to eq(new_desc) + + get_resp = @client.common.get_user_group(group_id) + expect(get_resp.user_group).not_to be_nil + expect(get_resp.user_group.name).to eq(new_name) + + end + + end + + describe 'ListUserGroups' do + + it 'lists groups and at least one created group appears' do + + group_id_a = "test-group-#{SecureRandom.uuid}" + group_id_b = "test-group-#{SecureRandom.uuid}" + create_group(id: group_id_a, name: "List Test Group One #{group_id_a}") + create_group(id: group_id_b, name: "List Test Group Two #{group_id_b}") + + list_resp = @client.common.list_user_groups + expect(list_resp.user_groups).not_to be_nil + expect(list_resp.user_groups).not_to be_empty + + found_ids = list_resp.user_groups.map { |g| g.is_a?(Hash) ? g['id'] : g.id } + expect(found_ids).to include(group_id_a).or include(group_id_b) + + end + + end + + describe 'ListUserGroupsWithLimit' do + + it 'respects the limit parameter' do + + group_ids = Array.new(3) { "test-group-#{SecureRandom.uuid}" } + group_ids.each_with_index do |gid, _i| + + create_group(id: gid, name: "Limit Test Group #{gid}") + + end + + limit = 2 + list_resp = @client.common.list_user_groups(limit) + expect(list_resp.user_groups).not_to be_nil + expect(list_resp.user_groups.length).to be <= limit + + end + + end + + describe 'SearchUserGroups' do + + it 'finds a group by name prefix search' do + + unique_prefix = "SearchTest-#{SecureRandom.hex(4)}" + group_id = "test-group-#{SecureRandom.uuid}" + create_group(id: group_id, name: "#{unique_prefix} Group") + + search_resp = @client.common.search_user_groups(unique_prefix) + expect(search_resp.user_groups).not_to be_nil + + found = search_resp.user_groups.any? do |g| + + name = g.is_a?(Hash) ? g['name'] : g.name + name.to_s.start_with?(unique_prefix) + + end + expect(found).to be true + + end + + end + + describe 'AddUserGroupMembers' do + + it 'adds members to an existing group and verifies all are present' do + + user_ids, _resp = create_test_users(3) + group_id = "test-group-#{SecureRandom.uuid}" + + # Create with first member only + create_group(id: group_id, name: "Member Management Group #{group_id}", member_ids: user_ids[0, 1]) + + # Add remaining members + add_resp = @client.common.add_user_group_members( + group_id, + GetStream::Generated::Models::AddUserGroupMembersRequest.new( + member_ids: user_ids[1..], + ), + ) + expect(add_resp.user_group).not_to be_nil + + # Verify all members are present + get_resp = @client.common.get_user_group(group_id) + expect(get_resp.user_group).not_to be_nil + + members = get_resp.user_group.members || [] + found_ids = members.map { |m| m.is_a?(Hash) ? m['user_id'] : m.user_id } + user_ids.each do |uid| + + expect(found_ids).to include(uid) + + end + + end + + end + + describe 'RemoveUserGroupMembers' do + + # TODO(yun): unskip once backend is redeployed with POST /members/delete route + it 'removes all members from a group and verifies it is empty' do + + skip 'Skipped: backend needs redeployment for new POST /members/delete endpoint' + + user_ids, _resp = create_test_users(2) + group_id = "test-group-#{SecureRandom.uuid}" + + # Create group with members + create_group(id: group_id, name: "Remove Members Group #{group_id}", member_ids: user_ids) + + # Verify members are present before removal + get_resp = @client.common.get_user_group(group_id) + expect(get_resp.user_group.members.length).to eq(user_ids.length) + + # Remove all members explicitly by ID (backend requires member_ids) + @client.common.remove_user_group_members( + group_id, + GetStream::Generated::Models::RemoveUserGroupMembersRequest.new( + member_ids: user_ids, + ), + ) + + # Verify members are removed + get_resp_after = @client.common.get_user_group(group_id) + expect(get_resp_after.user_group).not_to be_nil + members_after = get_resp_after.user_group.members + expect(members_after).to satisfy('be nil or empty') { |m| m.nil? || m.empty? } + + end + + end + + describe 'DeleteUserGroup' do + + it 'deletes a group and verifies a subsequent GET returns an error' do + + group_id = "test-group-#{SecureRandom.uuid}" + create_group(id: group_id, name: "Group To Delete #{group_id}") + + delete_group(group_id) + + expect { @client.common.get_user_group(group_id) }.to raise_error(StandardError) + + end + + end + +end diff --git a/spec/integration/chat_user_integration_spec.rb b/spec/integration/chat_user_integration_spec.rb new file mode 100644 index 0000000..7d3aeae --- /dev/null +++ b/spec/integration/chat_user_integration_spec.rb @@ -0,0 +1,563 @@ +# frozen_string_literal: true + +require 'rspec' +require 'securerandom' +require 'json' +require_relative 'chat_test_helpers' + +RSpec.describe 'Chat User Integration', type: :integration do + + include ChatTestHelpers + + before(:all) do + + init_chat_client + + end + + after(:all) do + + cleanup_chat_resources + + end + + # Helper to query users with a filter + def query_users_with_filter(filter, **opts) + payload = { 'filter_conditions' => filter } + payload['limit'] = opts[:limit] if opts[:limit] + payload['offset'] = opts[:offset] if opts[:offset] + payload['include_deactivated_users'] = opts[:include_deactivated_users] if opts.key?(:include_deactivated_users) + payload['sort'] = opts[:sort] if opts[:sort] + @client.common.query_users(JSON.generate(payload)) + end + + describe 'UpsertUsers' do + + it 'creates 2 users and verifies both in response' do + + user_ids, response = create_test_users(2) + + expect(response).to be_a(GetStreamRuby::StreamResponse) + expect(user_ids.length).to eq(2) + + users_hash = response.users + expect(users_hash).not_to be_nil + user_ids.each do |uid| + + expect(users_hash.to_h.key?(uid)).to be true + + end + + end + + end + + describe 'QueryUsers' do + + it 'queries users with $in filter and verifies found' do + + user_ids, _resp = create_test_users(2) + + resp = query_users_with_filter({ 'id' => { '$in' => user_ids } }) + expect(resp.users).not_to be_nil + expect(resp.users.length).to be >= 2 + + returned_ids = resp.users.map { |u| u.to_h['id'] || u.id } + user_ids.each do |uid| + + expect(returned_ids).to include(uid) + + end + + end + + end + + describe 'QueryUsersWithOffsetLimit' do + + it 'queries with offset=1 limit=2 and verifies exactly 2 returned' do + + user_ids, _resp = create_test_users(3) + + resp = query_users_with_filter( + { 'id' => { '$in' => user_ids } }, + offset: 1, + limit: 2, + sort: [{ 'field' => 'id', 'direction' => 1 }], + ) + expect(resp.users).not_to be_nil + expect(resp.users.length).to eq(2) + + end + + end + + describe 'PartialUpdateUser' do + + it 'sets custom fields then unsets one' do + + user_ids, _resp = create_test_users(1) + uid = user_ids.first + + # Set country and role + @client.common.update_users_partial( + GetStream::Generated::Models::UpdateUsersPartialRequest.new( + users: [ + GetStream::Generated::Models::UpdateUserPartialRequest.new( + id: uid, + set: { 'country' => 'NL', 'role' => 'admin' }, + ), + ], + ), + ) + + # Verify set + resp = query_users_with_filter({ 'id' => uid }) + user = resp.users.first + user_h = user.to_h + # Custom fields may be at top-level or under 'custom' + country = user_h['custom'].is_a?(Hash) ? user_h['custom']['country'] : user_h['country'] + expect(country).to eq('NL') + + # Unset country + @client.common.update_users_partial( + GetStream::Generated::Models::UpdateUsersPartialRequest.new( + users: [ + GetStream::Generated::Models::UpdateUserPartialRequest.new( + id: uid, + unset: ['country'], + ), + ], + ), + ) + + # Verify unset + resp_2 = query_users_with_filter({ 'id' => uid }) + user_2 = resp_2.users.first + user_2_hash = user_2.to_h + country_2 = user_2_hash['custom'].is_a?(Hash) ? user_2_hash['custom']['country'] : user_2_hash['country'] + expect(country_2).to be_nil + + end + + end + + describe 'BlockUnblockUser' do + + it 'blocks user, verifies in blocked list, unblocks, verifies removed' do + + user_ids, _resp = create_test_users(2) + blocker_id = user_ids[0] + blocked_id = user_ids[1] + + # Block + @client.common.block_users( + GetStream::Generated::Models::BlockUsersRequest.new( + blocked_user_id: blocked_id, + user_id: blocker_id, + ), + ) + + # Verify blocked + blocked_resp = @client.common.get_blocked_users(blocker_id) + expect(blocked_resp.blocks).not_to be_nil + blocked_user_ids = blocked_resp.blocks.map { |b| b.to_h['blocked_user_id'] || b.blocked_user_id } + expect(blocked_user_ids).to include(blocked_id) + + # Unblock + @client.common.unblock_users( + GetStream::Generated::Models::UnblockUsersRequest.new( + blocked_user_id: blocked_id, + user_id: blocker_id, + ), + ) + + # Verify unblocked + blocked_resp_2 = @client.common.get_blocked_users(blocker_id) + blocked_user_ids_2 = (blocked_resp_2.blocks || []).map { |b| b.to_h['blocked_user_id'] || b.blocked_user_id } + expect(blocked_user_ids_2).not_to include(blocked_id) + + end + + end + + describe 'DeactivateReactivateUser' do + + it 'deactivates then reactivates a user' do + + user_ids, _resp = create_test_users(1) + uid = user_ids.first + + # Deactivate + @client.common.deactivate_user( + uid, + GetStream::Generated::Models::DeactivateUserRequest.new, + ) + + # Reactivate + @client.common.reactivate_user( + uid, + GetStream::Generated::Models::ReactivateUserRequest.new, + ) + + # Verify active by querying + resp = query_users_with_filter({ 'id' => uid }) + expect(resp.users.length).to eq(1) + + end + + end + + describe 'DeleteUsers' do + + it 'deletes 2 users and polls task until completed' do + + user_ids, _resp = create_test_users(2) + + resp = nil + 3.times do + + resp = @client.common.delete_users( + GetStream::Generated::Models::DeleteUsersRequest.new( + user_ids: user_ids, + user: 'hard', + messages: 'hard', + conversations: 'hard', + ), + ) + # Remove from tracked list only after a successful call so that a + # rate-limit failure on a prior attempt still leaves them registered + # for suite cleanup. + user_ids.each { |uid| @created_user_ids.delete(uid) } + break + rescue GetStreamRuby::APIError => e + raise unless e.message.include?('Too many requests') + + wait = 61 - Time.now.sec + sleep(wait) + + end + + expect(resp).not_to be_nil + task_id = resp.task_id + expect(task_id).not_to be_nil + + result = wait_for_task(task_id) + expect(result.status).to eq('completed') + + end + + end + + describe 'ExportUser' do + + it 'exports a user and verifies response not nil' do + + user_ids, _resp = create_test_users(1) + uid = user_ids.first + + resp = @client.common.export_user(uid) + expect(resp).not_to be_nil + + end + + end + + describe 'CreateGuest' do + + it 'creates guest and verifies access token' do + + guest_id = "test-guest-#{SecureRandom.uuid}" + + resp = @client.common.create_guest( + GetStream::Generated::Models::CreateGuestRequest.new( + user: GetStream::Generated::Models::UserRequest.new( + id: guest_id, + name: 'Test Guest', + ), + ), + ) + + expect(resp.access_token).not_to be_nil + expect(resp.access_token).not_to be_empty + + # Clean up the guest user + @created_user_ids << guest_id + rescue GetStreamRuby::APIError => e + skip('Guest access not enabled') if e.message.downcase.include?('guest') + raise + + end + + end + + describe 'UpsertUsersWithRoleAndTeamsRole' do + + it 'creates user with role=admin, teams, and teams_role' do + + uid = "test-user-#{SecureRandom.uuid}" + @created_user_ids << uid + + @client.common.update_users( + GetStream::Generated::Models::UpdateUsersRequest.new( + users: { + uid => GetStream::Generated::Models::UserRequest.new( + id: uid, + name: "Admin User #{uid[0..7]}", + role: 'admin', + teams: ['blue'], + teams_role: { 'blue' => 'admin' }, + ), + }, + ), + ) + + resp = query_users_with_filter({ 'id' => uid }) + user = resp.users.first + user_h = user.to_h + expect(user_h['role']).to eq('admin') + expect(user_h['teams']).to include('blue') + expect(user_h['teams_role']).to eq({ 'blue' => 'admin' }) + + end + + end + + describe 'PartialUpdateUserWithTeam' do + + it 'partial updates to add teams and teams_role' do + + user_ids, _resp = create_test_users(1) + uid = user_ids.first + + @client.common.update_users_partial( + GetStream::Generated::Models::UpdateUsersPartialRequest.new( + users: [ + GetStream::Generated::Models::UpdateUserPartialRequest.new( + id: uid, + set: { + 'teams' => ['blue'], + 'teams_role' => { 'blue' => 'admin' }, + }, + ), + ], + ), + ) + + resp = query_users_with_filter({ 'id' => uid }) + user = resp.users.first + user_h = user.to_h + expect(user_h['teams']).to include('blue') + expect(user_h['teams_role']).to eq({ 'blue' => 'admin' }) + + end + + end + + describe 'UpdatePrivacySettings' do + + it 'sets typing_indicators disabled then sets both typing + read_receipts' do + + uid = "test-user-#{SecureRandom.uuid}" + @created_user_ids << uid + + # Create user with typing_indicators disabled + @client.common.update_users( + GetStream::Generated::Models::UpdateUsersRequest.new( + users: { + uid => GetStream::Generated::Models::UserRequest.new( + id: uid, + name: "Privacy User #{uid[0..7]}", + privacy_settings: GetStream::Generated::Models::PrivacySettingsResponse.new( + typing_indicators: GetStream::Generated::Models::TypingIndicatorsResponse.new(enabled: false), + ), + ), + }, + ), + ) + + resp = query_users_with_filter({ 'id' => uid }) + user_h = resp.users.first.to_h + expect(user_h.dig('privacy_settings', 'typing_indicators', 'enabled')).to eq(false) + + # Update both typing_indicators and read_receipts + @client.common.update_users( + GetStream::Generated::Models::UpdateUsersRequest.new( + users: { + uid => GetStream::Generated::Models::UserRequest.new( + id: uid, + privacy_settings: GetStream::Generated::Models::PrivacySettingsResponse.new( + typing_indicators: GetStream::Generated::Models::TypingIndicatorsResponse.new(enabled: true), + read_receipts: GetStream::Generated::Models::ReadReceiptsResponse.new(enabled: false), + ), + ), + }, + ), + ) + + resp_2 = query_users_with_filter({ 'id' => uid }) + user_h_2 = resp_2.users.first.to_h + expect(user_h_2.dig('privacy_settings', 'typing_indicators', 'enabled')).to eq(true) + expect(user_h_2.dig('privacy_settings', 'read_receipts', 'enabled')).to eq(false) + + end + + end + + describe 'PartialUpdatePrivacySettings' do + + it 'partial updates privacy settings incrementally' do + + user_ids, _resp = create_test_users(1) + uid = user_ids.first + + # First: set typing_indicators.enabled = true + @client.common.update_users_partial( + GetStream::Generated::Models::UpdateUsersPartialRequest.new( + users: [ + GetStream::Generated::Models::UpdateUserPartialRequest.new( + id: uid, + set: { + 'privacy_settings' => { + 'typing_indicators' => { 'enabled' => true }, + }, + }, + ), + ], + ), + ) + + resp = query_users_with_filter({ 'id' => uid }) + user_h = resp.users.first.to_h + expect(user_h.dig('privacy_settings', 'typing_indicators', 'enabled')).to eq(true) + + # Second: set read_receipts.enabled = false + @client.common.update_users_partial( + GetStream::Generated::Models::UpdateUsersPartialRequest.new( + users: [ + GetStream::Generated::Models::UpdateUserPartialRequest.new( + id: uid, + set: { + 'privacy_settings' => { + 'read_receipts' => { 'enabled' => false }, + }, + }, + ), + ], + ), + ) + + resp_2 = query_users_with_filter({ 'id' => uid }) + user_h_2 = resp_2.users.first.to_h + expect(user_h_2.dig('privacy_settings', 'read_receipts', 'enabled')).to eq(false) + + end + + end + + describe 'QueryUsersWithDeactivated' do + + it 'deactivates one user, queries without/with include_deactivated' do + + user_ids, _resp = create_test_users(3) + deactivated_id = user_ids.first + + # Deactivate one user + @client.common.deactivate_user( + deactivated_id, + GetStream::Generated::Models::DeactivateUserRequest.new, + ) + + # Query WITHOUT include_deactivated_users โ€” expect 2 + resp = query_users_with_filter({ 'id' => { '$in' => user_ids } }) + expect(resp.users.length).to eq(2) + + # Query WITH include_deactivated_users โ€” expect 3 + resp_2 = query_users_with_filter( + { 'id' => { '$in' => user_ids } }, + include_deactivated_users: true, + ) + expect(resp_2.users.length).to eq(3) + + # Reactivate for cleanup + @client.common.reactivate_user( + deactivated_id, + GetStream::Generated::Models::ReactivateUserRequest.new, + ) + + end + + end + + describe 'DeactivateUsersPlural' do + + it 'deactivates multiple users at once via async task' do + + user_ids, _resp = create_test_users(2) + + resp = @client.common.deactivate_users( + GetStream::Generated::Models::DeactivateUsersRequest.new( + user_ids: user_ids, + ), + ) + + task_id = resp.task_id + expect(task_id).not_to be_nil + + result = wait_for_task(task_id) + expect(result.status).to eq('completed') + + # Verify deactivated users don't appear in default query + query_resp = query_users_with_filter({ 'id' => { '$in' => user_ids } }) + expect(query_resp.users.length).to eq(0) + + # Reactivate for cleanup + user_ids.each do |uid| + + @client.common.reactivate_user(uid, GetStream::Generated::Models::ReactivateUserRequest.new) + + end + + end + + end + + describe 'UserCustomData' do + + it 'creates user with custom fields and verifies persistence' do + + uid = "test-user-#{SecureRandom.uuid}" + @created_user_ids << uid + + custom_data = { + 'favorite_color' => 'blue', + 'age' => 30, + 'tags' => %w[vip early_adopter], + } + + resp = @client.common.update_users( + GetStream::Generated::Models::UpdateUsersRequest.new( + users: { + uid => GetStream::Generated::Models::UserRequest.new( + id: uid, + name: "Custom User #{uid[0..7]}", + custom: custom_data, + ), + }, + ), + ) + + # Verify in upsert response + users_hash = resp.users.to_h + expect(users_hash).to have_key(uid) + + # Verify via query + query_resp = query_users_with_filter({ 'id' => uid }) + user_h = query_resp.users.first.to_h + expect(user_h['custom']['favorite_color'] || user_h['favorite_color']).to eq('blue') + + end + + end + +end diff --git a/spec/integration/feed_integration_spec.rb b/spec/integration/feed_integration_spec.rb index 05b2ea0..897b6a3 100644 --- a/spec/integration/feed_integration_spec.rb +++ b/spec/integration/feed_integration_spec.rb @@ -310,20 +310,8 @@ expect(response).to be_a(GetStreamRuby::StreamResponse) puts "โœ… Created/updated users in batch: #{user_id_1}, #{user_id_2}" # snippet-stop: UpdateUsers - - # Wait for backend propagation - test_helper.wait_for_backend_propagation(1) ensure - # Cleanup created users - begin - delete_request = GetStream::Generated::Models::DeleteUsersRequest.new( - user_ids: [user_id_1, user_id_2], - user: 'hard', - ) - client.common.delete_users(delete_request) - rescue StandardError => e - puts "โš ๏ธ Cleanup error: #{e.message}" - end + SuiteCleanup.register_users([user_id_1, user_id_2]) end end @@ -346,7 +334,6 @@ }, ) client.common.update_users(create_request) - test_helper.wait_for_backend_propagation(1) # snippet-start: UpdateUsersPartial # Partially update user @@ -366,16 +353,7 @@ puts "โœ… Partially updated user: #{user_id}" # snippet-stop: UpdateUsersPartial ensure - # Cleanup - begin - delete_request = GetStream::Generated::Models::DeleteUsersRequest.new( - user_ids: [user_id], - user: 'hard', - ) - client.common.delete_users(delete_request) - rescue StandardError => e - puts "โš ๏ธ Cleanup error: #{e.message}" - end + SuiteCleanup.register_users([user_id]) end end @@ -406,32 +384,43 @@ create_request = GetStream::Generated::Models::UpdateUsersRequest.new(users: users_hash) client.common.update_users(create_request) - test_helper.wait_for_backend_propagation(1) # snippet-start: DeleteUsers - # Delete users in batch - delete_request = GetStream::Generated::Models::DeleteUsersRequest.new( - user_ids: user_ids, - user: 'hard', - ) + # Delete users in batch. + # delete_users is rate-limited to 6 req/min on a fixed 1-minute clock + # window. Rejected 429 calls still increment the counter, so arbitrary + # backoff makes recovery harder. On a 429, sleep until the next minute + # boundary (at most 61s) to guarantee a fresh window before retrying. + response = nil + last_error = nil + 3.times do + + last_error = nil + response = client.common.delete_users( + GetStream::Generated::Models::DeleteUsersRequest.new( + user_ids: user_ids, + user: 'hard', + ), + ) + break + rescue GetStreamRuby::APIError => e + raise unless e.message.include?('Too many requests') + + last_error = e + sleep(61 - Time.now.sec) + + end + + raise last_error if last_error - response = client.common.delete_users(delete_request) + expect(response).not_to be_nil expect(response).to be_a(GetStreamRuby::StreamResponse) puts "โœ… Deleted #{user_ids.length} users in batch" # snippet-stop: DeleteUsers - rescue StandardError => e - puts "โš ๏ธ Error: #{e.message}" - # Try cleanup anyway - begin - delete_request = GetStream::Generated::Models::DeleteUsersRequest.new( - user_ids: user_ids, - user: 'hard', - ) - client.common.delete_users(delete_request) - rescue StandardError - # Ignore cleanup errors - end - raise e + ensure + # Register for suite cleanup. If delete_users already succeeded above, + # the suite cleanup attempt on these IDs is a harmless no-op. + SuiteCleanup.register_users(user_ids) end end @@ -649,7 +638,7 @@ puts 'โœ… Pinned activity successfully' # Unpin activity - unpin_response = client.feeds.unpin_activity(feed_group_id, feed_id, activity_id, test_user_id_1) + unpin_response = client.feeds.unpin_activity(feed_group_id, feed_id, activity_id, nil, test_user_id_1) expect(unpin_response).to be_a(GetStreamRuby::StreamResponse) puts 'โœ… Unpinned activity successfully' @@ -832,30 +821,57 @@ puts "\n๐Ÿ“ค Testing file upload..." - # Get the path to the test file (in the same directory as the spec) - test_file_path = File.join(__dir__, 'upload-test.png') - raise "Test file not found: #{test_file_path}" unless File.exist?(test_file_path) - - # Create file upload request - file_upload_request = GetStream::Generated::Models::FileUploadRequest.new( - file: test_file_path, - user: GetStream::Generated::Models::OnlyUserID.new(id: test_user_id_1), + # Save original file upload config and clear restrictions + app_resp = client.common.get_app + original_config = app_resp.app.file_upload_config + client.common.update_app( + GetStream::Generated::Models::UpdateAppRequest.new( + file_upload_config: GetStream::Generated::Models::FileUploadConfig.new( + allowed_file_extensions: [], + blocked_file_extensions: [], + allowed_mime_types: [], + blocked_mime_types: [], + ), + ), ) + sleep 2 - # Upload the file - upload_response = client.common.upload_file(file_upload_request) + # Create a temporary text file + require 'tempfile' + tmpfile = Tempfile.new(['feed-upload-test-', '.txt']) + tmpfile.write('hello world test file content from Ruby SDK') + tmpfile.close - expect(upload_response).to be_a(GetStreamRuby::StreamResponse) - expect(upload_response.file).not_to be_nil - expect(upload_response.file).to be_a(String) - expect(upload_response.file).not_to be_empty + begin + # Create file upload request + file_upload_request = GetStream::Generated::Models::FileUploadRequest.new( + file: tmpfile.path, + user: GetStream::Generated::Models::OnlyUserID.new(id: test_user_id_1), + ) + + # Upload the file + upload_response = client.common.upload_file(file_upload_request) - puts 'โœ… File uploaded successfully' - puts " File URL: #{upload_response.file}" - puts " Thumbnail URL: #{upload_response.thumb_url}" if upload_response.thumb_url + expect(upload_response).to be_a(GetStreamRuby::StreamResponse) + expect(upload_response.file).not_to be_nil + expect(upload_response.file).to be_a(String) + expect(upload_response.file).not_to be_empty - # Verify the URL is a valid URL - expect(upload_response.file).to match(/^https?:\/\//) + puts 'โœ… File uploaded successfully' + puts " File URL: #{upload_response.file}" + puts " Thumbnail URL: #{upload_response.thumb_url}" if upload_response.thumb_url + + # Verify the URL is a valid URL + expect(upload_response.file).to match(/^https?:\/\//) + ensure + tmpfile.unlink + # Restore original file upload config + client.common.update_app( + GetStream::Generated::Models::UpdateAppRequest.new( + file_upload_config: original_config, + ), + ) + end end diff --git a/spec/integration/suite_cleanup.rb b/spec/integration/suite_cleanup.rb new file mode 100644 index 0000000..f4eb796 --- /dev/null +++ b/spec/integration/suite_cleanup.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +require 'dotenv' + +# Global registry that collects test user IDs across all spec files and +# deletes them in a single batched call after the full suite completes. +# +# Why: the delete_users endpoint is rate-limited. Calling it once per spec +# file (8+ calls per run) exhausts the quota and causes the DeleteUsers +# integration test to fail. Batching everything into one call at suite end +# reduces pressure to 1โ€“2 API calls per run and keeps the test data clean. +# +# Usage: +# SuiteCleanup.register_users(user_ids) # call from any spec/helper +# +# The after(:suite) hook below triggers the actual deletion automatically. +module SuiteCleanup + + @user_ids = [] + + class << self + + def register_users(ids) + @user_ids.concat(Array(ids).compact) + end + + def run + return if @user_ids.empty? + + Dotenv.load('.env') if File.exist?('.env') + + # Require the library; it may already be loaded, require is idempotent. + require_relative '../../lib/getstream_ruby' + + # Allow network access in case WebMock disabled it after the last test. + WebMock.allow_net_connect! if defined?(WebMock) + + client = GetStreamRuby.client + uniq_ids = @user_ids.uniq + puts "\n๐Ÿงน Suite cleanup: deleting #{uniq_ids.length} test users..." + + # The delete_users endpoint accepts up to 100 user IDs per request. + uniq_ids.each_slice(100) do |batch| + + 3.times do + + client.common.delete_users( + GetStream::Generated::Models::DeleteUsersRequest.new( + user_ids: batch, + user: 'hard', + messages: 'hard', + conversations: 'hard', + ), + ) + break + rescue GetStreamRuby::APIError => e + raise unless e.message.include?('Too many requests') + + # The Stream backend enforces 6 req/min on a fixed 1-minute clock + # window. Sleep until the next boundary (at most 61s) to guarantee + # a fresh window. Arbitrary backoff risks retrying in the same window. + wait = 61 - Time.now.sec + puts "โณ Rate-limited during suite cleanup, waiting #{wait}s for window reset..." + sleep(wait) + + end + + end + + puts 'โœ… Suite cleanup complete' + end + + end + +end + +RSpec.configure do |config| + + config.after(:suite) do + + SuiteCleanup.run + + end + +end diff --git a/spec/integration/video_client_integration_spec.rb b/spec/integration/video_client_integration_spec.rb new file mode 100644 index 0000000..a58db4c --- /dev/null +++ b/spec/integration/video_client_integration_spec.rb @@ -0,0 +1,377 @@ +# frozen_string_literal: true + +require 'rspec' +require 'securerandom' +require 'json' +require_relative 'video_test_helpers' + +RSpec.describe 'Video Client Integration', type: :integration do + + include VideoTestHelpers + + before(:all) do + + init_video_client + @shared_user_ids, _resp = create_test_users(3) + @user_a = @shared_user_ids[0] + @user_b = @shared_user_ids[1] + @user_c = @shared_user_ids[2] + + end + + after(:all) do + + cleanup_video_resources + + end + + # --------------------------------------------------------------------------- + # GetOrCreateCall via generated client + # --------------------------------------------------------------------------- + + describe 'GetOrCreateCall' do + + it 'creates a call using the generated video client' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + resp = @client.video.get_or_create_call( + 'default', call_id, + GetStream::Generated::Models::GetOrCreateCallRequest.new( + data: { + created_by_id: @user_a, + members: [ + { user_id: @user_a }, + { user_id: @user_b }, + ], + }, + ) + ) + expect(resp).not_to be_nil + call_h = resp.to_h + expect(call_h['call']).not_to be_nil + + end + + end + + # --------------------------------------------------------------------------- + # GetCall via generated client + # --------------------------------------------------------------------------- + + describe 'GetCall' do + + it 'retrieves a call using the generated video client' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + @client.video.get_or_create_call( + 'default', call_id, + GetStream::Generated::Models::GetOrCreateCallRequest.new( + data: { created_by_id: @user_a }, + ) + ) + + resp = @client.video.get_call('default', call_id) + call_h = resp.to_h + expect(call_h['call']).not_to be_nil + + end + + end + + # --------------------------------------------------------------------------- + # UpdateCall via generated client + # --------------------------------------------------------------------------- + + describe 'UpdateCall' do + + it 'updates call settings using the generated video client' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + @client.video.get_or_create_call( + 'default', call_id, + GetStream::Generated::Models::GetOrCreateCallRequest.new( + data: { created_by_id: @user_a }, + ) + ) + + resp = @client.video.update_call( + 'default', call_id, + GetStream::Generated::Models::UpdateCallRequest.new( + settings_override: { + limits: { max_duration_seconds: 3600 }, + }, + ) + ) + call_h = resp.to_h + max_dur = call_h.dig('call', 'settings', 'limits', 'max_duration_seconds') + expect(max_dur).to eq(3600) + + end + + end + + # --------------------------------------------------------------------------- + # BlockUser / UnblockUser via generated client + # --------------------------------------------------------------------------- + + describe 'BlockUnblockUser' do + + it 'blocks and unblocks a user from a call using the generated video client' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + @client.video.get_or_create_call( + 'default', call_id, + GetStream::Generated::Models::GetOrCreateCallRequest.new( + data: { created_by_id: @user_a }, + ) + ) + + # Block user + @client.video.block_user( + 'default', call_id, + GetStream::Generated::Models::BlockUserRequest.new(user_id: @user_b) + ) + + # Verify blocked + resp = @client.video.get_call('default', call_id) + blocked_ids = resp.to_h.dig('call', 'blocked_user_ids') || [] + expect(blocked_ids).to include(@user_b) + + # Unblock user + @client.video.unblock_user( + 'default', call_id, + GetStream::Generated::Models::UnblockUserRequest.new(user_id: @user_b) + ) + + # Verify unblocked (with retry for eventual consistency) + unblocked = false + 5.times do + + sleep(1) + resp_b = @client.video.get_call('default', call_id) + blocked_ids_b = resp_b.to_h.dig('call', 'blocked_user_ids') || [] + unless blocked_ids_b.include?(@user_b) + unblocked = true + break + end + + end + expect(unblocked).to be(true), 'Expected user to be unblocked after unblock call' + + end + + end + + # --------------------------------------------------------------------------- + # SendCallEvent via generated client + # --------------------------------------------------------------------------- + + describe 'SendCallEvent' do + + it 'sends a custom event in a call using the generated video client' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + @client.video.get_or_create_call( + 'default', call_id, + GetStream::Generated::Models::GetOrCreateCallRequest.new( + data: { created_by_id: @user_a }, + ) + ) + + resp = @client.video.send_call_event( + 'default', call_id, + GetStream::Generated::Models::SendCallEventRequest.new( + user_id: @user_a, + custom: { bananas: 'good' }, + ) + ) + expect(resp).not_to be_nil + + end + + end + + # --------------------------------------------------------------------------- + # MuteUsers via generated client + # --------------------------------------------------------------------------- + + describe 'MuteUsers' do + + it 'mutes all users in a call using the generated video client' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + @client.video.get_or_create_call( + 'default', call_id, + GetStream::Generated::Models::GetOrCreateCallRequest.new( + data: { created_by_id: @user_a }, + ) + ) + + resp = @client.video.mute_users( + 'default', call_id, + GetStream::Generated::Models::MuteUsersRequest.new( + muted_by_id: @user_a, + mute_all_users: true, + audio: true, + ) + ) + expect(resp).not_to be_nil + + end + + end + + # --------------------------------------------------------------------------- + # DeleteCall (soft) via generated client + # --------------------------------------------------------------------------- + + describe 'DeleteCall' do + + it 'soft deletes a call using the generated video client' do + + call_id = new_call_id + # Don't track since we're deleting + + @client.video.get_or_create_call( + 'default', call_id, + GetStream::Generated::Models::GetOrCreateCallRequest.new( + data: { created_by_id: @user_a }, + ) + ) + + resp = @client.video.delete_call( + 'default', call_id, + GetStream::Generated::Models::DeleteCallRequest.new + ) + resp_h = resp.to_h + expect(resp_h['call']).not_to be_nil + + end + + end + + # --------------------------------------------------------------------------- + # DeleteCall (hard) via generated client + # --------------------------------------------------------------------------- + + describe 'HardDeleteCall' do + + it 'hard deletes a call using the generated video client' do + + call_id = new_call_id + # Don't track since we're deleting + + @client.video.get_or_create_call( + 'default', call_id, + GetStream::Generated::Models::GetOrCreateCallRequest.new( + data: { created_by_id: @user_a }, + ) + ) + + resp = @client.video.delete_call( + 'default', call_id, + GetStream::Generated::Models::DeleteCallRequest.new(hard: true) + ) + resp_h = resp.to_h + task_id = resp_h['task_id'] + expect(task_id).not_to be_nil + + task_result = wait_for_task(task_id) + expect(task_result.status).to eq('completed') + + end + + end + + # --------------------------------------------------------------------------- + # QueryCalls via generated client + # --------------------------------------------------------------------------- + + describe 'QueryCalls' do + + it 'queries calls using the generated video client' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + @client.video.get_or_create_call( + 'default', call_id, + GetStream::Generated::Models::GetOrCreateCallRequest.new( + data: { created_by_id: @user_a }, + ) + ) + + resp = @client.video.query_calls( + GetStream::Generated::Models::QueryCallsRequest.new( + filter_conditions: { 'id' => call_id }, + ), + ) + resp_h = resp.to_h + expect(resp_h['calls']).not_to be_nil + expect(resp_h['calls'].length).to be >= 1 + + end + + end + + # --------------------------------------------------------------------------- + # ListCallTypes via generated client + # --------------------------------------------------------------------------- + + describe 'ListCallTypes' do + + it 'lists call types using the generated video client' do + + resp = @client.video.list_call_types + resp_h = resp.to_h + expect(resp_h['call_types']).not_to be_nil + expect(resp_h['call_types']).not_to be_empty + + end + + end + + # --------------------------------------------------------------------------- + # GetCallType via generated client + # --------------------------------------------------------------------------- + + describe 'GetCallType' do + + it 'gets the default call type using the generated video client' do + + resp = @client.video.get_call_type('default') + expect(resp.name).to eq('default') + + end + + end + + # --------------------------------------------------------------------------- + # GetEdges via generated client + # --------------------------------------------------------------------------- + + describe 'GetEdges' do + + it 'gets edge servers using the generated video client' do + + resp = @client.video.get_edges + resp_h = resp.to_h + expect(resp_h['edges']).not_to be_nil + + end + + end + +end diff --git a/spec/integration/video_integration_spec.rb b/spec/integration/video_integration_spec.rb new file mode 100644 index 0000000..9f2b101 --- /dev/null +++ b/spec/integration/video_integration_spec.rb @@ -0,0 +1,838 @@ +# frozen_string_literal: true + +require 'rspec' +require 'securerandom' +require 'json' +require_relative 'chat_test_helpers' + +RSpec.describe 'Video Integration', type: :integration do + + include ChatTestHelpers + + before(:all) do + + init_chat_client + @created_call_type_names = [] + @created_call_ids = [] # [call_type, call_id] pairs + @shared_user_ids, _resp = create_test_users(4) + @user_1 = @shared_user_ids[0] + @user_2 = @shared_user_ids[1] + @user_3 = @shared_user_ids[2] + @user_4 = @shared_user_ids[3] + + end + + after(:all) do + + # Clean up calls (soft delete) + @created_call_ids&.each do |call_type, call_id| + + @client.make_request( + :post, + "/api/v2/video/call/#{call_type}/#{call_id}/delete", + body: {}, + ) + rescue StandardError => e + puts "Warning: Failed to delete call #{call_type}:#{call_id}: #{e.message}" + + end + + # Clean up call types + @created_call_type_names&.each do |name| + + @client.make_request(:delete, "/api/v2/video/calltypes/#{name}") + rescue StandardError => e + puts "Warning: Failed to delete call type #{name}: #{e.message}" + + end + + cleanup_chat_resources + + end + + # --------------------------------------------------------------------------- + # Helpers + # --------------------------------------------------------------------------- + + def create_call(call_type, call_id, body = {}) + @client.make_request(:post, "/api/v2/video/call/#{call_type}/#{call_id}", body: body) + end + + def get_call(call_type, call_id) + @client.make_request(:get, "/api/v2/video/call/#{call_type}/#{call_id}") + end + + def update_call(call_type, call_id, body) + @client.make_request(:patch, "/api/v2/video/call/#{call_type}/#{call_id}", body: body) + end + + def delete_call_req(call_type, call_id, body = {}) + @client.make_request(:post, "/api/v2/video/call/#{call_type}/#{call_id}/delete", body: body) + end + + def new_call_id + "test-call-#{random_string(10)}" + end + + def new_call_type_name + "testct#{random_string(8)}" + end + + # --------------------------------------------------------------------------- + # CRUDCallTypeOperations + # --------------------------------------------------------------------------- + + describe 'CRUDCallTypeOperations' do + + it 'creates a call type with settings, updates, reads, and deletes' do + + ct_name = new_call_type_name + @created_call_type_names << ct_name + + # Create call type + resp = @client.make_request(:post, '/api/v2/video/calltypes', body: { + name: ct_name, + grants: { + 'admin' => %w[send-audio send-video mute-users], + 'user' => %w[send-audio send-video], + }, + settings: { + audio: { default_device: 'speaker', mic_default_on: true }, + screensharing: { access_request_enabled: false, enabled: true }, + }, + notification_settings: { + enabled: true, + call_notification: { + enabled: true, + apns: { title: '{{ user.display_name }} invites you to a call', body: '' }, + }, + session_started: { enabled: false }, + call_live_started: { enabled: false }, + call_ring: { enabled: false }, + }, + }) + expect(resp.name).to eq(ct_name) + + # Poll for eventual consistency + 10.times do + + @client.make_request(:get, "/api/v2/video/calltypes/#{ct_name}") + break + rescue GetStreamRuby::APIError + sleep(1) + + end + + # Update call type settings (with retry for eventual consistency) + resp_2 = nil + 3.times do |i| + + resp_2 = @client.make_request(:put, "/api/v2/video/calltypes/#{ct_name}", body: { + settings: { + audio: { default_device: 'earpiece', mic_default_on: false }, + recording: { mode: 'disabled' }, + backstage: { enabled: true }, + }, + grants: { + 'host' => %w[join-backstage], + }, + }) + break + rescue GetStreamRuby::APIError + raise if i == 2 + + sleep(2) + + end + expect(resp_2).not_to be_nil + + # Read call type (with retry) + resp_3 = nil + 3.times do |i| + + resp_3 = @client.make_request(:get, "/api/v2/video/calltypes/#{ct_name}") + break + rescue GetStreamRuby::APIError + raise if i == 2 + + sleep(2) + + end + expect(resp_3.name).to eq(ct_name) + + # Delete call type (with retry for eventual consistency) + sleep(2) + 5.times do |i| + + @client.make_request(:delete, "/api/v2/video/calltypes/#{ct_name}") + @created_call_type_names.delete(ct_name) + break + rescue GetStreamRuby::APIError + raise if i == 4 + + sleep(2) + + end + + end + + end + + # --------------------------------------------------------------------------- + # CreateCallWithMembers + # --------------------------------------------------------------------------- + + describe 'CreateCallWithMembers' do + + it 'creates a call and adds members' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + resp = create_call('default', call_id, { + data: { + created_by_id: @user_1, + members: [ + { user_id: @user_1 }, + { user_id: @user_2 }, + ], + }, + }) + expect(resp).not_to be_nil + call_h = resp.to_h + expect(call_h['call']).not_to be_nil + + end + + end + + # --------------------------------------------------------------------------- + # BlockUnblockUserFromCalls + # --------------------------------------------------------------------------- + + describe 'BlockUnblockUserFromCalls' do + + it 'blocks a user from a call and unblocks' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + create_call('default', call_id, { + data: { created_by_id: @user_1 }, + }) + + # Block user + @client.make_request( + :post, + "/api/v2/video/call/default/#{call_id}/block", + body: { user_id: @user_2 }, + ) + + # Verify blocked + resp = get_call('default', call_id) + call_h = resp.to_h + blocked_ids = call_h.dig('call', 'blocked_user_ids') || [] + expect(blocked_ids).to include(@user_2) + + # Unblock user + @client.make_request( + :post, + "/api/v2/video/call/default/#{call_id}/unblock", + body: { user_id: @user_2 }, + ) + + # Verify unblocked (with retry for eventual consistency) + unblocked = false + 5.times do + + sleep(1) + resp_2 = get_call('default', call_id) + call_h_2 = resp_2.to_h + blocked_ids_2 = call_h_2.dig('call', 'blocked_user_ids') || [] + unless blocked_ids_2.include?(@user_2) + unblocked = true + break + end + + end + expect(unblocked).to be(true), 'Expected user to be unblocked after unblock call' + + end + + end + + # --------------------------------------------------------------------------- + # SendCustomEvent + # --------------------------------------------------------------------------- + + describe 'SendCustomEvent' do + + it 'sends a custom event in a call' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + create_call('default', call_id, { + data: { created_by_id: @user_1 }, + }) + + resp = @client.make_request( + :post, + "/api/v2/video/call/default/#{call_id}/event", + body: { user_id: @user_1, custom: { bananas: 'good' } }, + ) + expect(resp).not_to be_nil + + end + + end + + # --------------------------------------------------------------------------- + # MuteAll + # --------------------------------------------------------------------------- + + describe 'MuteAll' do + + it 'mutes all users in a call' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + create_call('default', call_id, { + data: { created_by_id: @user_1 }, + }) + + resp = @client.make_request( + :post, + "/api/v2/video/call/default/#{call_id}/mute_users", + body: { + muted_by_id: @user_1, + mute_all_users: true, + audio: true, + }, + ) + expect(resp).not_to be_nil + + end + + end + + # --------------------------------------------------------------------------- + # MuteSomeUsers + # --------------------------------------------------------------------------- + + describe 'MuteSomeUsers' do + + it 'mutes specific users with audio, video, screenshare' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + create_call('default', call_id, { + data: { created_by_id: @user_1 }, + }) + + resp = @client.make_request( + :post, + "/api/v2/video/call/default/#{call_id}/mute_users", + body: { + muted_by_id: @user_1, + user_ids: [@user_2, @user_3], + audio: true, + video: true, + screenshare: true, + screenshare_audio: true, + }, + ) + expect(resp).not_to be_nil + + end + + end + + # --------------------------------------------------------------------------- + # UpdateUserPermissions + # --------------------------------------------------------------------------- + + describe 'UpdateUserPermissions' do + + it 'revokes and grants permissions in a call' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + create_call('default', call_id, { + data: { created_by_id: @user_1 }, + }) + + # Revoke send-audio + resp_1 = @client.make_request( + :post, + "/api/v2/video/call/default/#{call_id}/user_permissions", + body: { + user_id: @user_2, + revoke_permissions: ['send-audio'], + }, + ) + expect(resp_1).not_to be_nil + + # Grant send-audio back + resp_2 = @client.make_request( + :post, + "/api/v2/video/call/default/#{call_id}/user_permissions", + body: { + user_id: @user_2, + grant_permissions: ['send-audio'], + }, + ) + expect(resp_2).not_to be_nil + + end + + end + + # --------------------------------------------------------------------------- + # DeactivateUser (video context: deactivate/reactivate/batch) + # --------------------------------------------------------------------------- + + describe 'DeactivateUser' do + + it 'deactivates, reactivates, and batch deactivates users' do + + user_ids, _resp = create_test_users(2) + alice = user_ids[0] + bob = user_ids[1] + + # Deactivate single user + @client.common.deactivate_user( + alice, + GetStream::Generated::Models::DeactivateUserRequest.new, + ) + + # Reactivate single user + @client.common.reactivate_user( + alice, + GetStream::Generated::Models::ReactivateUserRequest.new, + ) + + # Batch deactivate + resp = @client.common.deactivate_users( + GetStream::Generated::Models::DeactivateUsersRequest.new(user_ids: [alice, bob]), + ) + expect(resp.task_id).not_to be_nil + + task_result = wait_for_task(resp.task_id) + expect(task_result.status).to eq('completed') + + end + + end + + # --------------------------------------------------------------------------- + # CreateCallWithSessionTimer + # --------------------------------------------------------------------------- + + describe 'CreateCallWithSessionTimer' do + + it 'creates a call with max_duration_seconds and updates it' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + resp = create_call('default', call_id, { + data: { + created_by_id: @user_1, + settings_override: { + limits: { max_duration_seconds: 3600 }, + }, + }, + }) + call_h = resp.to_h + max_dur = call_h.dig('call', 'settings', 'limits', 'max_duration_seconds') + expect(max_dur).to eq(3600) + + # Update to 7200 + resp_2 = update_call('default', call_id, { + settings_override: { + limits: { max_duration_seconds: 7200 }, + }, + }) + call_h_2 = resp_2.to_h + max_dur_2 = call_h_2.dig('call', 'settings', 'limits', 'max_duration_seconds') + expect(max_dur_2).to eq(7200) + + # Reset to 0 + resp_3 = update_call('default', call_id, { + settings_override: { + limits: { max_duration_seconds: 0 }, + }, + }) + call_h_3 = resp_3.to_h + max_dur_3 = call_h_3.dig('call', 'settings', 'limits', 'max_duration_seconds') + expect(max_dur_3).to eq(0) + + end + + end + + # --------------------------------------------------------------------------- + # UserBlocking (app-level user block/unblock, not call-level) + # --------------------------------------------------------------------------- + + describe 'UserBlocking' do + + it 'blocks and unblocks a user at app level' do + + user_ids, _resp = create_test_users(2) + alice = user_ids[0] + bob = user_ids[1] + + # Block + @client.common.block_users( + GetStream::Generated::Models::BlockUsersRequest.new( + blocked_user_id: bob, + user_id: alice, + ), + ) + + # Verify blocked + resp = @client.common.get_blocked_users(alice) + blocks = resp.blocks || [] + expect(blocks.length).to be >= 1 + block_h = blocks[0].is_a?(Hash) ? blocks[0] : blocks[0].to_h + expect(block_h['blocked_user_id']).to eq(bob) + + # Unblock + @client.common.unblock_users( + GetStream::Generated::Models::UnblockUsersRequest.new( + blocked_user_id: bob, + user_id: alice, + ), + ) + + # Verify unblocked + resp_2 = @client.common.get_blocked_users(alice) + blocks_2 = resp_2.blocks || [] + blocked_ids = blocks_2.map do |b| + + h = b.is_a?(Hash) ? b : b.to_h + h['blocked_user_id'] + + end + expect(blocked_ids).not_to include(bob) + + end + + end + + # --------------------------------------------------------------------------- + # CreateCallWithBackstageAndJoinAhead + # --------------------------------------------------------------------------- + + describe 'CreateCallWithBackstageAndJoinAhead' do + + it 'creates a call with backstage and join_ahead_time_seconds' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + starts_at = (Time.now.utc + (30 * 60)).strftime('%Y-%m-%dT%H:%M:%S.%NZ') + + resp = create_call('default', call_id, { + data: { + starts_at: starts_at, + created_by_id: @user_1, + settings_override: { + backstage: { enabled: true, join_ahead_time_seconds: 300 }, + }, + }, + }) + call_h = resp.to_h + join_ahead = call_h.dig('call', 'settings', 'backstage', 'join_ahead_time_seconds') + expect(join_ahead).to eq(300) + + # Update to 600 + resp_2 = update_call('default', call_id, { + settings_override: { + backstage: { enabled: true, join_ahead_time_seconds: 600 }, + }, + }) + call_h_2 = resp_2.to_h + join_ahead_2 = call_h_2.dig('call', 'settings', 'backstage', 'join_ahead_time_seconds') + expect(join_ahead_2).to eq(600) + + # Reset to 0 + resp_3 = update_call('default', call_id, { + settings_override: { + backstage: { enabled: true, join_ahead_time_seconds: 0 }, + }, + }) + call_h_3 = resp_3.to_h + join_ahead_3 = call_h_3.dig('call', 'settings', 'backstage', 'join_ahead_time_seconds') + expect(join_ahead_3).to eq(0) + + end + + end + + # --------------------------------------------------------------------------- + # DeleteCall (soft) + # --------------------------------------------------------------------------- + + describe 'DeleteCall (soft)' do + + it 'soft deletes a call and verifies not found' do + + call_id = new_call_id + # Don't add to @created_call_ids since we're deleting it here + + create_call('default', call_id, { + data: { created_by_id: @user_1 }, + }) + + resp = delete_call_req('default', call_id, {}) + resp_h = resp.to_h + expect(resp_h['call']).not_to be_nil + # task_id should be nil for soft delete + expect(resp_h['task_id']).to be_nil + + # Verify not found (with retry for eventual consistency) + found = false + 5.times do + + sleep(1) + begin + get_call('default', call_id) + rescue GetStreamRuby::APIError => e + found = true if e.message.include?("Can't find call with id") + break + end + + end + expect(found).to be(true), 'Expected call to be not found after soft delete' + + end + + end + + # --------------------------------------------------------------------------- + # HardDeleteCall + # --------------------------------------------------------------------------- + + describe 'HardDeleteCall' do + + it 'hard deletes a call with task polling' do + + call_id = new_call_id + # Don't add to @created_call_ids since we're deleting it here + + create_call('default', call_id, { + data: { created_by_id: @user_1 }, + }) + + resp = delete_call_req('default', call_id, { hard: true }) + resp_h = resp.to_h + task_id = resp_h['task_id'] + expect(task_id).not_to be_nil + + task_result = wait_for_task(task_id) + expect(task_result.status).to eq('completed') + + # Verify not found (with retry for eventual consistency) + found = false + 5.times do + + sleep(1) + begin + get_call('default', call_id) + rescue GetStreamRuby::APIError => e + found = true if e.message.include?("Can't find call with id") + break + end + + end + expect(found).to be(true), 'Expected call to be not found after hard delete' + + end + + end + + # --------------------------------------------------------------------------- + # Teams + # --------------------------------------------------------------------------- + + describe 'Teams' do + + it 'creates a user with teams, creates a call with team, queries' do + + team_user_id = "test-user-#{SecureRandom.uuid}" + @created_user_ids << team_user_id + + @client.common.update_users( + GetStream::Generated::Models::UpdateUsersRequest.new( + users: { + team_user_id => GetStream::Generated::Models::UserRequest.new( + id: team_user_id, + name: 'Team User', + role: 'user', + teams: %w[red blue], + ), + }, + ), + ) + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + resp = create_call('default', call_id, { + data: { + created_by_id: team_user_id, + team: 'blue', + }, + }) + call_h = resp.to_h + expect(call_h.dig('call', 'team')).to eq('blue') + + # Query calls by team + query_resp = @client.make_request(:post, '/api/v2/video/calls', body: { + filter_conditions: { + 'id' => call_id, + 'team' => { '$eq' => 'blue' }, + }, + }) + query_h = query_resp.to_h + expect(query_h['calls'].length).to be >= 1 + + end + + end + + # --------------------------------------------------------------------------- + # ExternalStorageOperations + # --------------------------------------------------------------------------- + + describe 'ExternalStorageOperations' do + + it 'creates, lists, and deletes external storage' do + + storage_name = "test-storage-#{random_string(10)}" + + # Create external storage (fake credentials for API contract testing only) + create_resp = @client.make_request(:post, '/api/v2/external_storage', body: { + bucket: 'test-bucket', + name: storage_name, + storage_type: 's3', + path: 'test-directory/', + 'aws_s3' => { + 's3_region' => 'us-east-1', + 's3_api_key' => 'test-access-key', + 's3_secret' => 'test-secret', + }, + }) + expect(create_resp).not_to be_nil + + # Verify via list (with retry for eventual consistency) + found = false + 10.times do + + sleep(1) + list_resp = @client.make_request(:get, '/api/v2/external_storage') + storages_h = list_resp.to_h['external_storages'] || {} + if storages_h.key?(storage_name) + found = true + break + end + + end + expect(found).to be(true), "Expected storage #{storage_name} to appear in list" + + # Delete external storage (with retry for eventual consistency) + 5.times do |i| + + @client.make_request(:delete, "/api/v2/external_storage/#{storage_name}") + break + rescue GetStreamRuby::APIError + raise if i == 4 + + sleep(2) + + end + + end + + end + + # --------------------------------------------------------------------------- + # EnableCallRecordingAndBackstageMode + # --------------------------------------------------------------------------- + + describe 'EnableCallRecordingAndBackstageMode' do + + it 'updates call settings for recording and backstage' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + create_call('default', call_id, { + data: { created_by_id: @user_1 }, + }) + + # Enable recording + resp_1 = update_call('default', call_id, { + settings_override: { + recording: { mode: 'available', audio_only: true }, + }, + }) + call_h_1 = resp_1.to_h + expect(call_h_1.dig('call', 'settings', 'recording', 'mode')).to eq('available') + + # Enable backstage + resp_2 = update_call('default', call_id, { + settings_override: { + backstage: { enabled: true }, + }, + }) + call_h_2 = resp_2.to_h + expect(call_h_2.dig('call', 'settings', 'backstage', 'enabled')).to eq(true) + + end + + end + + # --------------------------------------------------------------------------- + # DeleteRecordingsAndTranscriptions + # --------------------------------------------------------------------------- + + describe 'DeleteRecordingsAndTranscriptions' do + + it 'returns error when deleting non-existent recording' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + create_call('default', call_id, { + data: { created_by_id: @user_1 }, + }) + + url = "/api/v2/video/call/default/#{call_id}/non-existent-session/recordings/non-existent-filename" + expect { @client.make_request(:delete, url) }.to raise_error(GetStreamRuby::APIError) + + end + + it 'returns error when deleting non-existent transcription' do + + call_id = new_call_id + @created_call_ids << ['default', call_id] + + create_call('default', call_id, { + data: { created_by_id: @user_1 }, + }) + + url = "/api/v2/video/call/default/#{call_id}/non-existent-session/transcriptions/non-existent-filename" + expect { @client.make_request(:delete, url) }.to raise_error(GetStreamRuby::APIError) + + end + + end + +end diff --git a/spec/integration/video_test_helpers.rb b/spec/integration/video_test_helpers.rb new file mode 100644 index 0000000..deee45c --- /dev/null +++ b/spec/integration/video_test_helpers.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +require 'securerandom' +require 'json' +require 'dotenv' +require_relative '../../lib/getstream_ruby' +require_relative 'suite_cleanup' + +# Shared helpers for video integration tests. +# Include this module in RSpec describe blocks and call `init_video_client` +# in a before(:all) hook. +module VideoTestHelpers + + # --------------------------------------------------------------------------- + # Setup / teardown + # --------------------------------------------------------------------------- + + def init_video_client + Dotenv.load('.env') if File.exist?('.env') + @client = GetStreamRuby.client + @created_user_ids = [] + @created_call_ids = [] # [call_type, call_id] pairs + @created_call_type_names = [] + end + + def retry_on_rate_limit(max_attempts: 3) + attempts = 0 + begin + yield + rescue GetStreamRuby::APIError => e + raise unless e.message.include?('Too many requests') + + attempts += 1 + raise if attempts >= max_attempts + + wait = 61 - Time.now.sec + puts "Rate limited, waiting #{wait}s for window reset (attempt #{attempts}/#{max_attempts})..." + sleep(wait) + retry + end + end + + def cleanup_video_resources + # Delete calls (soft delete) + @created_call_ids&.each do |call_type, call_id| + + @client.video.delete_call( + call_type, call_id, + GetStream::Generated::Models::DeleteCallRequest.new + ) + rescue StandardError => e + puts "Warning: Failed to delete call #{call_type}:#{call_id}: #{e.message}" + + end + + # Delete call types + @created_call_type_names&.each do |name| + + @client.video.delete_call_type(name) + rescue StandardError => e + puts "Warning: Failed to delete call type #{name}: #{e.message}" + + end + + # Register users for deferred deletion at suite end. + SuiteCleanup.register_users(@created_user_ids) + end + + # --------------------------------------------------------------------------- + # Helpers + # --------------------------------------------------------------------------- + + def random_string(length = 8) + SecureRandom.alphanumeric(length) + end + + def create_test_users(count) + ids = Array.new(count) { "test-user-#{SecureRandom.uuid}" } + users = {} + ids.each do |id| + + users[id] = GetStream::Generated::Models::UserRequest.new( + id: id, + name: "Test User #{id[0..7]}", + role: 'user', + ) + + end + + response = @client.common.update_users( + GetStream::Generated::Models::UpdateUsersRequest.new(users: users), + ) + @created_user_ids.concat(ids) + [ids, response] + end + + def new_call_id + "test-call-#{random_string(10)}" + end + + def new_call_type_name + "testct#{random_string(8)}" + end + + def wait_for_task(task_id, max_attempts: 60, interval_seconds: 1) + max_attempts.times do + + result = @client.common.get_task(task_id) + return result if %w[completed failed].include?(result.status) + + sleep(interval_seconds) + + end + raise "Task #{task_id} did not complete after #{max_attempts} attempts" + end + +end diff --git a/test/webhook_test.rb b/test/webhook_test.rb index 229dc65..b0424fc 100644 --- a/test/webhook_test.rb +++ b/test/webhook_test.rb @@ -596,6 +596,11 @@ def test_parse_feeds_feed_group_deleted assert_equal 'StreamChat::FeedGroupDeletedEvent', event.class.name end + def test_parse_feeds_feed_group_restored + event = StreamChat::Webhook.parse_webhook_event('{"type":"feeds.feed_group.restored"}') + assert_equal 'StreamChat::FeedGroupRestoredEvent', event.class.name + end + def test_parse_feeds_feed_member_added event = StreamChat::Webhook.parse_webhook_event('{"type":"feeds.feed_member.added"}') assert_equal 'StreamChat::FeedMemberAddedEvent', event.class.name @@ -851,6 +856,31 @@ def test_parse_user_updated assert_equal 'StreamChat::UserUpdatedEvent', event.class.name end + def test_parse_user_group_created + event = StreamChat::Webhook.parse_webhook_event('{"type":"user_group.created"}') + assert_equal 'StreamChat::UserGroupCreatedEvent', event.class.name + end + + def test_parse_user_group_deleted + event = StreamChat::Webhook.parse_webhook_event('{"type":"user_group.deleted"}') + assert_equal 'StreamChat::UserGroupDeletedEvent', event.class.name + end + + def test_parse_user_group_member_added + event = StreamChat::Webhook.parse_webhook_event('{"type":"user_group.member_added"}') + assert_equal 'StreamChat::UserGroupMemberAddedEvent', event.class.name + end + + def test_parse_user_group_member_removed + event = StreamChat::Webhook.parse_webhook_event('{"type":"user_group.member_removed"}') + assert_equal 'StreamChat::UserGroupMemberRemovedEvent', event.class.name + end + + def test_parse_user_group_updated + event = StreamChat::Webhook.parse_webhook_event('{"type":"user_group.updated"}') + assert_equal 'StreamChat::UserGroupUpdatedEvent', event.class.name + end + def test_parse_webhook_event_unknown_type assert_raises(ArgumentError) do StreamChat::Webhook.parse_webhook_event('{"type":"unknown.event"}')