diff --git a/getstream/chat/async_channel.py b/getstream/chat/async_channel.py index 03f33e78..30eec042 100644 --- a/getstream/chat/async_channel.py +++ b/getstream/chat/async_channel.py @@ -31,6 +31,25 @@ async def delete( self._sync_from_response(response.data) return response + @attach_channel_cid_async + async def get( + self, + state: Optional[bool] = None, + messages_limit: Optional[int] = None, + members_limit: Optional[int] = None, + watchers_limit: Optional[int] = None, + ) -> StreamResponse[ChannelStateResponse]: + response = await self.client.get_channel( + type=self.channel_type, + id=self.channel_id, + state=state, + messages_limit=messages_limit, + members_limit=members_limit, + watchers_limit=watchers_limit, + ) + self._sync_from_response(response.data) + return response + @attach_channel_cid_async async def update_channel_partial( self, diff --git a/getstream/chat/async_rest_client.py b/getstream/chat/async_rest_client.py index bbed3216..ec3afe5b 100644 --- a/getstream/chat/async_rest_client.py +++ b/getstream/chat/async_rest_client.py @@ -353,6 +353,35 @@ async def delete_channel( path_params=path_params, ) + @telemetry.operation_name("getstream.api.chat.get_channel") + async def get_channel( + self, + type: str, + id: str, + state: Optional[bool] = None, + messages_limit: Optional[int] = None, + members_limit: Optional[int] = None, + watchers_limit: Optional[int] = None, + ) -> StreamResponse[ChannelStateResponse]: + query_params = build_query_param( + **{ + "state": state, + "messages_limit": messages_limit, + "members_limit": members_limit, + "watchers_limit": watchers_limit, + } + ) + path_params = { + "type": type, + "id": id, + } + return await self.get( + "/api/v2/chat/channels/{type}/{id}", + ChannelStateResponse, + query_params=query_params, + path_params=path_params, + ) + @telemetry.operation_name("getstream.api.chat.update_channel_partial") async def update_channel_partial( self, diff --git a/getstream/chat/channel.py b/getstream/chat/channel.py index d2e86ce9..445c7d77 100644 --- a/getstream/chat/channel.py +++ b/getstream/chat/channel.py @@ -31,6 +31,25 @@ def delete( self._sync_from_response(response.data) return response + @attach_channel_cid + def get( + self, + state: Optional[bool] = None, + messages_limit: Optional[int] = None, + members_limit: Optional[int] = None, + watchers_limit: Optional[int] = None, + ) -> StreamResponse[ChannelStateResponse]: + response = self.client.get_channel( + type=self.channel_type, + id=self.channel_id, + state=state, + messages_limit=messages_limit, + members_limit=members_limit, + watchers_limit=watchers_limit, + ) + self._sync_from_response(response.data) + return response + @attach_channel_cid def update_channel_partial( self, diff --git a/getstream/chat/rest_client.py b/getstream/chat/rest_client.py index 75f1f08d..7513e711 100644 --- a/getstream/chat/rest_client.py +++ b/getstream/chat/rest_client.py @@ -347,6 +347,35 @@ def delete_channel( path_params=path_params, ) + @telemetry.operation_name("getstream.api.chat.get_channel") + def get_channel( + self, + type: str, + id: str, + state: Optional[bool] = None, + messages_limit: Optional[int] = None, + members_limit: Optional[int] = None, + watchers_limit: Optional[int] = None, + ) -> StreamResponse[ChannelStateResponse]: + query_params = build_query_param( + **{ + "state": state, + "messages_limit": messages_limit, + "members_limit": members_limit, + "watchers_limit": watchers_limit, + } + ) + path_params = { + "type": type, + "id": id, + } + return self.get( + "/api/v2/chat/channels/{type}/{id}", + ChannelStateResponse, + query_params=query_params, + path_params=path_params, + ) + @telemetry.operation_name("getstream.api.chat.update_channel_partial") def update_channel_partial( self, diff --git a/getstream/common/async_rest_client.py b/getstream/common/async_rest_client.py index 5df0c77e..67925dd4 100644 --- a/getstream/common/async_rest_client.py +++ b/getstream/common/async_rest_client.py @@ -49,6 +49,7 @@ async def update_app( disable_permissions_checks: Optional[bool] = None, enable_hook_payload_compression: Optional[bool] = None, enforce_unique_usernames: Optional[str] = None, + feed_audit_logs_enabled: Optional[bool] = None, feeds_moderation_enabled: Optional[bool] = None, feeds_v2_region: Optional[str] = None, guest_user_creation_disabled: Optional[bool] = None, @@ -64,6 +65,7 @@ async def update_app( permission_version: Optional[str] = None, reminders_interval: Optional[int] = None, reminders_max_members: Optional[int] = None, + reminders_max_per_user: Optional[int] = None, revoke_tokens_issued_before: Optional[datetime] = None, sns_key: Optional[str] = None, sns_secret: Optional[str] = None, @@ -107,6 +109,7 @@ async def update_app( disable_permissions_checks=disable_permissions_checks, enable_hook_payload_compression=enable_hook_payload_compression, enforce_unique_usernames=enforce_unique_usernames, + feed_audit_logs_enabled=feed_audit_logs_enabled, feeds_moderation_enabled=feeds_moderation_enabled, feeds_v2_region=feeds_v2_region, guest_user_creation_disabled=guest_user_creation_disabled, @@ -122,6 +125,7 @@ async def update_app( permission_version=permission_version, reminders_interval=reminders_interval, reminders_max_members=reminders_max_members, + reminders_max_per_user=reminders_max_per_user, revoke_tokens_issued_before=revoke_tokens_issued_before, sns_key=sns_key, sns_secret=sns_secret, diff --git a/getstream/common/rest_client.py b/getstream/common/rest_client.py index 92abd1f2..e333e0ac 100644 --- a/getstream/common/rest_client.py +++ b/getstream/common/rest_client.py @@ -49,6 +49,7 @@ def update_app( disable_permissions_checks: Optional[bool] = None, enable_hook_payload_compression: Optional[bool] = None, enforce_unique_usernames: Optional[str] = None, + feed_audit_logs_enabled: Optional[bool] = None, feeds_moderation_enabled: Optional[bool] = None, feeds_v2_region: Optional[str] = None, guest_user_creation_disabled: Optional[bool] = None, @@ -64,6 +65,7 @@ def update_app( permission_version: Optional[str] = None, reminders_interval: Optional[int] = None, reminders_max_members: Optional[int] = None, + reminders_max_per_user: Optional[int] = None, revoke_tokens_issued_before: Optional[datetime] = None, sns_key: Optional[str] = None, sns_secret: Optional[str] = None, @@ -107,6 +109,7 @@ def update_app( disable_permissions_checks=disable_permissions_checks, enable_hook_payload_compression=enable_hook_payload_compression, enforce_unique_usernames=enforce_unique_usernames, + feed_audit_logs_enabled=feed_audit_logs_enabled, feeds_moderation_enabled=feeds_moderation_enabled, feeds_v2_region=feeds_v2_region, guest_user_creation_disabled=guest_user_creation_disabled, @@ -122,6 +125,7 @@ def update_app( permission_version=permission_version, reminders_interval=reminders_interval, reminders_max_members=reminders_max_members, + reminders_max_per_user=reminders_max_per_user, revoke_tokens_issued_before=revoke_tokens_issued_before, sns_key=sns_key, sns_secret=sns_secret, diff --git a/getstream/feeds/feeds.py b/getstream/feeds/feeds.py index e53c72f7..2ad55e8a 100644 --- a/getstream/feeds/feeds.py +++ b/getstream/feeds/feeds.py @@ -30,6 +30,8 @@ def delete( def get_or_create( self, + language: Optional[str] = None, + translate_text: Optional[bool] = None, id_around: Optional[str] = None, limit: Optional[int] = None, next: Optional[str] = None, @@ -52,6 +54,8 @@ def get_or_create( response = self.client.get_or_create_feed( feed_group_id=self.feed_group, feed_id=self.id, + language=language, + translate_text=translate_text, id_around=id_around, limit=limit, next=next, @@ -230,6 +234,8 @@ def reject_feed_member_invite( def query_pinned_activities( self, + language: Optional[str] = None, + translate_text: Optional[bool] = None, enrich_own_fields: Optional[bool] = None, limit: Optional[int] = None, next: Optional[str] = None, @@ -240,6 +246,8 @@ def query_pinned_activities( response = self.client.query_pinned_activities( feed_group_id=self.feed_group, feed_id=self.id, + language=language, + translate_text=translate_text, enrich_own_fields=enrich_own_fields, limit=limit, next=next, diff --git a/getstream/feeds/rest_client.py b/getstream/feeds/rest_client.py index 89122ea0..8eaad9c2 100644 --- a/getstream/feeds/rest_client.py +++ b/getstream/feeds/rest_client.py @@ -163,6 +163,8 @@ def track_activity_metrics( @telemetry.operation_name("getstream.api.feeds.query_activities") def query_activities( self, + language: Optional[str] = None, + translate_text: Optional[bool] = None, enrich_own_fields: Optional[bool] = None, include_expired_activities: Optional[bool] = None, include_private_activities: Optional[bool] = None, @@ -175,6 +177,9 @@ def query_activities( filter: Optional[Dict[str, object]] = None, user: Optional[UserRequest] = None, ) -> StreamResponse[QueryActivitiesResponse]: + query_params = build_query_param( + **{"language": language, "translate_text": translate_text} + ) json = QueryActivitiesRequest( enrich_own_fields=enrich_own_fields, include_expired_activities=include_expired_activities, @@ -189,7 +194,38 @@ def query_activities( user=user, ).to_dict() return self.post( - "/api/v2/feeds/activities/query", QueryActivitiesResponse, json=json + "/api/v2/feeds/activities/query", + QueryActivitiesResponse, + query_params=query_params, + json=json, + ) + + @telemetry.operation_name("getstream.api.feeds.batch_query_activity_reactions") + def batch_query_activity_reactions( + self, + activity_ids: List[str], + limit: Optional[int] = None, + next: Optional[str] = None, + prev: Optional[str] = None, + user_id: Optional[str] = None, + sort: Optional[List[SortParamRequest]] = None, + filter: Optional[Dict[str, object]] = None, + user: Optional[UserRequest] = None, + ) -> StreamResponse[BatchQueryActivityReactionsResponse]: + json = BatchQueryActivityReactionsRequest( + activity_ids=activity_ids, + limit=limit, + next=next, + prev=prev, + user_id=user_id, + sort=sort, + filter=filter, + user=user, + ).to_dict() + return self.post( + "/api/v2/feeds/activities/reactions/query", + BatchQueryActivityReactionsResponse, + json=json, ) @telemetry.operation_name("getstream.api.feeds.delete_bookmark") @@ -346,6 +382,7 @@ def add_activity_reaction( enforce_unique: Optional[bool] = None, skip_push: Optional[bool] = None, user_id: Optional[str] = None, + target_feeds: Optional[List[str]] = None, custom: Optional[Dict[str, object]] = None, user: Optional[UserRequest] = None, ) -> StreamResponse[AddReactionResponse]: @@ -360,6 +397,7 @@ def add_activity_reaction( enforce_unique=enforce_unique, skip_push=skip_push, user_id=user_id, + target_feeds=target_feeds, custom=custom, user=user, ).to_dict() @@ -418,6 +456,25 @@ def delete_activity_reaction( path_params=path_params, ) + @telemetry.operation_name("getstream.api.feeds.query_activity_shares") + def query_activity_shares( + self, + activity_id: str, + limit: Optional[int] = None, + prev: Optional[str] = None, + next: Optional[str] = None, + ) -> StreamResponse[QueryActivitySharesResponse]: + query_params = build_query_param(**{"limit": limit, "prev": prev, "next": next}) + path_params = { + "activity_id": activity_id, + } + return self.get( + "/api/v2/feeds/activities/{activity_id}/shares", + QueryActivitySharesResponse, + query_params=query_params, + path_params=path_params, + ) + @telemetry.operation_name("getstream.api.feeds.delete_activity") def delete_activity( self, @@ -445,12 +502,16 @@ def delete_activity( def get_activity( self, id: str, + language: Optional[str] = None, + translate_text: Optional[bool] = None, comment_sort: Optional[str] = None, comment_limit: Optional[int] = None, user_id: Optional[str] = None, ) -> StreamResponse[GetActivityResponse]: query_params = build_query_param( **{ + "language": language, + "translate_text": translate_text, "comment_sort": comment_sort, "comment_limit": comment_limit, "user_id": user_id, @@ -585,6 +646,21 @@ def restore_activity( json=json, ) + @telemetry.operation_name("getstream.api.feeds.translate_activity") + def translate_activity( + self, id: str, language: str + ) -> StreamResponse[TranslateActivityResponse]: + path_params = { + "id": id, + } + json = TranslateActivityRequest(language=language).to_dict() + return self.post( + "/api/v2/feeds/activities/{id}/translate", + TranslateActivityResponse, + path_params=path_params, + json=json, + ) + @telemetry.operation_name("getstream.api.feeds.query_bookmark_folders") def query_bookmark_folders( self, @@ -641,6 +717,8 @@ def update_bookmark_folder( @telemetry.operation_name("getstream.api.feeds.query_bookmarks") def query_bookmarks( self, + language: Optional[str] = None, + translate_text: Optional[bool] = None, enrich_own_fields: Optional[bool] = None, limit: Optional[int] = None, next: Optional[str] = None, @@ -650,6 +728,9 @@ def query_bookmarks( filter: Optional[Dict[str, object]] = None, user: Optional[UserRequest] = None, ) -> StreamResponse[QueryBookmarksResponse]: + query_params = build_query_param( + **{"language": language, "translate_text": translate_text} + ) json = QueryBookmarksRequest( enrich_own_fields=enrich_own_fields, limit=limit, @@ -661,7 +742,10 @@ def query_bookmarks( user=user, ).to_dict() return self.post( - "/api/v2/feeds/bookmarks/query", QueryBookmarksResponse, json=json + "/api/v2/feeds/bookmarks/query", + QueryBookmarksResponse, + query_params=query_params, + json=json, ) @telemetry.operation_name("getstream.api.feeds.delete_collections") @@ -758,6 +842,8 @@ def get_comments( sort: Optional[str] = None, replies_limit: Optional[int] = None, id_around: Optional[str] = None, + language: Optional[str] = None, + translate_text: Optional[bool] = None, user_id: Optional[str] = None, limit: Optional[int] = None, prev: Optional[str] = None, @@ -771,6 +857,8 @@ def get_comments( "sort": sort, "replies_limit": replies_limit, "id_around": id_around, + "language": language, + "translate_text": translate_text, "user_id": user_id, "limit": limit, "prev": prev, @@ -839,7 +927,12 @@ def query_comments( sort: Optional[str] = None, user_id: Optional[str] = None, user: Optional[UserRequest] = None, + language: Optional[str] = None, + translate_text: Optional[bool] = None, ) -> StreamResponse[QueryCommentsResponse]: + query_params = build_query_param( + **{"language": language, "translate_text": translate_text} + ) json = QueryCommentsRequest( filter=filter, id_around=id_around, @@ -851,7 +944,38 @@ def query_comments( user=user, ).to_dict() return self.post( - "/api/v2/feeds/comments/query", QueryCommentsResponse, json=json + "/api/v2/feeds/comments/query", + QueryCommentsResponse, + query_params=query_params, + json=json, + ) + + @telemetry.operation_name("getstream.api.feeds.batch_query_comment_reactions") + def batch_query_comment_reactions( + self, + comment_ids: List[str], + limit: Optional[int] = None, + next: Optional[str] = None, + prev: Optional[str] = None, + user_id: Optional[str] = None, + sort: Optional[List[SortParamRequest]] = None, + filter: Optional[Dict[str, object]] = None, + user: Optional[UserRequest] = None, + ) -> StreamResponse[BatchQueryCommentReactionsResponse]: + json = BatchQueryCommentReactionsRequest( + comment_ids=comment_ids, + limit=limit, + next=next, + prev=prev, + user_id=user_id, + sort=sort, + filter=filter, + user=user, + ).to_dict() + return self.post( + "/api/v2/feeds/comments/reactions/query", + BatchQueryCommentReactionsResponse, + json=json, ) @telemetry.operation_name("getstream.api.feeds.delete_comment_bookmark") @@ -953,9 +1077,19 @@ def delete_comment( @telemetry.operation_name("getstream.api.feeds.get_comment") def get_comment( - self, id: str, user_id: Optional[str] = None + self, + id: str, + language: Optional[str] = None, + translate_text: Optional[bool] = None, + user_id: Optional[str] = None, ) -> StreamResponse[GetCommentResponse]: - query_params = build_query_param(**{"user_id": user_id}) + query_params = build_query_param( + **{ + "language": language, + "translate_text": translate_text, + "user_id": user_id, + } + ) path_params = { "id": id, } @@ -1050,6 +1184,7 @@ def add_comment_reaction( enforce_unique: Optional[bool] = None, skip_push: Optional[bool] = None, user_id: Optional[str] = None, + target_feeds: Optional[List[str]] = None, custom: Optional[Dict[str, object]] = None, user: Optional[UserRequest] = None, ) -> StreamResponse[AddCommentReactionResponse]: @@ -1063,6 +1198,7 @@ def add_comment_reaction( enforce_unique=enforce_unique, skip_push=skip_push, user_id=user_id, + target_feeds=target_feeds, custom=custom, user=user, ).to_dict() @@ -1129,6 +1265,8 @@ def get_comment_replies( sort: Optional[str] = None, replies_limit: Optional[int] = None, id_around: Optional[str] = None, + language: Optional[str] = None, + translate_text: Optional[bool] = None, user_id: Optional[str] = None, limit: Optional[int] = None, prev: Optional[str] = None, @@ -1140,6 +1278,8 @@ def get_comment_replies( "sort": sort, "replies_limit": replies_limit, "id_around": id_around, + "language": language, + "translate_text": translate_text, "user_id": user_id, "limit": limit, "prev": prev, @@ -1171,6 +1311,21 @@ def restore_comment( json=json, ) + @telemetry.operation_name("getstream.api.feeds.translate_comment") + def translate_comment( + self, id: str, language: str + ) -> StreamResponse[TranslateCommentResponse]: + path_params = { + "id": id, + } + json = TranslateCommentRequest(language=language).to_dict() + return self.post( + "/api/v2/feeds/comments/{id}/translate", + TranslateCommentResponse, + path_params=path_params, + json=json, + ) + @telemetry.operation_name("getstream.api.feeds.list_feed_groups") def list_feed_groups( self, include_soft_deleted: Optional[bool] = None @@ -1246,6 +1401,8 @@ def get_or_create_feed( self, feed_group_id: str, feed_id: str, + language: Optional[str] = None, + translate_text: Optional[bool] = None, id_around: Optional[str] = None, limit: Optional[int] = None, next: Optional[str] = None, @@ -1265,6 +1422,9 @@ def get_or_create_feed( member_pagination: Optional[PagerRequest] = None, user: Optional[UserRequest] = None, ) -> StreamResponse[GetOrCreateFeedResponse]: + query_params = build_query_param( + **{"language": language, "translate_text": translate_text} + ) path_params = { "feed_group_id": feed_group_id, "feed_id": feed_id, @@ -1292,6 +1452,7 @@ def get_or_create_feed( return self.post( "/api/v2/feeds/feed_groups/{feed_group_id}/feeds/{feed_id}", GetOrCreateFeedResponse, + query_params=query_params, path_params=path_params, json=json, ) @@ -1530,6 +1691,8 @@ def query_pinned_activities( self, feed_group_id: str, feed_id: str, + language: Optional[str] = None, + translate_text: Optional[bool] = None, enrich_own_fields: Optional[bool] = None, limit: Optional[int] = None, next: Optional[str] = None, @@ -1537,6 +1700,9 @@ def query_pinned_activities( sort: Optional[List[SortParamRequest]] = None, filter: Optional[Dict[str, object]] = None, ) -> StreamResponse[QueryPinnedActivitiesResponse]: + query_params = build_query_param( + **{"language": language, "translate_text": translate_text} + ) path_params = { "feed_group_id": feed_group_id, "feed_id": feed_id, @@ -1552,6 +1718,7 @@ def query_pinned_activities( return self.post( "/api/v2/feeds/feed_groups/{feed_group_id}/feeds/{feed_id}/pinned_activities/query", QueryPinnedActivitiesResponse, + query_params=query_params, path_params=path_params, json=json, ) diff --git a/getstream/models/__init__.py b/getstream/models/__init__.py index 46ed1ff5..2cc2f407 100644 --- a/getstream/models/__init__.py +++ b/getstream/models/__init__.py @@ -9,6 +9,23 @@ from getstream.utils import encode_datetime, datetime_from_unix_ns +@dataclass +class AIAudioConfigRequest(DataClassJsonMixin): + profile: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="profile") + ) + rules: "Optional[List[BodyguardRule]]" = dc_field( + default=None, metadata=dc_config(field_name="rules") + ) + + +@dataclass +class AIAudioConfigResponse(DataClassJsonMixin): + enabled: bool = dc_field(metadata=dc_config(field_name="enabled")) + profile: str = dc_field(metadata=dc_config(field_name="profile")) + rules: "List[BodyguardRule]" = dc_field(metadata=dc_config(field_name="rules")) + + @dataclass class AIImageConfig(DataClassJsonMixin): _async: Optional[bool] = dc_field( @@ -1035,9 +1052,16 @@ class ActivityResponse(DataClassJsonMixin): friend_reactions: "Optional[List[FeedsReactionResponse]]" = dc_field( default=None, metadata=dc_config(field_name="friend_reactions") ) + # Recent shares of the activity, one entry per share (org-gated) + latest_shares: "Optional[List[ShareResponse]]" = dc_field( + default=None, metadata=dc_config(field_name="latest_shares") + ) current_feed: "Optional[FeedResponse]" = dc_field( default=None, metadata=dc_config(field_name="current_feed") ) + i18n: "Optional[Dict[str, str]]" = dc_field( + default=None, metadata=dc_config(field_name="i18n") + ) location: "Optional[Location]" = dc_field( default=None, metadata=dc_config(field_name="location") ) @@ -1419,6 +1443,10 @@ class AddCommentReactionRequest(DataClassJsonMixin): user_id: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="user_id") ) + # Optional list of feeds to create a reference (share) activity of the commented-on activity in. The reference activity's type mirrors the reaction type. + target_feeds: Optional[List[str]] = dc_field( + default=None, metadata=dc_config(field_name="target_feeds") + ) # Optional custom data to add to the reaction custom: Optional[Dict[str, object]] = dc_field( default=None, metadata=dc_config(field_name="custom") @@ -1436,10 +1464,22 @@ class AddCommentReactionResponse(DataClassJsonMixin): reaction: "FeedsReactionResponse" = dc_field( metadata=dc_config(field_name="reaction") ) - # Whether a notification activity was successfully created + # Whether notification creation was accepted for asynchronous processing + notification_accepted: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="notification_accepted") + ) + # Deprecated. Mirrors notification_accepted; use notification_accepted for async enqueue status Deprecated: use notification_accepted + # Deprecated notification_created: Optional[bool] = dc_field( default=None, metadata=dc_config(field_name="notification_created") ) + # ID of the async notification-creation task; poll GET /tasks/{id} for its status + notification_task_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="notification_task_id") + ) + reference_activity: "Optional[ActivityResponse]" = dc_field( + default=None, metadata=dc_config(field_name="reference_activity") + ) @dataclass @@ -1570,6 +1610,10 @@ class AddReactionRequest(DataClassJsonMixin): user_id: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="user_id") ) + # Optional list of feeds to create a reference (share) activity of the original activity in. The reference activity's type mirrors the reaction type. + target_feeds: Optional[List[str]] = dc_field( + default=None, metadata=dc_config(field_name="target_feeds") + ) # Custom data for the reaction custom: Optional[Dict[str, object]] = dc_field( default=None, metadata=dc_config(field_name="custom") @@ -1586,10 +1630,22 @@ class AddReactionResponse(DataClassJsonMixin): reaction: "FeedsReactionResponse" = dc_field( metadata=dc_config(field_name="reaction") ) - # Whether a notification activity was successfully created + # Whether notification creation was accepted for asynchronous processing + notification_accepted: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="notification_accepted") + ) + # Deprecated. Mirrors notification_accepted; use notification_accepted for async enqueue status Deprecated: use notification_accepted + # Deprecated notification_created: Optional[bool] = dc_field( default=None, metadata=dc_config(field_name="notification_created") ) + # ID of the async notification-creation task; poll GET /tasks/{id} for its status + notification_task_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="notification_task_id") + ) + reference_activity: "Optional[ActivityResponse]" = dc_field( + default=None, metadata=dc_config(field_name="reference_activity") + ) @dataclass @@ -2288,7 +2344,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.moderation_logs.error", metadata=dc_config(field_name="type") + default="export.users.error", metadata=dc_config(field_name="type") ) received_at: Optional[datetime] = dc_field( default=None, @@ -2344,6 +2400,49 @@ class AsyncExportModerationLogsEvent(DataClassJsonMixin): ) +@dataclass +class AsyncExportReviewQueueEvent(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"), + ) + ) + finished_at: datetime = dc_field( + metadata=dc_config( + field_name="finished_at", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ) + ) + started_at: datetime = dc_field( + metadata=dc_config( + field_name="started_at", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ) + ) + task_id: str = dc_field(metadata=dc_config(field_name="task_id")) + url: str = dc_field(metadata=dc_config(field_name="url")) + custom: Dict[str, object] = dc_field(metadata=dc_config(field_name="custom")) + type: str = dc_field( + default="export.review_queue.success", metadata=dc_config(field_name="type") + ) + 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"), + ), + ) + + @dataclass class AsyncExportUsersEvent(DataClassJsonMixin): created_at: datetime = dc_field( @@ -2819,6 +2918,78 @@ class BanResponse(DataClassJsonMixin): ) +@dataclass +class BatchQueryActivityReactionsRequest(DataClassJsonMixin): + # Activity IDs to fetch the user's reactions for (max 100) + activity_ids: List[str] = dc_field(metadata=dc_config(field_name="activity_ids")) + limit: Optional[int] = dc_field( + default=None, metadata=dc_config(field_name="limit") + ) + 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")) + # Server-side only. The user whose reactions to fetch; defaults to the authenticated user for client-side requests + user_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="user_id") + ) + sort: "Optional[List[SortParamRequest]]" = dc_field( + default=None, metadata=dc_config(field_name="sort") + ) + # Optional filter on reaction_type or created_at + filter: Optional[Dict[str, object]] = dc_field( + default=None, metadata=dc_config(field_name="filter") + ) + user: "Optional[UserRequest]" = dc_field( + default=None, metadata=dc_config(field_name="user") + ) + + +@dataclass +class BatchQueryActivityReactionsResponse(DataClassJsonMixin): + # Duration of the request in milliseconds + duration: str = dc_field(metadata=dc_config(field_name="duration")) + reactions: "List[FeedsReactionResponse]" = dc_field( + metadata=dc_config(field_name="reactions") + ) + 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")) + + +@dataclass +class BatchQueryCommentReactionsRequest(DataClassJsonMixin): + # Comment IDs to fetch the user's reactions for (max 100) + comment_ids: List[str] = dc_field(metadata=dc_config(field_name="comment_ids")) + limit: Optional[int] = dc_field( + default=None, metadata=dc_config(field_name="limit") + ) + 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")) + # Server-side only. The user whose reactions to fetch; defaults to the authenticated user for client-side requests + user_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="user_id") + ) + sort: "Optional[List[SortParamRequest]]" = dc_field( + default=None, metadata=dc_config(field_name="sort") + ) + # Optional filter on reaction_type or created_at + filter: Optional[Dict[str, object]] = dc_field( + default=None, metadata=dc_config(field_name="filter") + ) + user: "Optional[UserRequest]" = dc_field( + default=None, metadata=dc_config(field_name="user") + ) + + +@dataclass +class BatchQueryCommentReactionsResponse(DataClassJsonMixin): + # Duration of the request in milliseconds + duration: str = dc_field(metadata=dc_config(field_name="duration")) + reactions: "List[FeedsReactionResponse]" = dc_field( + metadata=dc_config(field_name="reactions") + ) + 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")) + + @dataclass class BlockActionRequestPayload(DataClassJsonMixin): # Reason for blocking @@ -7840,6 +8011,10 @@ class CheckResponse(DataClassJsonMixin): task_id: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="task_id") ) + # All moderation rules triggered by this check (content, user, and call rules), with their resolved actions + triggered_rules: "Optional[List[TriggeredRuleResponse]]" = dc_field( + default=None, metadata=dc_config(field_name="triggered_rules") + ) item: "Optional[ReviewQueueItemResponse]" = dc_field( default=None, metadata=dc_config(field_name="item") ) @@ -8092,6 +8267,9 @@ class ClosedCaptionEvent(DataClassJsonMixin): @dataclass class ClosedCaptionRuleParameters(DataClassJsonMixin): + severity: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="severity") + ) threshold: Optional[int] = dc_field( default=None, metadata=dc_config(field_name="threshold") ) @@ -8488,6 +8666,9 @@ class CommentResponse(DataClassJsonMixin): custom: Optional[Dict[str, object]] = dc_field( default=None, metadata=dc_config(field_name="custom") ) + i18n: "Optional[Dict[str, str]]" = dc_field( + default=None, metadata=dc_config(field_name="i18n") + ) moderation: "Optional[ModerationV2Response]" = dc_field( default=None, metadata=dc_config(field_name="moderation") ) @@ -8680,6 +8861,9 @@ class ConfigResponse(DataClassJsonMixin): available_bodyguard_profiles: "Optional[List[BodyguardProfileSummary]]" = dc_field( default=None, metadata=dc_config(field_name="available_bodyguard_profiles") ) + ai_audio_config: "Optional[AIAudioConfigResponse]" = dc_field( + default=None, metadata=dc_config(field_name="ai_audio_config") + ) ai_image_config: "Optional[AIImageConfig]" = dc_field( default=None, metadata=dc_config(field_name="ai_image_config") ) @@ -9511,6 +9695,27 @@ class CreatePollRequest(DataClassJsonMixin): ) +@dataclass +class CreateQueueRequest(DataClassJsonMixin): + name: str = dc_field(metadata=dc_config(field_name="name")) + type: str = dc_field(metadata=dc_config(field_name="type")) + description: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="description") + ) + user_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="user_id") + ) + sort: "Optional[List[Dict[str, object]]]" = dc_field( + default=None, metadata=dc_config(field_name="sort") + ) + filters: Optional[Dict[str, object]] = dc_field( + default=None, metadata=dc_config(field_name="filters") + ) + user: "Optional[UserRequest]" = dc_field( + default=None, metadata=dc_config(field_name="user") + ) + + @dataclass class CreateReminderRequest(DataClassJsonMixin): remind_at: Optional[datetime] = dc_field( @@ -10188,6 +10393,16 @@ class DeleteModerationTemplateResponse(DataClassJsonMixin): duration: str = dc_field(metadata=dc_config(field_name="duration")) +@dataclass +class DeleteQueueRequest(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 DeleteReactionRequestPayload(DataClassJsonMixin): # ID of the reaction to delete (alternative to item_id) @@ -12315,6 +12530,20 @@ class FeedsReactionResponse(DataClassJsonMixin): ) +@dataclass +class FeedsShareResponse(DataClassJsonMixin): + activity_id: str = dc_field(metadata=dc_config(field_name="activity_id")) + 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"), + ) + ) + user: "UserResponse" = dc_field(metadata=dc_config(field_name="user")) + + @dataclass class FeedsV3ActivityResponse(DataClassJsonMixin): bookmark_count: int = dc_field(metadata=dc_config(field_name="bookmark_count")) @@ -12429,9 +12658,15 @@ class FeedsV3ActivityResponse(DataClassJsonMixin): friend_reactions: "Optional[List[FeedsReactionResponse]]" = dc_field( default=None, metadata=dc_config(field_name="friend_reactions") ) + latest_shares: "Optional[List[FeedsShareResponse]]" = dc_field( + default=None, metadata=dc_config(field_name="latest_shares") + ) current_feed: "Optional[FeedsFeedResponse]" = dc_field( default=None, metadata=dc_config(field_name="current_feed") ) + i18n: "Optional[Dict[str, str]]" = dc_field( + default=None, metadata=dc_config(field_name="i18n") + ) location: "Optional[FeedsActivityLocation]" = dc_field( default=None, metadata=dc_config(field_name="location") ) @@ -12527,6 +12762,9 @@ class FeedsV3CommentResponse(DataClassJsonMixin): custom: Optional[Dict[str, object]] = dc_field( default=None, metadata=dc_config(field_name="custom") ) + i18n: "Optional[Dict[str, str]]" = dc_field( + default=None, metadata=dc_config(field_name="i18n") + ) moderation: "Optional[ModerationV2Response]" = dc_field( default=None, metadata=dc_config(field_name="moderation") ) @@ -12584,6 +12822,10 @@ class FileUploadResponse(DataClassJsonMixin): class FilterConfigResponse(DataClassJsonMixin): # LLM moderation labels available as filter values llm_labels: List[str] = dc_field(metadata=dc_config(field_name="llm_labels")) + # AI image moderation labels available as filter values. Reflects the app's effective image taxonomy: custom Bodyguard taxonomy when enabled, otherwise the standard L1 label set. + ai_image_labels: Optional[List[str]] = dc_field( + default=None, metadata=dc_config(field_name="ai_image_labels") + ) # AI text moderation labels available as filter values ai_text_labels: Optional[List[str]] = dc_field( default=None, metadata=dc_config(field_name="ai_text_labels") @@ -15544,6 +15786,15 @@ class ListPushProvidersResponse(DataClassJsonMixin): ) +@dataclass +class ListQueuesResponse(DataClassJsonMixin): + # Duration of the request in milliseconds + duration: str = dc_field(metadata=dc_config(field_name="duration")) + queues: "List[ModerationQueueResponse]" = dc_field( + metadata=dc_config(field_name="queues") + ) + + @dataclass class ListRecordingsResponse(DataClassJsonMixin): duration: str = dc_field(metadata=dc_config(field_name="duration")) @@ -17496,12 +17747,15 @@ class ModerationCustomActionEvent(DataClassJsonMixin): @dataclass class ModerationDashboardPreferences(DataClassJsonMixin): - analyze_max_image_size_bytes: Optional[int] = dc_field( - default=None, metadata=dc_config(field_name="analyze_max_image_size_bytes") - ) async_review_queue_upsert: Optional[bool] = dc_field( default=None, metadata=dc_config(field_name="async_review_queue_upsert") ) + block_foreign_cdn_attachments: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="block_foreign_cdn_attachments") + ) + custom_views_enabled: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="custom_views_enabled") + ) disable_audit_logs: Optional[bool] = dc_field( default=None, metadata=dc_config(field_name="disable_audit_logs") ) @@ -17520,10 +17774,6 @@ class ModerationDashboardPreferences(DataClassJsonMixin): media_queue_blur_enabled: Optional[bool] = dc_field( default=None, metadata=dc_config(field_name="media_queue_blur_enabled") ) - webhook_header_client_request_id_key: Optional[str] = dc_field( - default=None, - metadata=dc_config(field_name="webhook_header_client_request_id_key"), - ) allowed_moderation_action_reasons: Optional[List[str]] = dc_field( default=None, metadata=dc_config(field_name="allowed_moderation_action_reasons") ) @@ -17709,9 +17959,18 @@ class ModerationMarkReviewedEvent(DataClassJsonMixin): @dataclass class ModerationPayload(DataClassJsonMixin): + audios: Optional[List[str]] = dc_field( + default=None, metadata=dc_config(field_name="audios") + ) + image_ordered_keys: Optional[List[str]] = dc_field( + default=None, metadata=dc_config(field_name="image_ordered_keys") + ) images: Optional[List[str]] = dc_field( default=None, metadata=dc_config(field_name="images") ) + text_ordered_keys: Optional[List[str]] = dc_field( + default=None, metadata=dc_config(field_name="text_ordered_keys") + ) texts: Optional[List[str]] = dc_field( default=None, metadata=dc_config(field_name="texts") ) @@ -17721,10 +17980,20 @@ class ModerationPayload(DataClassJsonMixin): custom: Optional[Dict[str, object]] = dc_field( default=None, metadata=dc_config(field_name="custom") ) + image_ids: "Optional[Dict[str, str]]" = dc_field( + default=None, metadata=dc_config(field_name="image_ids") + ) + text_ids: "Optional[Dict[str, str]]" = dc_field( + default=None, metadata=dc_config(field_name="text_ids") + ) @dataclass class ModerationPayloadRequest(DataClassJsonMixin): + # Audio URLs to moderate + audios: Optional[List[str]] = dc_field( + default=None, metadata=dc_config(field_name="audios") + ) # Image URLs to moderate (max 30) images: Optional[List[str]] = dc_field( default=None, metadata=dc_config(field_name="images") @@ -17745,10 +18014,22 @@ class ModerationPayloadRequest(DataClassJsonMixin): @dataclass class ModerationPayloadResponse(DataClassJsonMixin): + # Audio URLs to moderate + audios: Optional[List[str]] = dc_field( + default=None, metadata=dc_config(field_name="audios") + ) + # Caller-supplied keys for images, index-aligned with images[] + image_ordered_keys: Optional[List[str]] = dc_field( + default=None, metadata=dc_config(field_name="image_ordered_keys") + ) # Image URLs to moderate images: Optional[List[str]] = dc_field( default=None, metadata=dc_config(field_name="images") ) + # Caller-supplied keys for texts (e.g. "title", "description"), index-aligned with texts[] + text_ordered_keys: Optional[List[str]] = dc_field( + default=None, metadata=dc_config(field_name="text_ordered_keys") + ) # Text content to moderate texts: Optional[List[str]] = dc_field( default=None, metadata=dc_config(field_name="texts") @@ -17761,6 +18042,42 @@ class ModerationPayloadResponse(DataClassJsonMixin): custom: Optional[Dict[str, object]] = dc_field( default=None, metadata=dc_config(field_name="custom") ) + # Caller-supplied content IDs per image key (from content_ids on /analyze) + image_ids: "Optional[Dict[str, str]]" = dc_field( + default=None, metadata=dc_config(field_name="image_ids") + ) + # Caller-supplied content IDs per text key (from content_ids on /analyze) + text_ids: "Optional[Dict[str, str]]" = dc_field( + default=None, metadata=dc_config(field_name="text_ids") + ) + + +@dataclass +class ModerationQueueResponse(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"), + ) + ) + created_by: str = dc_field(metadata=dc_config(field_name="created_by")) + description: str = dc_field(metadata=dc_config(field_name="description")) + id: str = dc_field(metadata=dc_config(field_name="id")) + item_count: int = dc_field(metadata=dc_config(field_name="item_count")) + name: str = dc_field(metadata=dc_config(field_name="name")) + type: str = dc_field(metadata=dc_config(field_name="type")) + updated_at: datetime = dc_field( + metadata=dc_config( + field_name="updated_at", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ) + ) + sort: "List[Dict[str, object]]" = dc_field(metadata=dc_config(field_name="sort")) + filters: Dict[str, object] = dc_field(metadata=dc_config(field_name="filters")) @dataclass @@ -18475,6 +18792,19 @@ class NotificationTrigger(DataClassJsonMixin): ) +@dataclass +class OCRContentParameters(DataClassJsonMixin): + label_operator: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="label_operator") + ) + severity: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="severity") + ) + harm_labels: Optional[List[str]] = dc_field( + default=None, metadata=dc_config(field_name="harm_labels") + ) + + @dataclass class OCRRule(DataClassJsonMixin): action: str = dc_field(metadata=dc_config(field_name="action")) @@ -18980,6 +19310,8 @@ class Permission(DataClassJsonMixin): name: str = dc_field(metadata=dc_config(field_name="name")) # Whether this permission applies to resource owner or not owner: bool = dc_field(metadata=dc_config(field_name="owner")) + # Resource type that defines ownership for this permission's action (e.g. 'Channel' for CreateMessage, 'Message' for UpdateMessage). Identical across all variants of an action; primarily meaningful for owner grants. + owner_resource: str = dc_field(metadata=dc_config(field_name="owner_resource")) # Whether this permission applies to teammates (multi-tenancy mode only) same_team: bool = dc_field(metadata=dc_config(field_name="same_team")) # List of tags of the permission @@ -19923,6 +20255,15 @@ class QueryActivityReactionsResponse(DataClassJsonMixin): prev: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="prev")) +@dataclass +class QueryActivitySharesResponse(DataClassJsonMixin): + # Duration of the request in milliseconds + duration: str = dc_field(metadata=dc_config(field_name="duration")) + shares: "List[ShareResponse]" = dc_field(metadata=dc_config(field_name="shares")) + 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")) + + @dataclass class QueryAggregateCallStatsRequest(DataClassJsonMixin): _from: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="from")) @@ -21085,7 +21426,7 @@ class QueryModerationRulesResponse(DataClassJsonMixin): keyframe_labels: List[str] = dc_field( metadata=dc_config(field_name="keyframe_labels") ) - # Available harm labels for keyframe OCR rules. Mirrors `closed_caption_labels` today but kept as a separate field so the two pickers can diverge later. + # Available harm labels for OCR-based rule conditions (keyframe_ocr_rule and ocr_content). Mirrors `closed_caption_labels` today but kept as a separate field so the pickers can diverge later. ocr_labels: List[str] = dc_field(metadata=dc_config(field_name="ocr_labels")) # List of moderation rules rules: "List[ModerationRuleV2Response]" = dc_field( @@ -21550,6 +21891,15 @@ class QueryUsersResponse(DataClassJsonMixin): users: "List[FullUserResponse]" = dc_field(metadata=dc_config(field_name="users")) +@dataclass +class QueueResponse(DataClassJsonMixin): + # Duration of the request in milliseconds + duration: str = dc_field(metadata=dc_config(field_name="duration")) + queue: "Optional[ModerationQueueResponse]" = dc_field( + default=None, metadata=dc_config(field_name="queue") + ) + + @dataclass class RTMPBroadcastRequest(DataClassJsonMixin): # Name identifier for RTMP broadcast, must be unique in call @@ -23042,6 +23392,9 @@ class RuleBuilderCondition(DataClassJsonMixin): keyframe_rule_params: "Optional[KeyframeRuleParameters]" = dc_field( default=None, metadata=dc_config(field_name="keyframe_rule_params") ) + ocr_content_params: "Optional[OCRContentParameters]" = dc_field( + default=None, metadata=dc_config(field_name="ocr_content_params") + ) text_content_params: "Optional[TextContentParameters]" = dc_field( default=None, metadata=dc_config(field_name="text_content_params") ) @@ -24125,6 +24478,22 @@ class ShadowBlockActionRequestPayload(DataClassJsonMixin): ) +@dataclass +class ShareResponse(DataClassJsonMixin): + # ID of the sharing (child) activity + activity_id: str = dc_field(metadata=dc_config(field_name="activity_id")) + # When the share occurred + 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"), + ) + ) + user: "UserResponse" = dc_field(metadata=dc_config(field_name="user")) + + @dataclass class SharedLocation(DataClassJsonMixin): latitude: float = dc_field(metadata=dc_config(field_name="latitude")) @@ -25261,6 +25630,9 @@ class ThreadedCommentResponse(DataClassJsonMixin): custom: Optional[Dict[str, object]] = dc_field( default=None, metadata=dc_config(field_name="custom") ) + i18n: "Optional[Dict[str, str]]" = dc_field( + default=None, metadata=dc_config(field_name="i18n") + ) meta: "Optional[RepliesMeta]" = dc_field( default=None, metadata=dc_config(field_name="meta") ) @@ -25416,6 +25788,32 @@ class TranscriptionSettingsResponse(DataClassJsonMixin): ) +@dataclass +class TranslateActivityRequest(DataClassJsonMixin): + # ISO 639-1 language code to translate to + language: str = dc_field(metadata=dc_config(field_name="language")) + + +@dataclass +class TranslateActivityResponse(DataClassJsonMixin): + # Duration of the request in milliseconds + duration: str = dc_field(metadata=dc_config(field_name="duration")) + activity: "ActivityResponse" = dc_field(metadata=dc_config(field_name="activity")) + + +@dataclass +class TranslateCommentRequest(DataClassJsonMixin): + # ISO 639-1 language code to translate to + language: str = dc_field(metadata=dc_config(field_name="language")) + + +@dataclass +class TranslateCommentResponse(DataClassJsonMixin): + # Duration of the request in milliseconds + duration: str = dc_field(metadata=dc_config(field_name="duration")) + comment: "CommentResponse" = dc_field(metadata=dc_config(field_name="comment")) + + @dataclass class TranslateMessageRequest(DataClassJsonMixin): # Language to translate message to @@ -25442,6 +25840,8 @@ class TriggeredRuleResponse(DataClassJsonMixin): rule_name: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="rule_name") ) + # Type of the moderation rule that triggered (content, user, or call) + type: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="type")) # Violation count for action sequence rules (1-based) violation_number: Optional[int] = dc_field( default=None, metadata=dc_config(field_name="violation_number") @@ -26010,6 +26410,9 @@ class UpdateAppRequest(DataClassJsonMixin): enforce_unique_usernames: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="enforce_unique_usernames") ) + feed_audit_logs_enabled: Optional[bool] = dc_field( + default=None, metadata=dc_config(field_name="feed_audit_logs_enabled") + ) feeds_moderation_enabled: Optional[bool] = dc_field( default=None, metadata=dc_config(field_name="feeds_moderation_enabled") ) @@ -26056,6 +26459,9 @@ class UpdateAppRequest(DataClassJsonMixin): reminders_max_members: Optional[int] = dc_field( default=None, metadata=dc_config(field_name="reminders_max_members") ) + reminders_max_per_user: Optional[int] = dc_field( + default=None, metadata=dc_config(field_name="reminders_max_per_user") + ) revoke_tokens_issued_before: Optional[datetime] = dc_field( default=None, metadata=dc_config( @@ -27321,6 +27727,26 @@ class UpdatePollRequest(DataClassJsonMixin): ) +@dataclass +class UpdateQueueRequest(DataClassJsonMixin): + description: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="description") + ) + name: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="name")) + user_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="user_id") + ) + sort: "Optional[List[Dict[str, object]]]" = dc_field( + default=None, metadata=dc_config(field_name="sort") + ) + filters: Optional[Dict[str, object]] = dc_field( + default=None, metadata=dc_config(field_name="filters") + ) + user: "Optional[UserRequest]" = dc_field( + default=None, metadata=dc_config(field_name="user") + ) + + @dataclass class UpdateReminderRequest(DataClassJsonMixin): remind_at: Optional[datetime] = dc_field( @@ -27732,6 +28158,9 @@ class UpsertConfigRequest(DataClassJsonMixin): user_id: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="user_id") ) + ai_audio_config: "Optional[AIAudioConfigRequest]" = dc_field( + default=None, metadata=dc_config(field_name="ai_audio_config") + ) ai_image_config: "Optional[AIImageConfig]" = dc_field( default=None, metadata=dc_config(field_name="ai_image_config") ) diff --git a/getstream/moderation/async_rest_client.py b/getstream/moderation/async_rest_client.py index 473fba30..69b34063 100644 --- a/getstream/moderation/async_rest_client.py +++ b/getstream/moderation/async_rest_client.py @@ -367,6 +367,7 @@ async def upsert_config( _async: Optional[bool] = None, team: Optional[str] = None, user_id: Optional[str] = None, + ai_audio_config: Optional[AIAudioConfigRequest] = None, ai_image_config: Optional[AIImageConfig] = None, ai_text_config: Optional[AITextConfig] = None, ai_video_config: Optional[AIVideoConfig] = None, @@ -391,6 +392,7 @@ async def upsert_config( _async=_async, team=team, user_id=user_id, + ai_audio_config=ai_audio_config, ai_image_config=ai_image_config, ai_text_config=ai_text_config, ai_video_config=ai_video_config, @@ -736,6 +738,91 @@ async def mute( ).to_dict() return await self.post("/api/v2/moderation/mute", MuteResponse, json=json) + @telemetry.operation_name("getstream.api.moderation.list_queues") + async def list_queues(self) -> StreamResponse[ListQueuesResponse]: + return await self.get("/api/v2/moderation/queues", ListQueuesResponse) + + @telemetry.operation_name("getstream.api.moderation.create_queue") + async def create_queue( + self, + name: str, + type: str, + description: Optional[str] = None, + user_id: Optional[str] = None, + sort: Optional[List[Dict[str, object]]] = None, + filters: Optional[Dict[str, object]] = None, + user: Optional[UserRequest] = None, + ) -> StreamResponse[QueueResponse]: + json = CreateQueueRequest( + name=name, + type=type, + description=description, + user_id=user_id, + sort=sort, + filters=filters, + user=user, + ).to_dict() + return await self.post("/api/v2/moderation/queues", QueueResponse, json=json) + + @telemetry.operation_name("getstream.api.moderation.get_queue") + async def get_queue( + self, id: str, user_id: Optional[str] = None + ) -> StreamResponse[QueueResponse]: + query_params = build_query_param(**{"user_id": user_id}) + path_params = { + "id": id, + } + return await self.get( + "/api/v2/moderation/queues/{id}", + QueueResponse, + query_params=query_params, + path_params=path_params, + ) + + @telemetry.operation_name("getstream.api.moderation.update_queue") + async def update_queue( + self, + id: str, + description: Optional[str] = None, + name: Optional[str] = None, + user_id: Optional[str] = None, + sort: Optional[List[Dict[str, object]]] = None, + filters: Optional[Dict[str, object]] = None, + user: Optional[UserRequest] = None, + ) -> StreamResponse[QueueResponse]: + path_params = { + "id": id, + } + json = UpdateQueueRequest( + description=description, + name=name, + user_id=user_id, + sort=sort, + filters=filters, + user=user, + ).to_dict() + return await self.patch( + "/api/v2/moderation/queues/{id}", + QueueResponse, + path_params=path_params, + json=json, + ) + + @telemetry.operation_name("getstream.api.moderation.delete_queue") + async def delete_queue( + self, id: str, user_id: Optional[str] = None, user: Optional[UserRequest] = None + ) -> StreamResponse[QueueResponse]: + path_params = { + "id": id, + } + json = DeleteQueueRequest(user_id=user_id, user=user).to_dict() + return await self.post( + "/api/v2/moderation/queues/{id}/delete", + QueueResponse, + path_params=path_params, + json=json, + ) + @telemetry.operation_name("getstream.api.moderation.query_review_queue") async def query_review_queue( self, diff --git a/getstream/moderation/rest_client.py b/getstream/moderation/rest_client.py index 79e7654d..822d26aa 100644 --- a/getstream/moderation/rest_client.py +++ b/getstream/moderation/rest_client.py @@ -363,6 +363,7 @@ def upsert_config( _async: Optional[bool] = None, team: Optional[str] = None, user_id: Optional[str] = None, + ai_audio_config: Optional[AIAudioConfigRequest] = None, ai_image_config: Optional[AIImageConfig] = None, ai_text_config: Optional[AITextConfig] = None, ai_video_config: Optional[AIVideoConfig] = None, @@ -387,6 +388,7 @@ def upsert_config( _async=_async, team=team, user_id=user_id, + ai_audio_config=ai_audio_config, ai_image_config=ai_image_config, ai_text_config=ai_text_config, ai_video_config=ai_video_config, @@ -728,6 +730,91 @@ def mute( ).to_dict() return self.post("/api/v2/moderation/mute", MuteResponse, json=json) + @telemetry.operation_name("getstream.api.moderation.list_queues") + def list_queues(self) -> StreamResponse[ListQueuesResponse]: + return self.get("/api/v2/moderation/queues", ListQueuesResponse) + + @telemetry.operation_name("getstream.api.moderation.create_queue") + def create_queue( + self, + name: str, + type: str, + description: Optional[str] = None, + user_id: Optional[str] = None, + sort: Optional[List[Dict[str, object]]] = None, + filters: Optional[Dict[str, object]] = None, + user: Optional[UserRequest] = None, + ) -> StreamResponse[QueueResponse]: + json = CreateQueueRequest( + name=name, + type=type, + description=description, + user_id=user_id, + sort=sort, + filters=filters, + user=user, + ).to_dict() + return self.post("/api/v2/moderation/queues", QueueResponse, json=json) + + @telemetry.operation_name("getstream.api.moderation.get_queue") + def get_queue( + self, id: str, user_id: Optional[str] = None + ) -> StreamResponse[QueueResponse]: + query_params = build_query_param(**{"user_id": user_id}) + path_params = { + "id": id, + } + return self.get( + "/api/v2/moderation/queues/{id}", + QueueResponse, + query_params=query_params, + path_params=path_params, + ) + + @telemetry.operation_name("getstream.api.moderation.update_queue") + def update_queue( + self, + id: str, + description: Optional[str] = None, + name: Optional[str] = None, + user_id: Optional[str] = None, + sort: Optional[List[Dict[str, object]]] = None, + filters: Optional[Dict[str, object]] = None, + user: Optional[UserRequest] = None, + ) -> StreamResponse[QueueResponse]: + path_params = { + "id": id, + } + json = UpdateQueueRequest( + description=description, + name=name, + user_id=user_id, + sort=sort, + filters=filters, + user=user, + ).to_dict() + return self.patch( + "/api/v2/moderation/queues/{id}", + QueueResponse, + path_params=path_params, + json=json, + ) + + @telemetry.operation_name("getstream.api.moderation.delete_queue") + def delete_queue( + self, id: str, user_id: Optional[str] = None, user: Optional[UserRequest] = None + ) -> StreamResponse[QueueResponse]: + path_params = { + "id": id, + } + json = DeleteQueueRequest(user_id=user_id, user=user).to_dict() + return self.post( + "/api/v2/moderation/queues/{id}/delete", + QueueResponse, + path_params=path_params, + json=json, + ) + @telemetry.operation_name("getstream.api.moderation.query_review_queue") def query_review_queue( self, diff --git a/getstream/tests/test_webhook.py b/getstream/tests/test_webhook.py index 22efe542..c7df02f3 100644 --- a/getstream/tests/test_webhook.py +++ b/getstream/tests/test_webhook.py @@ -564,6 +564,18 @@ def test_parse_export_moderation_logs_success(self): event = parse_webhook_event({"type": "export.moderation_logs.success"}) assert type(event).__name__ == "AsyncExportModerationLogsEvent" + def test_parse_export_review_queue_error(self): + with warnings.catch_warnings(): + warnings.simplefilter("ignore", RuntimeWarning) + event = parse_webhook_event({"type": "export.review_queue.error"}) + assert type(event).__name__ == "AsyncExportErrorEvent" + + def test_parse_export_review_queue_success(self): + with warnings.catch_warnings(): + warnings.simplefilter("ignore", RuntimeWarning) + event = parse_webhook_event({"type": "export.review_queue.success"}) + assert type(event).__name__ == "AsyncExportReviewQueueEvent" + def test_parse_export_users_error(self): with warnings.catch_warnings(): warnings.simplefilter("ignore", RuntimeWarning) diff --git a/getstream/webhook.py b/getstream/webhook.py index 4fb449d6..f21a4e1f 100644 --- a/getstream/webhook.py +++ b/getstream/webhook.py @@ -86,6 +86,7 @@ AsyncBulkImageModerationEvent, AsyncExportChannelsEvent, AsyncExportModerationLogsEvent, + AsyncExportReviewQueueEvent, AsyncExportErrorEvent, AsyncExportUsersEvent, ActivityAddedEvent, @@ -261,6 +262,8 @@ EVENT_TYPE_EXPORT_CHANNELS_SUCCESS = "export.channels.success" EVENT_TYPE_EXPORT_MODERATION_LOGS_ERROR = "export.moderation_logs.error" EVENT_TYPE_EXPORT_MODERATION_LOGS_SUCCESS = "export.moderation_logs.success" +EVENT_TYPE_EXPORT_REVIEW_QUEUE_ERROR = "export.review_queue.error" +EVENT_TYPE_EXPORT_REVIEW_QUEUE_SUCCESS = "export.review_queue.success" EVENT_TYPE_EXPORT_USERS_ERROR = "export.users.error" EVENT_TYPE_EXPORT_USERS_SUCCESS = "export.users.success" EVENT_TYPE_FEEDS_ACTIVITY_ADDED = "feeds.activity.added" @@ -526,6 +529,8 @@ def _get_event_class(event_type: str): "export.channels.success": AsyncExportChannelsEvent, "export.moderation_logs.error": AsyncExportErrorEvent, "export.moderation_logs.success": AsyncExportModerationLogsEvent, + "export.review_queue.error": AsyncExportErrorEvent, + "export.review_queue.success": AsyncExportReviewQueueEvent, "export.users.error": AsyncExportErrorEvent, "export.users.success": AsyncExportUsersEvent, "feeds.activity.added": ActivityAddedEvent,