Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Conformance fixture suite under `tests/fixtures/webhooks/` (13 happy-path
event directories + 8 negative cases) for SDK conformance testing across
language ports.
- Regenerated from the latest chat OpenAPI spec. New endpoints: `moderation.analyze`,
`moderation.bulk_action_appeals`, `moderation.get_setup_session`,
`moderation.upsert_setup_session`; `feeds.get_or_create_follow`,
`feeds.get_or_create_unfollow`, `feeds.get_user_interests`; `chat.create_segment`,
`chat.update_segment`, `chat.add_segment_targets`; `common.cancel_import_v2_task`;
`video.report_client_call_event`, together with the request/response models backing them.
- New webhook event types `moderation.image_analysis.complete` and
`moderation.text_analysis.complete`, with `ModerationImageAnalysisCompleteEvent`
and `ModerationTextAnalysisCompleteEvent` models.

### Changed

Expand All @@ -82,6 +91,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Default HTTP transport now caps connections per host at `5` and closes idle sockets after `55.0s`. Previous default was httpx's `100` max-connections with `5.0s` keep-alive expiry.
- No breaking changes. All existing webhook helpers (`verify_webhook_signature`,
`parse_webhook_event`, `get_event_type`, event type constants) are preserved.
- `FlagResponse` now represents the full flag record (`created_at`, `updated_at`,
`target_message`, `target_user`, `user`, `reason`, `details`, `custom`, and related
fields). The moderation flag-action acknowledgement, which carries `item_id` and
`duration`, moved to the new `FlagItemResponse`; `moderation.flag()` now returns
`FlagItemResponse`. The `/api/v2/moderation/flag` wire response is unchanged, so code
reading `item_id`/`duration` off the parsed response is unaffected. Code referencing
the `FlagResponse` type for those two fields should switch to `FlagItemResponse`.
- `ChannelInput.config_overrides` and `ChannelDataUpdate.config_overrides` are now typed
as `ChannelConfigOverrides` (the override-specific field set) instead of `ChannelConfig`.
- `enabled` on `DeliveryReceiptsResponse`, `ReadReceiptsResponse`, and
`TypingIndicatorsResponse` is now a required `bool` (was `Optional[bool]`).
- `LLMRule.description`, `TargetResolution.bitrate`, and `TranslationSettings.languages` /
`TranslationSettings.enabled` are now optional.

### Deprecated

Expand Down
63 changes: 62 additions & 1 deletion getstream/chat/async_rest_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,10 +282,11 @@ async def grouped_query_channels(
self,
limit: Optional[int] = None,
user_id: Optional[str] = None,
groups: Optional[Dict[str, GroupedChannelsGroupRequest]] = None,
user: Optional[UserRequest] = None,
) -> StreamResponse[GroupedQueryChannelsResponse]:
json = GroupedQueryChannelsRequest(
limit=limit, user_id=user_id, user=user
limit=limit, user_id=user_id, groups=groups, user=user
).to_dict()
return await self.post(
"/api/v2/chat/channels/grouped", GroupedQueryChannelsResponse, json=json
Expand Down Expand Up @@ -1657,6 +1658,30 @@ async def search(
"/api/v2/chat/search", SearchResponse, query_params=query_params
)

@telemetry.operation_name("getstream.api.chat.create_segment")
async def create_segment(
self,
type: str,
all_sender_channels: Optional[bool] = None,
all_users: Optional[bool] = None,
description: Optional[str] = None,
id: Optional[str] = None,
name: Optional[str] = None,
filter: Optional[Dict[str, object]] = None,
) -> StreamResponse[CreateSegmentResponse]:
json = CreateSegmentRequest(
type=type,
all_sender_channels=all_sender_channels,
all_users=all_users,
description=description,
id=id,
name=name,
filter=filter,
).to_dict()
return await self.post(
"/api/v2/chat/segments", CreateSegmentResponse, json=json
)

@telemetry.operation_name("getstream.api.chat.query_segments")
async def query_segments(
self,
Expand Down Expand Up @@ -1691,6 +1716,42 @@ async def get_segment(self, id: str) -> StreamResponse[GetSegmentResponse]:
"/api/v2/chat/segments/{id}", GetSegmentResponse, path_params=path_params
)

@telemetry.operation_name("getstream.api.chat.update_segment")
async def update_segment(
self,
id: str,
description: Optional[str] = None,
name: Optional[str] = None,
filter: Optional[Dict[str, object]] = None,
) -> StreamResponse[UpdateSegmentResponse]:
path_params = {
"id": id,
}
json = UpdateSegmentRequest(
description=description, name=name, filter=filter
).to_dict()
return await self.put(
"/api/v2/chat/segments/{id}",
UpdateSegmentResponse,
path_params=path_params,
json=json,
)

@telemetry.operation_name("getstream.api.chat.add_segment_targets")
async def add_segment_targets(
self, id: str, target_ids: List[str]
) -> StreamResponse[Response]:
path_params = {
"id": id,
}
json = AddSegmentTargetsRequest(target_ids=target_ids).to_dict()
return await self.post(
"/api/v2/chat/segments/{id}/addtargets",
Response,
path_params=path_params,
json=json,
)

@telemetry.operation_name("getstream.api.chat.delete_segment_targets")
async def delete_segment_targets(
self, id: str, target_ids: List[str]
Expand Down
61 changes: 60 additions & 1 deletion getstream/chat/rest_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,10 +278,11 @@ def grouped_query_channels(
self,
limit: Optional[int] = None,
user_id: Optional[str] = None,
groups: Optional[Dict[str, GroupedChannelsGroupRequest]] = None,
user: Optional[UserRequest] = None,
) -> StreamResponse[GroupedQueryChannelsResponse]:
json = GroupedQueryChannelsRequest(
limit=limit, user_id=user_id, user=user
limit=limit, user_id=user_id, groups=groups, user=user
).to_dict()
return self.post(
"/api/v2/chat/channels/grouped", GroupedQueryChannelsResponse, json=json
Expand Down Expand Up @@ -1643,6 +1644,28 @@ def search(
"/api/v2/chat/search", SearchResponse, query_params=query_params
)

@telemetry.operation_name("getstream.api.chat.create_segment")
def create_segment(
self,
type: str,
all_sender_channels: Optional[bool] = None,
all_users: Optional[bool] = None,
description: Optional[str] = None,
id: Optional[str] = None,
name: Optional[str] = None,
filter: Optional[Dict[str, object]] = None,
) -> StreamResponse[CreateSegmentResponse]:
json = CreateSegmentRequest(
type=type,
all_sender_channels=all_sender_channels,
all_users=all_users,
description=description,
id=id,
name=name,
filter=filter,
).to_dict()
return self.post("/api/v2/chat/segments", CreateSegmentResponse, json=json)

@telemetry.operation_name("getstream.api.chat.query_segments")
def query_segments(
self,
Expand Down Expand Up @@ -1677,6 +1700,42 @@ def get_segment(self, id: str) -> StreamResponse[GetSegmentResponse]:
"/api/v2/chat/segments/{id}", GetSegmentResponse, path_params=path_params
)

@telemetry.operation_name("getstream.api.chat.update_segment")
def update_segment(
self,
id: str,
description: Optional[str] = None,
name: Optional[str] = None,
filter: Optional[Dict[str, object]] = None,
) -> StreamResponse[UpdateSegmentResponse]:
path_params = {
"id": id,
}
json = UpdateSegmentRequest(
description=description, name=name, filter=filter
).to_dict()
return self.put(
"/api/v2/chat/segments/{id}",
UpdateSegmentResponse,
path_params=path_params,
json=json,
)

@telemetry.operation_name("getstream.api.chat.add_segment_targets")
def add_segment_targets(
self, id: str, target_ids: List[str]
) -> StreamResponse[Response]:
path_params = {
"id": id,
}
json = AddSegmentTargetsRequest(target_ids=target_ids).to_dict()
return self.post(
"/api/v2/chat/segments/{id}/addtargets",
Response,
path_params=path_params,
json=json,
)

@telemetry.operation_name("getstream.api.chat.delete_segment_targets")
def delete_segment_targets(
self, id: str, target_ids: List[str]
Expand Down
29 changes: 29 additions & 0 deletions getstream/common/async_rest_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ async def update_app(
self,
async_url_enrich_enabled: Optional[bool] = None,
auto_translation_enabled: Optional[bool] = None,
before_message_send_hook_attempt_timeout_ms: Optional[int] = None,
before_message_send_hook_url: Optional[str] = None,
cdn_expiration_seconds: Optional[int] = None,
channel_hide_members_only: Optional[bool] = None,
Expand All @@ -56,6 +57,7 @@ async def update_app(
migrate_permissions_to_v2: Optional[bool] = None,
moderation_analytics_enabled: Optional[bool] = None,
moderation_enabled: Optional[bool] = None,
moderation_onboarding_complete: Optional[bool] = None,
moderation_s3_image_access_role_arn: Optional[str] = None,
moderation_webhook_url: Optional[str] = None,
multi_tenant_enabled: Optional[bool] = None,
Expand All @@ -70,6 +72,7 @@ async def update_app(
sqs_secret: Optional[str] = None,
sqs_url: Optional[str] = None,
user_response_time_enabled: Optional[bool] = None,
video_primary_use_case: Optional[str] = None,
webhook_url: Optional[str] = None,
allowed_flag_reasons: Optional[List[str]] = None,
event_hooks: Optional[List[EventHook]] = None,
Expand All @@ -95,6 +98,7 @@ async def update_app(
json = UpdateAppRequest(
async_url_enrich_enabled=async_url_enrich_enabled,
auto_translation_enabled=auto_translation_enabled,
before_message_send_hook_attempt_timeout_ms=before_message_send_hook_attempt_timeout_ms,
before_message_send_hook_url=before_message_send_hook_url,
cdn_expiration_seconds=cdn_expiration_seconds,
channel_hide_members_only=channel_hide_members_only,
Expand All @@ -111,6 +115,7 @@ async def update_app(
migrate_permissions_to_v2=migrate_permissions_to_v2,
moderation_analytics_enabled=moderation_analytics_enabled,
moderation_enabled=moderation_enabled,
moderation_onboarding_complete=moderation_onboarding_complete,
moderation_s3_image_access_role_arn=moderation_s3_image_access_role_arn,
moderation_webhook_url=moderation_webhook_url,
multi_tenant_enabled=multi_tenant_enabled,
Expand All @@ -125,6 +130,7 @@ async def update_app(
sqs_secret=sqs_secret,
sqs_url=sqs_url,
user_response_time_enabled=user_response_time_enabled,
video_primary_use_case=video_primary_use_case,
webhook_url=webhook_url,
allowed_flag_reasons=allowed_flag_reasons,
event_hooks=event_hooks,
Expand Down Expand Up @@ -161,16 +167,20 @@ async def create_block_list(
self,
name: str,
words: List[str],
is_confusable_folding_enabled: Optional[bool] = None,
is_leet_check_enabled: Optional[bool] = None,
is_plural_check_enabled: Optional[bool] = None,
is_substring_matching_enabled: Optional[bool] = None,
team: Optional[str] = None,
type: Optional[str] = None,
) -> StreamResponse[CreateBlockListResponse]:
json = CreateBlockListRequest(
name=name,
words=words,
is_confusable_folding_enabled=is_confusable_folding_enabled,
is_leet_check_enabled=is_leet_check_enabled,
is_plural_check_enabled=is_plural_check_enabled,
is_substring_matching_enabled=is_substring_matching_enabled,
team=team,
type=type,
).to_dict()
Expand Down Expand Up @@ -210,17 +220,21 @@ async def get_block_list(
async def update_block_list(
self,
name: str,
is_confusable_folding_enabled: Optional[bool] = None,
is_leet_check_enabled: Optional[bool] = None,
is_plural_check_enabled: Optional[bool] = None,
is_substring_matching_enabled: Optional[bool] = None,
team: Optional[str] = None,
words: Optional[List[str]] = None,
) -> StreamResponse[UpdateBlockListResponse]:
path_params = {
"name": name,
}
json = UpdateBlockListRequest(
is_confusable_folding_enabled=is_confusable_folding_enabled,
is_leet_check_enabled=is_leet_check_enabled,
is_plural_check_enabled=is_plural_check_enabled,
is_substring_matching_enabled=is_substring_matching_enabled,
team=team,
words=words,
).to_dict()
Expand Down Expand Up @@ -304,6 +318,7 @@ async def create_device(
self,
id: str,
push_provider: str,
hardware_id: Optional[str] = None,
push_provider_name: Optional[str] = None,
user_id: Optional[str] = None,
voip_token: Optional[bool] = None,
Expand All @@ -312,6 +327,7 @@ async def create_device(
json = CreateDeviceRequest(
id=id,
push_provider=push_provider,
hardware_id=hardware_id,
push_provider_name=push_provider_name,
user_id=user_id,
voip_token=voip_token,
Expand Down Expand Up @@ -524,6 +540,19 @@ async def get_import_v2_task(
"/api/v2/imports/v2/{id}", GetImportV2TaskResponse, path_params=path_params
)

@telemetry.operation_name("getstream.api.common.cancel_import_v2_task")
async def cancel_import_v2_task(
self, id: str
) -> StreamResponse[CancelImportV2TaskResponse]:
path_params = {
"id": id,
}
return await self.post(
"/api/v2/imports/v2/{id}/cancel",
CancelImportV2TaskResponse,
path_params=path_params,
)

@telemetry.operation_name("getstream.api.common.get_import")
async def get_import(self, id: str) -> StreamResponse[GetImportResponse]:
path_params = {
Expand Down
Loading