diff --git a/getstream/chat/async_rest_client.py b/getstream/chat/async_rest_client.py index 3b5f9cdc..63be0a6c 100644 --- a/getstream/chat/async_rest_client.py +++ b/getstream/chat/async_rest_client.py @@ -113,10 +113,13 @@ async def query_channels( member_limit: Optional[int] = None, message_limit: Optional[int] = None, offset: Optional[int] = None, + predefined_filter: Optional[str] = None, state: Optional[bool] = None, user_id: Optional[str] = None, sort: Optional[List[SortParamRequest]] = None, filter_conditions: Optional[Dict[str, object]] = None, + filter_values: Optional[Dict[str, object]] = None, + sort_values: Optional[Dict[str, object]] = None, user: Optional[UserRequest] = None, ) -> StreamResponse[QueryChannelsResponse]: json = build_body_dict( @@ -124,16 +127,39 @@ async def query_channels( member_limit=member_limit, message_limit=message_limit, offset=offset, + predefined_filter=predefined_filter, state=state, user_id=user_id, sort=sort, filter_conditions=filter_conditions, + filter_values=filter_values, + sort_values=sort_values, user=user, ) return await self.post( "/api/v2/chat/channels", QueryChannelsResponse, json=json ) + @telemetry.operation_name("getstream.api.chat.channel_batch_update") + async def channel_batch_update( + self, + operation: str, + filter: Dict[str, object], + filter_tags_update: Optional[List[str]] = None, + members: Optional[List[ChannelBatchMemberRequest]] = None, + data: Optional[ChannelDataUpdate] = None, + ) -> StreamResponse[ChannelBatchUpdateResponse]: + json = build_body_dict( + operation=operation, + filter=filter, + filter_tags_update=filter_tags_update, + members=members, + data=data, + ) + return await self.put( + "/api/v2/chat/channels/batch", ChannelBatchUpdateResponse, json=json + ) + @telemetry.operation_name("getstream.api.chat.delete_channels") async def delete_channels( self, cids: List[str], hard_delete: Optional[bool] = None @@ -1404,6 +1430,17 @@ async def query_banned_users( query_params=query_params, ) + @telemetry.operation_name("getstream.api.chat.query_future_channel_bans") + async def query_future_channel_bans( + self, payload: Optional[QueryFutureChannelBansPayload] = None + ) -> StreamResponse[QueryFutureChannelBansResponse]: + query_params = build_query_param(payload=payload) + return await self.get( + "/api/v2/chat/query_future_channel_bans", + QueryFutureChannelBansResponse, + query_params=query_params, + ) + @telemetry.operation_name("getstream.api.chat.query_reminders") async def query_reminders( self, diff --git a/getstream/chat/rest_client.py b/getstream/chat/rest_client.py index 7130c897..dbbe3c0e 100644 --- a/getstream/chat/rest_client.py +++ b/getstream/chat/rest_client.py @@ -113,10 +113,13 @@ def query_channels( member_limit: Optional[int] = None, message_limit: Optional[int] = None, offset: Optional[int] = None, + predefined_filter: Optional[str] = None, state: Optional[bool] = None, user_id: Optional[str] = None, sort: Optional[List[SortParamRequest]] = None, filter_conditions: Optional[Dict[str, object]] = None, + filter_values: Optional[Dict[str, object]] = None, + sort_values: Optional[Dict[str, object]] = None, user: Optional[UserRequest] = None, ) -> StreamResponse[QueryChannelsResponse]: json = build_body_dict( @@ -124,14 +127,37 @@ def query_channels( member_limit=member_limit, message_limit=message_limit, offset=offset, + predefined_filter=predefined_filter, state=state, user_id=user_id, sort=sort, filter_conditions=filter_conditions, + filter_values=filter_values, + sort_values=sort_values, user=user, ) return self.post("/api/v2/chat/channels", QueryChannelsResponse, json=json) + @telemetry.operation_name("getstream.api.chat.channel_batch_update") + def channel_batch_update( + self, + operation: str, + filter: Dict[str, object], + filter_tags_update: Optional[List[str]] = None, + members: Optional[List[ChannelBatchMemberRequest]] = None, + data: Optional[ChannelDataUpdate] = None, + ) -> StreamResponse[ChannelBatchUpdateResponse]: + json = build_body_dict( + operation=operation, + filter=filter, + filter_tags_update=filter_tags_update, + members=members, + data=data, + ) + return self.put( + "/api/v2/chat/channels/batch", ChannelBatchUpdateResponse, json=json + ) + @telemetry.operation_name("getstream.api.chat.delete_channels") def delete_channels( self, cids: List[str], hard_delete: Optional[bool] = None @@ -1394,6 +1420,17 @@ def query_banned_users( query_params=query_params, ) + @telemetry.operation_name("getstream.api.chat.query_future_channel_bans") + def query_future_channel_bans( + self, payload: Optional[QueryFutureChannelBansPayload] = None + ) -> StreamResponse[QueryFutureChannelBansResponse]: + query_params = build_query_param(payload=payload) + return self.get( + "/api/v2/chat/query_future_channel_bans", + QueryFutureChannelBansResponse, + query_params=query_params, + ) + @telemetry.operation_name("getstream.api.chat.query_reminders") def query_reminders( self, diff --git a/getstream/feeds/rest_client.py b/getstream/feeds/rest_client.py index 9b43414b..e9dbc9e5 100644 --- a/getstream/feeds/rest_client.py +++ b/getstream/feeds/rest_client.py @@ -36,12 +36,14 @@ def add_activity( self, type: str, feeds: List[str], + create_notification_activity: Optional[bool] = None, expires_at: Optional[str] = None, id: Optional[str] = None, parent_id: Optional[str] = None, poll_id: Optional[str] = None, restrict_replies: Optional[str] = None, skip_enrich_url: Optional[bool] = None, + skip_push: Optional[bool] = None, text: Optional[str] = None, user_id: Optional[str] = None, visibility: Optional[str] = None, @@ -58,12 +60,14 @@ def add_activity( json = build_body_dict( type=type, feeds=feeds, + create_notification_activity=create_notification_activity, expires_at=expires_at, id=id, parent_id=parent_id, poll_id=poll_id, restrict_replies=restrict_replies, skip_enrich_url=skip_enrich_url, + skip_push=skip_push, text=text, user_id=user_id, visibility=visibility, @@ -92,12 +96,17 @@ def upsert_activities( def delete_activities( self, ids: List[str], + delete_notification_activity: Optional[bool] = None, hard_delete: Optional[bool] = None, user_id: Optional[str] = None, user: Optional[UserRequest] = None, ) -> StreamResponse[DeleteActivitiesResponse]: json = build_body_dict( - ids=ids, hard_delete=hard_delete, user_id=user_id, user=user + ids=ids, + delete_notification_activity=delete_notification_activity, + hard_delete=hard_delete, + user_id=user_id, + user=user, ) return self.post( "/api/v2/feeds/activities/delete", DeleteActivitiesResponse, json=json @@ -328,9 +337,15 @@ def query_activity_reactions( @telemetry.operation_name("getstream.api.feeds.delete_activity_reaction") def delete_activity_reaction( - self, activity_id: str, type: str, user_id: Optional[str] = None + self, + activity_id: str, + type: str, + delete_notification_activity: Optional[bool] = None, + user_id: Optional[str] = None, ) -> StreamResponse[DeleteActivityReactionResponse]: - query_params = build_query_param(user_id=user_id) + query_params = build_query_param( + delete_notification_activity=delete_notification_activity, user_id=user_id + ) path_params = { "activity_id": activity_id, "type": type, @@ -344,9 +359,15 @@ def delete_activity_reaction( @telemetry.operation_name("getstream.api.feeds.delete_activity") def delete_activity( - self, id: str, hard_delete: Optional[bool] = None + self, + id: str, + hard_delete: Optional[bool] = None, + delete_notification_activity: Optional[bool] = None, ) -> StreamResponse[DeleteActivityResponse]: - query_params = build_query_param(hard_delete=hard_delete) + query_params = build_query_param( + hard_delete=hard_delete, + delete_notification_activity=delete_notification_activity, + ) path_params = { "id": id, } @@ -372,6 +393,7 @@ def get_activity(self, id: str) -> StreamResponse[GetActivityResponse]: def update_activity_partial( self, id: str, + handle_mention_notifications: Optional[bool] = None, user_id: Optional[str] = None, unset: Optional[List[str]] = None, set: Optional[Dict[str, object]] = None, @@ -380,7 +402,13 @@ def update_activity_partial( path_params = { "id": id, } - json = build_body_dict(user_id=user_id, unset=unset, set=set, user=user) + json = build_body_dict( + handle_mention_notifications=handle_mention_notifications, + user_id=user_id, + unset=unset, + set=set, + user=user, + ) return self.patch( "/api/v2/feeds/activities/{id}", UpdateActivityPartialResponse, @@ -393,12 +421,14 @@ def update_activity( self, id: str, expires_at: Optional[datetime] = None, + handle_mention_notifications: Optional[bool] = None, poll_id: Optional[str] = None, restrict_replies: Optional[str] = None, skip_enrich_url: Optional[bool] = None, text: Optional[str] = None, user_id: Optional[str] = None, visibility: Optional[str] = None, + visibility_tag: Optional[str] = None, attachments: Optional[List[Attachment]] = None, collection_refs: Optional[List[str]] = None, feeds: Optional[List[str]] = None, @@ -414,12 +444,14 @@ def update_activity( } json = build_body_dict( expires_at=expires_at, + handle_mention_notifications=handle_mention_notifications, poll_id=poll_id, restrict_replies=restrict_replies, skip_enrich_url=skip_enrich_url, text=text, user_id=user_id, visibility=visibility, + visibility_tag=visibility_tag, attachments=attachments, collection_refs=collection_refs, feeds=feeds, @@ -437,6 +469,21 @@ def update_activity( json=json, ) + @telemetry.operation_name("getstream.api.feeds.restore_activity") + def restore_activity( + self, id: str, user_id: Optional[str] = None, user: Optional[UserRequest] = None + ) -> StreamResponse[RestoreActivityResponse]: + path_params = { + "id": id, + } + json = build_body_dict(user_id=user_id, user=user) + return self.post( + "/api/v2/feeds/activities/{id}/restore", + RestoreActivityResponse, + path_params=path_params, + json=json, + ) + @telemetry.operation_name("getstream.api.feeds.query_bookmark_folders") def query_bookmark_folders( self, @@ -569,6 +616,7 @@ def get_comments( depth: Optional[int] = None, sort: Optional[str] = None, replies_limit: Optional[int] = None, + user_id: Optional[str] = None, limit: Optional[int] = None, prev: Optional[str] = None, next: Optional[str] = None, @@ -579,6 +627,7 @@ def get_comments( depth=depth, sort=sort, replies_limit=replies_limit, + user_id=user_id, limit=limit, prev=prev, next=next, @@ -648,9 +697,15 @@ def query_comments( @telemetry.operation_name("getstream.api.feeds.delete_comment") def delete_comment( - self, id: str, hard_delete: Optional[bool] = None + self, + id: str, + hard_delete: Optional[bool] = None, + delete_notification_activity: Optional[bool] = None, ) -> StreamResponse[DeleteCommentResponse]: - query_params = build_query_param(hard_delete=hard_delete) + query_params = build_query_param( + hard_delete=hard_delete, + delete_notification_activity=delete_notification_activity, + ) path_params = { "id": id, } @@ -675,10 +730,12 @@ def update_comment( self, id: str, comment: Optional[str] = None, + handle_mention_notifications: Optional[bool] = None, skip_enrich_url: Optional[bool] = None, skip_push: Optional[bool] = None, user_id: Optional[str] = None, attachments: Optional[List[Attachment]] = None, + mentioned_user_ids: Optional[List[str]] = None, custom: Optional[Dict[str, object]] = None, user: Optional[UserRequest] = None, ) -> StreamResponse[UpdateCommentResponse]: @@ -687,10 +744,12 @@ def update_comment( } json = build_body_dict( comment=comment, + handle_mention_notifications=handle_mention_notifications, skip_enrich_url=skip_enrich_url, skip_push=skip_push, user_id=user_id, attachments=attachments, + mentioned_user_ids=mentioned_user_ids, custom=custom, user=user, ) @@ -757,9 +816,15 @@ def query_comment_reactions( @telemetry.operation_name("getstream.api.feeds.delete_comment_reaction") def delete_comment_reaction( - self, id: str, type: str, user_id: Optional[str] = None + self, + id: str, + type: str, + delete_notification_activity: Optional[bool] = None, + user_id: Optional[str] = None, ) -> StreamResponse[DeleteCommentReactionResponse]: - query_params = build_query_param(user_id=user_id) + query_params = build_query_param( + delete_notification_activity=delete_notification_activity, user_id=user_id + ) path_params = { "id": id, "type": type, @@ -778,6 +843,7 @@ def get_comment_replies( depth: Optional[int] = None, sort: Optional[str] = None, replies_limit: Optional[int] = None, + user_id: Optional[str] = None, limit: Optional[int] = None, prev: Optional[str] = None, next: Optional[str] = None, @@ -786,6 +852,7 @@ def get_comment_replies( depth=depth, sort=sort, replies_limit=replies_limit, + user_id=user_id, limit=limit, prev=prev, next=next, @@ -1416,6 +1483,7 @@ def update_follow( follower_role: Optional[str] = None, push_preference: Optional[str] = None, skip_push: Optional[bool] = None, + status: Optional[str] = None, custom: Optional[Dict[str, object]] = None, ) -> StreamResponse[UpdateFollowResponse]: json = build_body_dict( @@ -1425,6 +1493,7 @@ def update_follow( follower_role=follower_role, push_preference=push_preference, skip_push=skip_push, + status=status, custom=custom, ) return self.patch("/api/v2/feeds/follows", UpdateFollowResponse, json=json) @@ -1437,6 +1506,7 @@ def follow( create_notification_activity: Optional[bool] = None, push_preference: Optional[str] = None, skip_push: Optional[bool] = None, + status: Optional[str] = None, custom: Optional[Dict[str, object]] = None, ) -> StreamResponse[SingleFollowResponse]: json = build_body_dict( @@ -1445,6 +1515,7 @@ def follow( create_notification_activity=create_notification_activity, push_preference=push_preference, skip_push=skip_push, + status=status, custom=custom, ) return self.post("/api/v2/feeds/follows", SingleFollowResponse, json=json) @@ -1500,7 +1571,15 @@ def reject_follow( ) @telemetry.operation_name("getstream.api.feeds.unfollow") - def unfollow(self, source: str, target: str) -> StreamResponse[UnfollowResponse]: + def unfollow( + self, + source: str, + target: str, + delete_notification_activity: Optional[bool] = None, + ) -> StreamResponse[UnfollowResponse]: + query_params = build_query_param( + delete_notification_activity=delete_notification_activity + ) path_params = { "source": source, "target": target, @@ -1508,6 +1587,7 @@ def unfollow(self, source: str, target: str) -> StreamResponse[UnfollowResponse] return self.delete( "/api/v2/feeds/follows/{source}/{target}", UnfollowResponse, + query_params=query_params, path_params=path_params, ) @@ -1598,18 +1678,26 @@ def query_feeds_usage_stats( @telemetry.operation_name("getstream.api.feeds.unfollow_batch") def unfollow_batch( - self, follows: List[FollowPair] + self, + follows: List[FollowPair], + delete_notification_activity: Optional[bool] = None, ) -> StreamResponse[UnfollowBatchResponse]: - json = build_body_dict(follows=follows) + json = build_body_dict( + follows=follows, delete_notification_activity=delete_notification_activity + ) return self.post( "/api/v2/feeds/unfollow/batch", UnfollowBatchResponse, json=json ) @telemetry.operation_name("getstream.api.feeds.get_or_create_unfollows") def get_or_create_unfollows( - self, follows: List[FollowPair] + self, + follows: List[FollowPair], + delete_notification_activity: Optional[bool] = None, ) -> StreamResponse[UnfollowBatchResponse]: - json = build_body_dict(follows=follows) + json = build_body_dict( + follows=follows, delete_notification_activity=delete_notification_activity + ) return self.post( "/api/v2/feeds/unfollow/batch/upsert", UnfollowBatchResponse, json=json ) diff --git a/getstream/models/__init__.py b/getstream/models/__init__.py index 2006363c..bde0651d 100644 --- a/getstream/models/__init__.py +++ b/getstream/models/__init__.py @@ -735,6 +735,9 @@ class ActivityRemovedFromFeedEvent(DataClassJsonMixin): class ActivityRequest(DataClassJsonMixin): type: str = dc_field(metadata=dc_config(field_name="type")) feeds: List[str] = dc_field(metadata=dc_config(field_name="feeds")) + create_notification_activity: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="create_notification_activity") + ) expires_at: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="expires_at") ) @@ -751,6 +754,9 @@ class ActivityRequest(DataClassJsonMixin): skip_enrich_url: Optional[bool] = dc_field( default=None, metadata=dc_config(field_name="skip_enrich_url") ) + skip_push: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="skip_push") + ) text: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="text")) user_id: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="user_id") @@ -882,6 +888,9 @@ class ActivityResponse(DataClassJsonMixin): moderation_action: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="moderation_action") ) + selector_source: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="selector_source") + ) text: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="text")) visibility_tag: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="visibility_tag") @@ -906,6 +915,39 @@ class ActivityResponse(DataClassJsonMixin): ) +@dataclass +class ActivityRestoredEvent(DataClassJsonMixin): + created_at: datetime = dc_field( + metadata=dc_config( + field_name="created_at", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ) + ) + fid: str = dc_field(metadata=dc_config(field_name="fid")) + activity: "ActivityResponse" = dc_field(metadata=dc_config(field_name="activity")) + custom: Dict[str, object] = dc_field(metadata=dc_config(field_name="custom")) + type: str = dc_field( + default="feeds.activity.restored", metadata=dc_config(field_name="type") + ) + feed_visibility: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="feed_visibility") + ) + received_at: Optional[datetime] = dc_field( + default=None, + metadata=dc_config( + field_name="received_at", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ), + ) + user: "Optional[UserResponseCommonFields]" = dc_field( + default=None, metadata=dc_config(field_name="user") + ) + + @dataclass class ActivitySelectorConfig(DataClassJsonMixin): type: str = dc_field(metadata=dc_config(field_name="type")) @@ -1030,6 +1072,9 @@ class ActivityUpdatedEvent(DataClassJsonMixin): class AddActivityRequest(DataClassJsonMixin): type: str = dc_field(metadata=dc_config(field_name="type")) feeds: List[str] = dc_field(metadata=dc_config(field_name="feeds")) + create_notification_activity: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="create_notification_activity") + ) expires_at: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="expires_at") ) @@ -1046,6 +1091,9 @@ class AddActivityRequest(DataClassJsonMixin): skip_enrich_url: Optional[bool] = dc_field( default=None, metadata=dc_config(field_name="skip_enrich_url") ) + skip_push: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="skip_push") + ) text: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="text")) user_id: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="user_id") @@ -1086,6 +1134,9 @@ class AddActivityRequest(DataClassJsonMixin): class AddActivityResponse(DataClassJsonMixin): duration: str = dc_field(metadata=dc_config(field_name="duration")) activity: "ActivityResponse" = dc_field(metadata=dc_config(field_name="activity")) + mention_notifications_created: Optional[int] = dc_field( + default=None, metadata=dc_config(field_name="mention_notifications_created") + ) @dataclass @@ -1143,6 +1194,9 @@ class AddCommentReactionResponse(DataClassJsonMixin): reaction: "FeedsReactionResponse" = dc_field( metadata=dc_config(field_name="reaction") ) + notification_created: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="notification_created") + ) @dataclass @@ -1190,6 +1244,12 @@ class AddCommentRequest(DataClassJsonMixin): class AddCommentResponse(DataClassJsonMixin): duration: str = dc_field(metadata=dc_config(field_name="duration")) comment: "CommentResponse" = dc_field(metadata=dc_config(field_name="comment")) + mention_notifications_created: Optional[int] = dc_field( + default=None, metadata=dc_config(field_name="mention_notifications_created") + ) + notification_created: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="notification_created") + ) @dataclass @@ -1245,6 +1305,9 @@ class AddReactionResponse(DataClassJsonMixin): reaction: "FeedsReactionResponse" = dc_field( metadata=dc_config(field_name="reaction") ) + notification_created: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="notification_created") + ) @dataclass @@ -1699,7 +1762,7 @@ class AsyncExportErrorEvent(DataClassJsonMixin): task_id: str = dc_field(metadata=dc_config(field_name="task_id")) custom: Dict[str, object] = dc_field(metadata=dc_config(field_name="custom")) type: str = dc_field( - default="export.users.error", metadata=dc_config(field_name="type") + default="export.channels.error", metadata=dc_config(field_name="type") ) received_at: Optional[datetime] = dc_field( default=None, @@ -3381,6 +3444,9 @@ class CallResponse(DataClassJsonMixin): join_ahead_time_seconds: Optional[int] = dc_field( default=None, metadata=dc_config(field_name="join_ahead_time_seconds") ) + routing_number: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="routing_number") + ) starts_at: Optional[datetime] = dc_field( default=None, metadata=dc_config( @@ -3933,6 +3999,9 @@ class CallStatsParticipantCounts(DataClassJsonMixin): ) publishers: int = dc_field(metadata=dc_config(field_name="publishers")) sessions: int = dc_field(metadata=dc_config(field_name="sessions")) + total_participant_duration: Optional[int] = dc_field( + default=None, metadata=dc_config(field_name="total_participant_duration") + ) @dataclass @@ -4635,6 +4704,14 @@ class ChannelBatchCompletedEvent(DataClassJsonMixin): ) +@dataclass +class ChannelBatchMemberRequest(DataClassJsonMixin): + user_id: str = dc_field(metadata=dc_config(field_name="user_id")) + channel_role: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="channel_role") + ) + + @dataclass class ChannelBatchStartedEvent(DataClassJsonMixin): batch_created_at: datetime = dc_field( @@ -4685,6 +4762,29 @@ class ChannelBatchStartedEvent(DataClassJsonMixin): ) +@dataclass +class ChannelBatchUpdateRequest(DataClassJsonMixin): + operation: str = dc_field(metadata=dc_config(field_name="operation")) + filter: Dict[str, object] = dc_field(metadata=dc_config(field_name="filter")) + filter_tags_update: Optional[List[str]] = dc_field( + default=None, metadata=dc_config(field_name="filter_tags_update") + ) + members: "Optional[List[ChannelBatchMemberRequest]]" = dc_field( + default=None, metadata=dc_config(field_name="members") + ) + data: "Optional[ChannelDataUpdate]" = dc_field( + default=None, metadata=dc_config(field_name="data") + ) + + +@dataclass +class ChannelBatchUpdateResponse(DataClassJsonMixin): + duration: str = dc_field(metadata=dc_config(field_name="duration")) + task_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="task_id") + ) + + @dataclass class ChannelConfig(DataClassJsonMixin): automod: str = dc_field(metadata=dc_config(field_name="automod")) @@ -4855,6 +4955,29 @@ class ChannelCreatedEvent(DataClassJsonMixin): ) +@dataclass +class ChannelDataUpdate(DataClassJsonMixin): + auto_translation_enabled: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="auto_translation_enabled") + ) + auto_translation_language: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="auto_translation_language") + ) + disabled: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="disabled") + ) + frozen: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="frozen") + ) + team: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="team")) + config_overrides: "Optional[ChannelConfig]" = dc_field( + default=None, metadata=dc_config(field_name="config_overrides") + ) + custom: Optional[Dict[str, object]] = dc_field( + default=None, metadata=dc_config(field_name="custom") + ) + + @dataclass class ChannelDeletedEvent(DataClassJsonMixin): channel_id: str = dc_field(metadata=dc_config(field_name="channel_id")) @@ -6378,6 +6501,15 @@ class CommentResponse(DataClassJsonMixin): mm_field=fields.DateTime(format="iso"), ), ) + edited_at: Optional[datetime] = dc_field( + default=None, + metadata=dc_config( + field_name="edited_at", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ), + ) parent_id: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="parent_id") ) @@ -7370,6 +7502,9 @@ class DecayFunctionConfig(DataClassJsonMixin): @dataclass class DeleteActivitiesRequest(DataClassJsonMixin): ids: List[str] = dc_field(metadata=dc_config(field_name="ids")) + delete_notification_activity: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="delete_notification_activity") + ) hard_delete: Optional[bool] = dc_field( default=None, metadata=dc_config(field_name="hard_delete") ) @@ -9577,6 +9712,9 @@ class FollowRequest(DataClassJsonMixin): skip_push: Optional[bool] = dc_field( default=None, metadata=dc_config(field_name="skip_push") ) + status: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="status") + ) custom: Optional[Dict[str, object]] = dc_field( default=None, metadata=dc_config(field_name="custom") ) @@ -9800,6 +9938,39 @@ class FullUserResponse(DataClassJsonMixin): ) +@dataclass +class FutureChannelBanResponse(DataClassJsonMixin): + created_at: datetime = dc_field( + metadata=dc_config( + field_name="created_at", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ) + ) + expires: Optional[datetime] = dc_field( + default=None, + metadata=dc_config( + field_name="expires", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ), + ) + reason: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="reason") + ) + shadow: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="shadow") + ) + banned_by: "Optional[UserResponse]" = dc_field( + default=None, metadata=dc_config(field_name="banned_by") + ) + user: "Optional[UserResponse]" = dc_field( + default=None, metadata=dc_config(field_name="user") + ) + + @dataclass class GeofenceResponse(DataClassJsonMixin): name: str = dc_field(metadata=dc_config(field_name="name")) @@ -9892,6 +10063,41 @@ class GetBlockedUsersResponse(DataClassJsonMixin): ) +@dataclass +class GetCallParticipantSessionMetricsResponse(DataClassJsonMixin): + duration: str = dc_field(metadata=dc_config(field_name="duration")) + is_publisher: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="is_publisher") + ) + is_subscriber: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="is_subscriber") + ) + joined_at: Optional[datetime] = dc_field( + default=None, + metadata=dc_config( + field_name="joined_at", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ), + ) + publisher_type: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="publisher_type") + ) + user_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="user_id") + ) + user_session_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="user_session_id") + ) + published_tracks: "Optional[List[PublishedTrackMetrics]]" = dc_field( + default=None, metadata=dc_config(field_name="published_tracks") + ) + client: "Optional[SessionClient]" = dc_field( + default=None, metadata=dc_config(field_name="client") + ) + + @dataclass class GetCallReportResponse(DataClassJsonMixin): duration: str = dc_field(metadata=dc_config(field_name="duration")) @@ -10887,6 +11093,8 @@ class ImportV2TaskItem(DataClassJsonMixin): @dataclass class ImportV2TaskSettings(DataClassJsonMixin): + mode: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="mode")) + path: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="path")) skip_references_check: Optional[bool] = dc_field( default=None, metadata=dc_config(field_name="skip_references_check") ) @@ -10949,6 +11157,26 @@ class IngressAudioEncodingResponse(DataClassJsonMixin): enable_dtx: bool = dc_field(metadata=dc_config(field_name="enable_dtx")) +@dataclass +class IngressErrorEvent(DataClassJsonMixin): + call_cid: str = dc_field(metadata=dc_config(field_name="call_cid")) + created_at: datetime = dc_field( + metadata=dc_config( + field_name="created_at", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ) + ) + error: str = dc_field(metadata=dc_config(field_name="error")) + ingress_stream_id: str = dc_field( + metadata=dc_config(field_name="ingress_stream_id") + ) + user_id: str = dc_field(metadata=dc_config(field_name="user_id")) + type: str = dc_field(default="ingress.error", metadata=dc_config(field_name="type")) + code: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="code")) + + @dataclass class IngressSettings(DataClassJsonMixin): enabled: bool = dc_field(metadata=dc_config(field_name="enabled")) @@ -11005,6 +11233,56 @@ class IngressSourceResponse(DataClassJsonMixin): width: int = dc_field(metadata=dc_config(field_name="width")) +@dataclass +class IngressStartedEvent(DataClassJsonMixin): + call_cid: str = dc_field(metadata=dc_config(field_name="call_cid")) + created_at: datetime = dc_field( + metadata=dc_config( + field_name="created_at", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ) + ) + ingress_stream_id: str = dc_field( + metadata=dc_config(field_name="ingress_stream_id") + ) + publisher_type: str = dc_field(metadata=dc_config(field_name="publisher_type")) + user_id: str = dc_field(metadata=dc_config(field_name="user_id")) + type: str = dc_field( + default="ingress.started", metadata=dc_config(field_name="type") + ) + client_ip: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="client_ip") + ) + client_name: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="client_name") + ) + version: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="version") + ) + + +@dataclass +class IngressStoppedEvent(DataClassJsonMixin): + call_cid: str = dc_field(metadata=dc_config(field_name="call_cid")) + created_at: datetime = dc_field( + metadata=dc_config( + field_name="created_at", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ) + ) + ingress_stream_id: str = dc_field( + metadata=dc_config(field_name="ingress_stream_id") + ) + user_id: str = dc_field(metadata=dc_config(field_name="user_id")) + type: str = dc_field( + default="ingress.stopped", metadata=dc_config(field_name="type") + ) + + @dataclass class IngressVideoEncodingOptions(DataClassJsonMixin): layers: "List[IngressVideoLayer]" = dc_field( @@ -12703,6 +12981,13 @@ class MetricThreshold(DataClassJsonMixin): ) +@dataclass +class MetricTimeSeries(DataClassJsonMixin): + data_points: "Optional[List[List[float]]]" = dc_field( + default=None, metadata=dc_config(field_name="data_points") + ) + + @dataclass class ModerationActionConfig(DataClassJsonMixin): action: str = dc_field(metadata=dc_config(field_name="action")) @@ -13680,6 +13965,15 @@ class PaginationParams(DataClassJsonMixin): ) +@dataclass +class ParsedPredefinedFilterResponse(DataClassJsonMixin): + name: str = dc_field(metadata=dc_config(field_name="name")) + filter: Dict[str, object] = dc_field(metadata=dc_config(field_name="filter")) + sort: "Optional[List[SortParamRequest]]" = dc_field( + default=None, metadata=dc_config(field_name="sort") + ) + + @dataclass class ParticipantCountByMinuteResponse(DataClassJsonMixin): first: int = dc_field(metadata=dc_config(field_name="first")) @@ -13852,6 +14146,35 @@ class ParticipantSeriesUserStats(DataClassJsonMixin): ) +@dataclass +class ParticipantSessionDetails(DataClassJsonMixin): + publisher_type: str = dc_field(metadata=dc_config(field_name="publisher_type")) + user_id: str = dc_field(metadata=dc_config(field_name="user_id")) + user_session_id: str = dc_field(metadata=dc_config(field_name="user_session_id")) + roles: List[str] = dc_field(metadata=dc_config(field_name="roles")) + duration_in_seconds: Optional[int] = dc_field( + default=None, metadata=dc_config(field_name="duration_in_seconds") + ) + joined_at: Optional[datetime] = dc_field( + default=None, + metadata=dc_config( + field_name="joined_at", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ), + ) + left_at: Optional[datetime] = dc_field( + default=None, + metadata=dc_config( + field_name="left_at", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ), + ) + + @dataclass class PendingMessageEvent(DataClassJsonMixin): created_at: datetime = dc_field( @@ -14316,6 +14639,31 @@ class PublishedTrackFlags(DataClassJsonMixin): video: bool = dc_field(metadata=dc_config(field_name="video")) +@dataclass +class PublishedTrackMetrics(DataClassJsonMixin): + codec: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="codec") + ) + track_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="track_id") + ) + track_type: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="track_type") + ) + warnings: "Optional[List[SessionWarningResponse]]" = dc_field( + default=None, metadata=dc_config(field_name="warnings") + ) + bitrate: "Optional[MetricTimeSeries]" = dc_field( + default=None, metadata=dc_config(field_name="bitrate") + ) + framerate: "Optional[MetricTimeSeries]" = dc_field( + default=None, metadata=dc_config(field_name="framerate") + ) + resolution: "Optional[ResolutionMetricsTimeSeries]" = dc_field( + default=None, metadata=dc_config(field_name="resolution") + ) + + @dataclass class PublisherAllMetrics(DataClassJsonMixin): audio: "Optional[PublisherAudioMetrics]" = dc_field( @@ -14974,6 +15322,28 @@ class QueryCallMembersResponse(DataClassJsonMixin): prev: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="prev")) +@dataclass +class QueryCallParticipantSessionsResponse(DataClassJsonMixin): + call_id: str = dc_field(metadata=dc_config(field_name="call_id")) + call_session_id: str = dc_field(metadata=dc_config(field_name="call_session_id")) + call_type: str = dc_field(metadata=dc_config(field_name="call_type")) + duration: int = dc_field(metadata=dc_config(field_name="duration")) + total_participant_duration: int = dc_field( + metadata=dc_config(field_name="total_participant_duration") + ) + total_participant_sessions: int = dc_field( + metadata=dc_config(field_name="total_participant_sessions") + ) + participants_sessions: "List[ParticipantSessionDetails]" = dc_field( + metadata=dc_config(field_name="participants_sessions") + ) + next: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="next")) + prev: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="prev")) + session: "Optional[CallSessionResponse]" = dc_field( + default=None, metadata=dc_config(field_name="session") + ) + + @dataclass class QueryCallParticipantsRequest(DataClassJsonMixin): filter_conditions: Optional[Dict[str, object]] = dc_field( @@ -15207,6 +15577,9 @@ class QueryChannelsRequest(DataClassJsonMixin): offset: Optional[int] = dc_field( default=None, metadata=dc_config(field_name="offset") ) + predefined_filter: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="predefined_filter") + ) state: Optional[bool] = dc_field( default=None, metadata=dc_config(field_name="state") ) @@ -15219,6 +15592,12 @@ class QueryChannelsRequest(DataClassJsonMixin): filter_conditions: Optional[Dict[str, object]] = dc_field( default=None, metadata=dc_config(field_name="filter_conditions") ) + filter_values: Optional[Dict[str, object]] = dc_field( + default=None, metadata=dc_config(field_name="filter_values") + ) + sort_values: Optional[Dict[str, object]] = dc_field( + default=None, metadata=dc_config(field_name="sort_values") + ) user: "Optional[UserRequest]" = dc_field( default=None, metadata=dc_config(field_name="user") ) @@ -15230,6 +15609,9 @@ class QueryChannelsResponse(DataClassJsonMixin): channels: "List[ChannelStateResponseFields]" = dc_field( metadata=dc_config(field_name="channels") ) + predefined_filter: "Optional[ParsedPredefinedFilterResponse]" = dc_field( + default=None, metadata=dc_config(field_name="predefined_filter") + ) @dataclass @@ -15436,6 +15818,36 @@ class QueryFollowsResponse(DataClassJsonMixin): prev: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="prev")) +@dataclass +class QueryFutureChannelBansPayload(DataClassJsonMixin): + exclude_expired_bans: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="exclude_expired_bans") + ) + limit: Optional[int] = dc_field( + default=None, metadata=dc_config(field_name="limit") + ) + offset: Optional[int] = dc_field( + default=None, metadata=dc_config(field_name="offset") + ) + target_user_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="target_user_id") + ) + user_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="user_id") + ) + user: "Optional[UserRequest]" = dc_field( + default=None, metadata=dc_config(field_name="user") + ) + + +@dataclass +class QueryFutureChannelBansResponse(DataClassJsonMixin): + duration: str = dc_field(metadata=dc_config(field_name="duration")) + bans: "List[FutureChannelBanResponse]" = dc_field( + metadata=dc_config(field_name="bans") + ) + + @dataclass class QueryMembersPayload(DataClassJsonMixin): type: str = dc_field(metadata=dc_config(field_name="type")) @@ -16620,6 +17032,16 @@ class ReportResponse(DataClassJsonMixin): ) +@dataclass +class ResolutionMetricsTimeSeries(DataClassJsonMixin): + height: "Optional[MetricTimeSeries]" = dc_field( + default=None, metadata=dc_config(field_name="height") + ) + width: "Optional[MetricTimeSeries]" = dc_field( + default=None, metadata=dc_config(field_name="width") + ) + + @dataclass class ResolveSipInboundRequest(DataClassJsonMixin): sip_caller_number: str = dc_field( @@ -16627,6 +17049,9 @@ class ResolveSipInboundRequest(DataClassJsonMixin): ) sip_trunk_number: str = dc_field(metadata=dc_config(field_name="sip_trunk_number")) challenge: "SIPChallenge" = dc_field(metadata=dc_config(field_name="challenge")) + routing_number: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="routing_number") + ) sip_headers: "Optional[Dict[str, str]]" = dc_field( default=None, metadata=dc_config(field_name="sip_headers") ) @@ -16658,6 +17083,22 @@ class RestoreActionRequest(DataClassJsonMixin): ) +@dataclass +class RestoreActivityRequest(DataClassJsonMixin): + user_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="user_id") + ) + user: "Optional[UserRequest]" = dc_field( + default=None, metadata=dc_config(field_name="user") + ) + + +@dataclass +class RestoreActivityResponse(DataClassJsonMixin): + duration: str = dc_field(metadata=dc_config(field_name="duration")) + activity: "ActivityResponse" = dc_field(metadata=dc_config(field_name="activity")) + + @dataclass class RestoreUsersRequest(DataClassJsonMixin): user_ids: List[str] = dc_field(metadata=dc_config(field_name="user_ids")) @@ -17784,6 +18225,21 @@ class SendUserCustomEventRequest(DataClassJsonMixin): event: "UserCustomEventRequest" = dc_field(metadata=dc_config(field_name="event")) +@dataclass +class SessionClient(DataClassJsonMixin): + ip: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="ip")) + name: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="name")) + network_type: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="network_type") + ) + version: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="version") + ) + location: "Optional[CallStatsLocation]" = dc_field( + default=None, metadata=dc_config(field_name="location") + ) + + @dataclass class SessionSettings(DataClassJsonMixin): inactivity_timeout_seconds: int = dc_field( @@ -17805,6 +18261,21 @@ class SessionSettingsResponse(DataClassJsonMixin): ) +@dataclass +class SessionWarningResponse(DataClassJsonMixin): + code: str = dc_field(metadata=dc_config(field_name="code")) + warning: str = dc_field(metadata=dc_config(field_name="warning")) + time: Optional[datetime] = dc_field( + default=None, + metadata=dc_config( + field_name="time", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ), + ) + + @dataclass class ShadowBlockActionRequest(DataClassJsonMixin): reason: Optional[str] = dc_field( @@ -17944,6 +18415,9 @@ class ShowChannelResponse(DataClassJsonMixin): class SingleFollowResponse(DataClassJsonMixin): duration: str = dc_field(metadata=dc_config(field_name="duration")) follow: "FollowResponse" = dc_field(metadata=dc_config(field_name="follow")) + notification_created: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="notification_created") + ) @dataclass @@ -18722,6 +19196,15 @@ class ThreadedCommentResponse(DataClassJsonMixin): mm_field=fields.DateTime(format="iso"), ), ) + edited_at: Optional[datetime] = dc_field( + default=None, + metadata=dc_config( + field_name="edited_at", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ), + ) parent_id: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="parent_id") ) @@ -18984,6 +19467,9 @@ class UnblockedUserEvent(DataClassJsonMixin): @dataclass class UnfollowBatchRequest(DataClassJsonMixin): follows: "List[FollowPair]" = dc_field(metadata=dc_config(field_name="follows")) + delete_notification_activity: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="delete_notification_activity") + ) @dataclass @@ -19129,6 +19615,9 @@ class UnreadCountsThread(DataClassJsonMixin): @dataclass class UpdateActivityPartialRequest(DataClassJsonMixin): + handle_mention_notifications: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="handle_mention_notifications") + ) user_id: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="user_id") ) @@ -19160,6 +19649,9 @@ class UpdateActivityRequest(DataClassJsonMixin): mm_field=fields.DateTime(format="iso"), ), ) + handle_mention_notifications: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="handle_mention_notifications") + ) poll_id: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="poll_id") ) @@ -19176,6 +19668,9 @@ class UpdateActivityRequest(DataClassJsonMixin): visibility: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="visibility") ) + visibility_tag: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="visibility_tag") + ) attachments: "Optional[List[Attachment]]" = dc_field( default=None, metadata=dc_config(field_name="attachments") ) @@ -19864,6 +20359,9 @@ class UpdateCommentRequest(DataClassJsonMixin): comment: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="comment") ) + handle_mention_notifications: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="handle_mention_notifications") + ) skip_enrich_url: Optional[bool] = dc_field( default=None, metadata=dc_config(field_name="skip_enrich_url") ) @@ -19876,6 +20374,9 @@ class UpdateCommentRequest(DataClassJsonMixin): attachments: "Optional[List[Attachment]]" = dc_field( default=None, metadata=dc_config(field_name="attachments") ) + mentioned_user_ids: Optional[List[str]] = dc_field( + default=None, metadata=dc_config(field_name="mentioned_user_ids") + ) custom: Optional[Dict[str, object]] = dc_field( default=None, metadata=dc_config(field_name="custom") ) @@ -20050,6 +20551,9 @@ class UpdateFollowRequest(DataClassJsonMixin): skip_push: Optional[bool] = dc_field( default=None, metadata=dc_config(field_name="skip_push") ) + status: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="status") + ) custom: Optional[Dict[str, object]] = dc_field( default=None, metadata=dc_config(field_name="custom") ) @@ -20471,6 +20975,9 @@ class UpsertActivitiesResponse(DataClassJsonMixin): activities: "List[ActivityResponse]" = dc_field( metadata=dc_config(field_name="activities") ) + mention_notifications_created: Optional[int] = dc_field( + default=None, metadata=dc_config(field_name="mention_notifications_created") + ) @dataclass diff --git a/getstream/video/async_call.py b/getstream/video/async_call.py index 2fe0b7ea..ec7fd972 100644 --- a/getstream/video/async_call.py +++ b/getstream/video/async_call.py @@ -273,6 +273,32 @@ async def list_recordings(self) -> StreamResponse[ListRecordingsResponse]: self._sync_from_response(response.data) return response + @attach_call_cid_async + async def start_recording( + self, recording_type: str, recording_external_storage: Optional[str] = None + ) -> StreamResponse[StartRecordingResponse]: + response = await self.client.start_recording( + type=self.call_type, + id=self.id, + recording_type=recording_type, + recording_external_storage=recording_external_storage, + ) + self._sync_from_response(response.data) + return response + + @attach_call_cid_async + async def stop_recording( + self, + recording_type: str, + ) -> StreamResponse[StopRecordingResponse]: + response = await self.client.stop_recording( + type=self.call_type, + id=self.id, + recording_type=recording_type, + ) + self._sync_from_response(response.data) + return response + @attach_call_cid_async async def get_call_report( self, session_id: Optional[str] = None @@ -326,6 +352,48 @@ async def stop_rtmp_broadcast( self._sync_from_response(response.data) return response + @attach_call_cid_async + async def get_call_participant_session_metrics( + self, + session: str, + user: str, + user_session: str, + since: Optional[datetime] = None, + until: Optional[datetime] = None, + ) -> StreamResponse[GetCallParticipantSessionMetricsResponse]: + response = await self.client.get_call_participant_session_metrics( + type=self.call_type, + id=self.id, + session=session, + user=user, + user_session=user_session, + since=since, + until=until, + ) + self._sync_from_response(response.data) + return response + + @attach_call_cid_async + async def query_call_participant_sessions( + self, + session: str, + limit: Optional[int] = None, + prev: Optional[str] = None, + next: Optional[str] = None, + filter_conditions: Optional[Dict[str, object]] = None, + ) -> StreamResponse[QueryCallParticipantSessionsResponse]: + response = await self.client.query_call_participant_sessions( + type=self.call_type, + id=self.id, + session=session, + limit=limit, + prev=prev, + next=next, + filter_conditions=filter_conditions, + ) + self._sync_from_response(response.data) + return response + @attach_call_cid_async async def start_hls_broadcasting( self, @@ -367,18 +435,6 @@ async def start_frame_recording( self._sync_from_response(response.data) return response - @attach_call_cid_async - async def start_recording( - self, recording_external_storage: Optional[str] = None - ) -> StreamResponse[StartRecordingResponse]: - response = await self.client.start_recording( - type=self.call_type, - id=self.id, - recording_external_storage=recording_external_storage, - ) - self._sync_from_response(response.data) - return response - @attach_call_cid_async async def start_transcription( self, @@ -451,17 +507,6 @@ async def stop_live( self._sync_from_response(response.data) return response - @attach_call_cid_async - async def stop_recording( - self, - ) -> StreamResponse[StopRecordingResponse]: - response = await self.client.stop_recording( - type=self.call_type, - id=self.id, - ) - self._sync_from_response(response.data) - return response - @attach_call_cid_async async def stop_transcription( self, stop_closed_captions: Optional[bool] = None diff --git a/getstream/video/async_rest_client.py b/getstream/video/async_rest_client.py index 815a4059..1ac231f0 100644 --- a/getstream/video/async_rest_client.py +++ b/getstream/video/async_rest_client.py @@ -487,6 +487,47 @@ async def list_recordings( path_params=path_params, ) + @telemetry.operation_name("getstream.api.video.start_recording") + async def start_recording( + self, + type: str, + id: str, + recording_type: str, + recording_external_storage: Optional[str] = None, + ) -> StreamResponse[StartRecordingResponse]: + path_params = { + "type": type, + "id": id, + "recording_type": recording_type, + } + json = build_body_dict(recording_external_storage=recording_external_storage) + return await self.post( + "/api/v2/video/call/{type}/{id}/recordings/{recording_type}/start", + StartRecordingResponse, + path_params=path_params, + json=json, + ) + + @telemetry.operation_name("getstream.api.video.stop_recording") + async def stop_recording( + self, + type: str, + id: str, + recording_type: str, + ) -> StreamResponse[StopRecordingResponse]: + path_params = { + "type": type, + "id": id, + "recording_type": recording_type, + } + json = build_body_dict() + return await self.post( + "/api/v2/video/call/{type}/{id}/recordings/{recording_type}/stop", + StopRecordingResponse, + path_params=path_params, + json=json, + ) + @telemetry.operation_name("getstream.api.video.get_call_report") async def get_call_report( self, type: str, id: str, session_id: Optional[str] = None @@ -573,6 +614,56 @@ async def stop_rtmp_broadcast( json=json, ) + @telemetry.operation_name( + "getstream.api.video.get_call_participant_session_metrics" + ) + async def get_call_participant_session_metrics( + self, + session: str, + user: str, + user_session: str, + since: Optional[datetime] = None, + until: Optional[datetime] = None, + ) -> StreamResponse[GetCallParticipantSessionMetricsResponse]: + query_params = build_query_param(since=since, until=until) + path_params = { + "session": session, + "user": user, + "user_session": user_session, + } + return await self.get( + "/api/v2/video/call/{type}/{id}/session/{session}/participant/{user}/{user_session}/details/track", + GetCallParticipantSessionMetricsResponse, + query_params=query_params, + path_params=path_params, + ) + + @telemetry.operation_name("getstream.api.video.query_call_participant_sessions") + async def query_call_participant_sessions( + self, + type: str, + id: str, + session: str, + limit: Optional[int] = None, + prev: Optional[str] = None, + next: Optional[str] = None, + filter_conditions: Optional[Dict[str, object]] = None, + ) -> StreamResponse[QueryCallParticipantSessionsResponse]: + query_params = build_query_param( + limit=limit, prev=prev, next=next, filter_conditions=filter_conditions + ) + path_params = { + "type": type, + "id": id, + "session": session, + } + return await self.get( + "/api/v2/video/call/{type}/{id}/session/{session}/participant_sessions", + QueryCallParticipantSessionsResponse, + query_params=query_params, + path_params=path_params, + ) + @telemetry.operation_name("getstream.api.video.start_hls_broadcasting") async def start_hls_broadcasting( self, type: str, id: str @@ -630,22 +721,6 @@ async def start_frame_recording( json=json, ) - @telemetry.operation_name("getstream.api.video.start_recording") - async def start_recording( - self, type: str, id: str, recording_external_storage: Optional[str] = None - ) -> StreamResponse[StartRecordingResponse]: - path_params = { - "type": type, - "id": id, - } - json = build_body_dict(recording_external_storage=recording_external_storage) - return await self.post( - "/api/v2/video/call/{type}/{id}/start_recording", - StartRecordingResponse, - path_params=path_params, - json=json, - ) - @telemetry.operation_name("getstream.api.video.start_transcription") async def start_transcription( self, @@ -750,24 +825,6 @@ async def stop_live( json=json, ) - @telemetry.operation_name("getstream.api.video.stop_recording") - async def stop_recording( - self, - type: str, - id: str, - ) -> StreamResponse[StopRecordingResponse]: - path_params = { - "type": type, - "id": id, - } - json = build_body_dict() - return await self.post( - "/api/v2/video/call/{type}/{id}/stop_recording", - StopRecordingResponse, - path_params=path_params, - json=json, - ) - @telemetry.operation_name("getstream.api.video.stop_transcription") async def stop_transcription( self, type: str, id: str, stop_closed_captions: Optional[bool] = None @@ -1104,30 +1161,12 @@ async def update_call_type( async def get_edges(self) -> StreamResponse[GetEdgesResponse]: return await self.get("/api/v2/video/edges", GetEdgesResponse) - @telemetry.operation_name("getstream.api.video.resolve_sip_inbound") - async def resolve_sip_inbound( - self, - sip_caller_number: str, - sip_trunk_number: str, - challenge: SIPChallenge, - sip_headers: Optional[Dict[str, str]] = None, - ) -> StreamResponse[ResolveSipInboundResponse]: - json = build_body_dict( - sip_caller_number=sip_caller_number, - sip_trunk_number=sip_trunk_number, - challenge=challenge, - sip_headers=sip_headers, - ) - return await self.post( - "/api/v2/video/sip/resolve", ResolveSipInboundResponse, json=json - ) - @telemetry.operation_name("getstream.api.video.list_sip_inbound_routing_rule") async def list_sip_inbound_routing_rule( self, ) -> StreamResponse[ListSIPInboundRoutingRuleResponse]: return await self.get( - "/api/v2/video/sip/routing_rules", ListSIPInboundRoutingRuleResponse + "/api/v2/video/sip/inbound_routing_rules", ListSIPInboundRoutingRuleResponse ) @telemetry.operation_name("getstream.api.video.create_sip_inbound_routing_rule") @@ -1155,7 +1194,9 @@ async def create_sip_inbound_routing_rule( pin_routing_configs=pin_routing_configs, ) return await self.post( - "/api/v2/video/sip/routing_rules", SIPInboundRoutingRuleResponse, json=json + "/api/v2/video/sip/inbound_routing_rules", + SIPInboundRoutingRuleResponse, + json=json, ) @telemetry.operation_name("getstream.api.video.delete_sip_inbound_routing_rule") @@ -1166,7 +1207,7 @@ async def delete_sip_inbound_routing_rule( "id": id, } return await self.delete( - "/api/v2/video/sip/routing_rules/{id}", + "/api/v2/video/sip/inbound_routing_rules/{id}", DeleteSIPInboundRoutingRuleResponse, path_params=path_params, ) @@ -1200,7 +1241,7 @@ async def update_sip_inbound_routing_rule( pin_routing_configs=pin_routing_configs, ) return await self.put( - "/api/v2/video/sip/routing_rules/{id}", + "/api/v2/video/sip/inbound_routing_rules/{id}", UpdateSIPInboundRoutingRuleResponse, path_params=path_params, json=json, @@ -1208,7 +1249,7 @@ async def update_sip_inbound_routing_rule( @telemetry.operation_name("getstream.api.video.list_sip_trunks") async def list_sip_trunks(self) -> StreamResponse[ListSIPTrunksResponse]: - return await self.get("/api/v2/video/sip/trunks", ListSIPTrunksResponse) + return await self.get("/api/v2/video/sip/inbound_trunks", ListSIPTrunksResponse) @telemetry.operation_name("getstream.api.video.create_sip_trunk") async def create_sip_trunk( @@ -1216,7 +1257,7 @@ async def create_sip_trunk( ) -> StreamResponse[CreateSIPTrunkResponse]: json = build_body_dict(name=name, numbers=numbers) return await self.post( - "/api/v2/video/sip/trunks", CreateSIPTrunkResponse, json=json + "/api/v2/video/sip/inbound_trunks", CreateSIPTrunkResponse, json=json ) @telemetry.operation_name("getstream.api.video.delete_sip_trunk") @@ -1225,7 +1266,7 @@ async def delete_sip_trunk(self, id: str) -> StreamResponse[DeleteSIPTrunkRespon "id": id, } return await self.delete( - "/api/v2/video/sip/trunks/{id}", + "/api/v2/video/sip/inbound_trunks/{id}", DeleteSIPTrunkResponse, path_params=path_params, ) @@ -1239,12 +1280,32 @@ async def update_sip_trunk( } json = build_body_dict(name=name, numbers=numbers) return await self.put( - "/api/v2/video/sip/trunks/{id}", + "/api/v2/video/sip/inbound_trunks/{id}", UpdateSIPTrunkResponse, path_params=path_params, json=json, ) + @telemetry.operation_name("getstream.api.video.resolve_sip_inbound") + async def resolve_sip_inbound( + self, + sip_caller_number: str, + sip_trunk_number: str, + challenge: SIPChallenge, + routing_number: Optional[str] = None, + sip_headers: Optional[Dict[str, str]] = None, + ) -> StreamResponse[ResolveSipInboundResponse]: + json = build_body_dict( + sip_caller_number=sip_caller_number, + sip_trunk_number=sip_trunk_number, + challenge=challenge, + routing_number=routing_number, + sip_headers=sip_headers, + ) + return await self.post( + "/api/v2/video/sip/resolve", ResolveSipInboundResponse, json=json + ) + @telemetry.operation_name("getstream.api.video.query_aggregate_call_stats") async def query_aggregate_call_stats( self, diff --git a/getstream/video/call.py b/getstream/video/call.py index 5dfef99d..197f5d0e 100644 --- a/getstream/video/call.py +++ b/getstream/video/call.py @@ -267,6 +267,32 @@ def list_recordings(self) -> StreamResponse[ListRecordingsResponse]: self._sync_from_response(response.data) return response + @attach_call_cid + def start_recording( + self, recording_type: str, recording_external_storage: Optional[str] = None + ) -> StreamResponse[StartRecordingResponse]: + response = self.client.start_recording( + type=self.call_type, + id=self.id, + recording_type=recording_type, + recording_external_storage=recording_external_storage, + ) + self._sync_from_response(response.data) + return response + + @attach_call_cid + def stop_recording( + self, + recording_type: str, + ) -> StreamResponse[StopRecordingResponse]: + response = self.client.stop_recording( + type=self.call_type, + id=self.id, + recording_type=recording_type, + ) + self._sync_from_response(response.data) + return response + @attach_call_cid def get_call_report( self, session_id: Optional[str] = None @@ -316,6 +342,48 @@ def stop_rtmp_broadcast( self._sync_from_response(response.data) return response + @attach_call_cid + def get_call_participant_session_metrics( + self, + session: str, + user: str, + user_session: str, + since: Optional[datetime] = None, + until: Optional[datetime] = None, + ) -> StreamResponse[GetCallParticipantSessionMetricsResponse]: + response = self.client.get_call_participant_session_metrics( + type=self.call_type, + id=self.id, + session=session, + user=user, + user_session=user_session, + since=since, + until=until, + ) + self._sync_from_response(response.data) + return response + + @attach_call_cid + def query_call_participant_sessions( + self, + session: str, + limit: Optional[int] = None, + prev: Optional[str] = None, + next: Optional[str] = None, + filter_conditions: Optional[Dict[str, object]] = None, + ) -> StreamResponse[QueryCallParticipantSessionsResponse]: + response = self.client.query_call_participant_sessions( + type=self.call_type, + id=self.id, + session=session, + limit=limit, + prev=prev, + next=next, + filter_conditions=filter_conditions, + ) + self._sync_from_response(response.data) + return response + @attach_call_cid def start_hls_broadcasting(self) -> StreamResponse[StartHLSBroadcastingResponse]: response = self.client.start_hls_broadcasting(type=self.call_type, id=self.id) @@ -353,18 +421,6 @@ def start_frame_recording( self._sync_from_response(response.data) return response - @attach_call_cid - def start_recording( - self, recording_external_storage: Optional[str] = None - ) -> StreamResponse[StartRecordingResponse]: - response = self.client.start_recording( - type=self.call_type, - id=self.id, - recording_external_storage=recording_external_storage, - ) - self._sync_from_response(response.data) - return response - @attach_call_cid def start_transcription( self, @@ -431,17 +487,6 @@ def stop_live( self._sync_from_response(response.data) return response - @attach_call_cid - def stop_recording( - self, - ) -> StreamResponse[StopRecordingResponse]: - response = self.client.stop_recording( - type=self.call_type, - id=self.id, - ) - self._sync_from_response(response.data) - return response - @attach_call_cid def stop_transcription( self, stop_closed_captions: Optional[bool] = None diff --git a/getstream/video/rest_client.py b/getstream/video/rest_client.py index 17dcd2d8..c13b620e 100644 --- a/getstream/video/rest_client.py +++ b/getstream/video/rest_client.py @@ -483,6 +483,47 @@ def list_recordings( path_params=path_params, ) + @telemetry.operation_name("getstream.api.video.start_recording") + def start_recording( + self, + type: str, + id: str, + recording_type: str, + recording_external_storage: Optional[str] = None, + ) -> StreamResponse[StartRecordingResponse]: + path_params = { + "type": type, + "id": id, + "recording_type": recording_type, + } + json = build_body_dict(recording_external_storage=recording_external_storage) + return self.post( + "/api/v2/video/call/{type}/{id}/recordings/{recording_type}/start", + StartRecordingResponse, + path_params=path_params, + json=json, + ) + + @telemetry.operation_name("getstream.api.video.stop_recording") + def stop_recording( + self, + type: str, + id: str, + recording_type: str, + ) -> StreamResponse[StopRecordingResponse]: + path_params = { + "type": type, + "id": id, + "recording_type": recording_type, + } + json = build_body_dict() + return self.post( + "/api/v2/video/call/{type}/{id}/recordings/{recording_type}/stop", + StopRecordingResponse, + path_params=path_params, + json=json, + ) + @telemetry.operation_name("getstream.api.video.get_call_report") def get_call_report( self, type: str, id: str, session_id: Optional[str] = None @@ -569,6 +610,56 @@ def stop_rtmp_broadcast( json=json, ) + @telemetry.operation_name( + "getstream.api.video.get_call_participant_session_metrics" + ) + def get_call_participant_session_metrics( + self, + session: str, + user: str, + user_session: str, + since: Optional[datetime] = None, + until: Optional[datetime] = None, + ) -> StreamResponse[GetCallParticipantSessionMetricsResponse]: + query_params = build_query_param(since=since, until=until) + path_params = { + "session": session, + "user": user, + "user_session": user_session, + } + return self.get( + "/api/v2/video/call/{type}/{id}/session/{session}/participant/{user}/{user_session}/details/track", + GetCallParticipantSessionMetricsResponse, + query_params=query_params, + path_params=path_params, + ) + + @telemetry.operation_name("getstream.api.video.query_call_participant_sessions") + def query_call_participant_sessions( + self, + type: str, + id: str, + session: str, + limit: Optional[int] = None, + prev: Optional[str] = None, + next: Optional[str] = None, + filter_conditions: Optional[Dict[str, object]] = None, + ) -> StreamResponse[QueryCallParticipantSessionsResponse]: + query_params = build_query_param( + limit=limit, prev=prev, next=next, filter_conditions=filter_conditions + ) + path_params = { + "type": type, + "id": id, + "session": session, + } + return self.get( + "/api/v2/video/call/{type}/{id}/session/{session}/participant_sessions", + QueryCallParticipantSessionsResponse, + query_params=query_params, + path_params=path_params, + ) + @telemetry.operation_name("getstream.api.video.start_hls_broadcasting") def start_hls_broadcasting( self, type: str, id: str @@ -626,22 +717,6 @@ def start_frame_recording( json=json, ) - @telemetry.operation_name("getstream.api.video.start_recording") - def start_recording( - self, type: str, id: str, recording_external_storage: Optional[str] = None - ) -> StreamResponse[StartRecordingResponse]: - path_params = { - "type": type, - "id": id, - } - json = build_body_dict(recording_external_storage=recording_external_storage) - return self.post( - "/api/v2/video/call/{type}/{id}/start_recording", - StartRecordingResponse, - path_params=path_params, - json=json, - ) - @telemetry.operation_name("getstream.api.video.start_transcription") def start_transcription( self, @@ -746,24 +821,6 @@ def stop_live( json=json, ) - @telemetry.operation_name("getstream.api.video.stop_recording") - def stop_recording( - self, - type: str, - id: str, - ) -> StreamResponse[StopRecordingResponse]: - path_params = { - "type": type, - "id": id, - } - json = build_body_dict() - return self.post( - "/api/v2/video/call/{type}/{id}/stop_recording", - StopRecordingResponse, - path_params=path_params, - json=json, - ) - @telemetry.operation_name("getstream.api.video.stop_transcription") def stop_transcription( self, type: str, id: str, stop_closed_captions: Optional[bool] = None @@ -1098,30 +1155,12 @@ def update_call_type( def get_edges(self) -> StreamResponse[GetEdgesResponse]: return self.get("/api/v2/video/edges", GetEdgesResponse) - @telemetry.operation_name("getstream.api.video.resolve_sip_inbound") - def resolve_sip_inbound( - self, - sip_caller_number: str, - sip_trunk_number: str, - challenge: SIPChallenge, - sip_headers: Optional[Dict[str, str]] = None, - ) -> StreamResponse[ResolveSipInboundResponse]: - json = build_body_dict( - sip_caller_number=sip_caller_number, - sip_trunk_number=sip_trunk_number, - challenge=challenge, - sip_headers=sip_headers, - ) - return self.post( - "/api/v2/video/sip/resolve", ResolveSipInboundResponse, json=json - ) - @telemetry.operation_name("getstream.api.video.list_sip_inbound_routing_rule") def list_sip_inbound_routing_rule( self, ) -> StreamResponse[ListSIPInboundRoutingRuleResponse]: return self.get( - "/api/v2/video/sip/routing_rules", ListSIPInboundRoutingRuleResponse + "/api/v2/video/sip/inbound_routing_rules", ListSIPInboundRoutingRuleResponse ) @telemetry.operation_name("getstream.api.video.create_sip_inbound_routing_rule") @@ -1149,7 +1188,9 @@ def create_sip_inbound_routing_rule( pin_routing_configs=pin_routing_configs, ) return self.post( - "/api/v2/video/sip/routing_rules", SIPInboundRoutingRuleResponse, json=json + "/api/v2/video/sip/inbound_routing_rules", + SIPInboundRoutingRuleResponse, + json=json, ) @telemetry.operation_name("getstream.api.video.delete_sip_inbound_routing_rule") @@ -1160,7 +1201,7 @@ def delete_sip_inbound_routing_rule( "id": id, } return self.delete( - "/api/v2/video/sip/routing_rules/{id}", + "/api/v2/video/sip/inbound_routing_rules/{id}", DeleteSIPInboundRoutingRuleResponse, path_params=path_params, ) @@ -1194,7 +1235,7 @@ def update_sip_inbound_routing_rule( pin_routing_configs=pin_routing_configs, ) return self.put( - "/api/v2/video/sip/routing_rules/{id}", + "/api/v2/video/sip/inbound_routing_rules/{id}", UpdateSIPInboundRoutingRuleResponse, path_params=path_params, json=json, @@ -1202,14 +1243,16 @@ def update_sip_inbound_routing_rule( @telemetry.operation_name("getstream.api.video.list_sip_trunks") def list_sip_trunks(self) -> StreamResponse[ListSIPTrunksResponse]: - return self.get("/api/v2/video/sip/trunks", ListSIPTrunksResponse) + return self.get("/api/v2/video/sip/inbound_trunks", ListSIPTrunksResponse) @telemetry.operation_name("getstream.api.video.create_sip_trunk") def create_sip_trunk( self, name: str, numbers: List[str] ) -> StreamResponse[CreateSIPTrunkResponse]: json = build_body_dict(name=name, numbers=numbers) - return self.post("/api/v2/video/sip/trunks", CreateSIPTrunkResponse, json=json) + return self.post( + "/api/v2/video/sip/inbound_trunks", CreateSIPTrunkResponse, json=json + ) @telemetry.operation_name("getstream.api.video.delete_sip_trunk") def delete_sip_trunk(self, id: str) -> StreamResponse[DeleteSIPTrunkResponse]: @@ -1217,7 +1260,7 @@ def delete_sip_trunk(self, id: str) -> StreamResponse[DeleteSIPTrunkResponse]: "id": id, } return self.delete( - "/api/v2/video/sip/trunks/{id}", + "/api/v2/video/sip/inbound_trunks/{id}", DeleteSIPTrunkResponse, path_params=path_params, ) @@ -1231,12 +1274,32 @@ def update_sip_trunk( } json = build_body_dict(name=name, numbers=numbers) return self.put( - "/api/v2/video/sip/trunks/{id}", + "/api/v2/video/sip/inbound_trunks/{id}", UpdateSIPTrunkResponse, path_params=path_params, json=json, ) + @telemetry.operation_name("getstream.api.video.resolve_sip_inbound") + def resolve_sip_inbound( + self, + sip_caller_number: str, + sip_trunk_number: str, + challenge: SIPChallenge, + routing_number: Optional[str] = None, + sip_headers: Optional[Dict[str, str]] = None, + ) -> StreamResponse[ResolveSipInboundResponse]: + json = build_body_dict( + sip_caller_number=sip_caller_number, + sip_trunk_number=sip_trunk_number, + challenge=challenge, + routing_number=routing_number, + sip_headers=sip_headers, + ) + return self.post( + "/api/v2/video/sip/resolve", ResolveSipInboundResponse, json=json + ) + @telemetry.operation_name("getstream.api.video.query_aggregate_call_stats") def query_aggregate_call_stats( self, diff --git a/tests/test_video_examples.py b/tests/test_video_examples.py index 8527f8f2..0812e07c 100644 --- a/tests/test_video_examples.py +++ b/tests/test_video_examples.py @@ -329,7 +329,7 @@ def test_start_stop_frame_recording(client: Stream): call.get_or_create(data=CallRequest(created_by_id=user_id)) with pytest.raises(StreamAPIException) as e_info: - call.start_recording() + call.start_recording(recording_type="composite") assert e_info.value.status_code == 400 assert ( @@ -338,7 +338,7 @@ def test_start_stop_frame_recording(client: Stream): ) with pytest.raises(StreamAPIException) as e_info: - call.stop_recording() + call.stop_recording(recording_type="composite") assert e_info.value.status_code == 400 assert (