diff --git a/.github/workflows/initiate_release.yml b/.github/workflows/initiate_release.yml index ab50fd8..3362a04 100644 --- a/.github/workflows/initiate_release.yml +++ b/.github/workflows/initiate_release.yml @@ -37,6 +37,7 @@ jobs: run: | gh pr create \ -t "Release ${{ github.event.inputs.version }}" \ + -l "ignore-for-release" \ -b "# :rocket: ${{ github.event.inputs.version }} Make sure to use squash & merge when merging! Once this is merged, another job will kick off automatically and publish the package." diff --git a/README.md b/README.md index b578292..f34b095 100644 --- a/README.md +++ b/README.md @@ -32,24 +32,14 @@ client = Stream(api_key="your_api_key", api_secret="your_api_secret") from getstream.models import UserRequest # sync two users using the update_users method, both users will get insert or updated -client.update_users(users={ - "tommaso-id": UserRequest( - id="tommaso-id", - name="tommaso", - role="admin", - custom={ - "country": "NL" - } +client.upsert_users( + UserRequest( + id="tommaso-id", name="tommaso", role="admin", custom={"country": "NL"} ), - "thierry-id": UserRequest( - id="thierry-id", - name="thierry", - role="admin", - custom={ - "country": "US" - } + UserRequest( + id="thierry-id", name="thierry", role="admin", custom={"country": "US"} ), -}) +) # Create a JWT token for the user to connect client-side (e.g. browser/mobile app) token = client.create_token("tommaso-id") diff --git a/getstream/chat/rest_client.py b/getstream/chat/rest_client.py index 3249507..5490560 100644 --- a/getstream/chat/rest_client.py +++ b/getstream/chat/rest_client.py @@ -923,6 +923,37 @@ def get_reactions( path_params=path_params, ) + def query_reactions( + self, + id: str, + limit: Optional[int] = None, + next: Optional[str] = None, + prev: Optional[str] = None, + user_id: Optional[str] = None, + sort: Optional[List[Optional[SortParam]]] = None, + filter: Optional[Dict[str, object]] = None, + user: Optional[UserRequest] = None, + ) -> StreamResponse[QueryReactionsResponse]: + path_params = { + "id": id, + } + json = build_body_dict( + limit=limit, + next=next, + prev=prev, + user_id=user_id, + sort=sort, + filter=filter, + user=user, + ) + + return self.post( + "/api/v2/chat/messages/{id}/reactions", + QueryReactionsResponse, + path_params=path_params, + json=json, + ) + def translate_message( self, id: str, language: str ) -> StreamResponse[MessageResponse]: diff --git a/getstream/models/__init__.py b/getstream/models/__init__.py index 2921f8d..753b27b 100644 --- a/getstream/models/__init__.py +++ b/getstream/models/__init__.py @@ -2828,10 +2828,14 @@ class GeofenceSettingsResponse(DataClassJsonMixin): @dataclass class GeolocationResult(DataClassJsonMixin): accuracy_radius: int = dc_field(metadata=dc_config(field_name="accuracy_radius")) + city: str = dc_field(metadata=dc_config(field_name="city")) + continent: str = dc_field(metadata=dc_config(field_name="continent")) continent_code: str = dc_field(metadata=dc_config(field_name="continent_code")) + country: str = dc_field(metadata=dc_config(field_name="country")) country_iso_code: str = dc_field(metadata=dc_config(field_name="country_iso_code")) latitude: float = dc_field(metadata=dc_config(field_name="latitude")) longitude: float = dc_field(metadata=dc_config(field_name="longitude")) + subdivision: str = dc_field(metadata=dc_config(field_name="subdivision")) subdivision_iso_code: str = dc_field( metadata=dc_config(field_name="subdivision_iso_code") ) @@ -3558,6 +3562,16 @@ class Location(DataClassJsonMixin): ) +@dataclass +class MOSStats(DataClassJsonMixin): + average_score: float = dc_field(metadata=dc_config(field_name="average_score")) + max_score: float = dc_field(metadata=dc_config(field_name="max_score")) + min_score: float = dc_field(metadata=dc_config(field_name="min_score")) + hist_og_ram_duration_seconds: "List[float]" = dc_field( + metadata=dc_config(field_name="histogram_duration_seconds") + ) + + @dataclass class MarkChannelsReadRequest(DataClassJsonMixin): user_id: Optional[str] = dc_field( @@ -3678,7 +3692,6 @@ class Message(DataClassJsonMixin): html: str = dc_field(metadata=dc_config(field_name="html")) id: str = dc_field(metadata=dc_config(field_name="id")) pinned: bool = dc_field(metadata=dc_config(field_name="pinned")) - poll_id: str = dc_field(metadata=dc_config(field_name="poll_id")) reply_count: int = dc_field(metadata=dc_config(field_name="reply_count")) shadowed: bool = dc_field(metadata=dc_config(field_name="shadowed")) silent: bool = dc_field(metadata=dc_config(field_name="silent")) @@ -3708,6 +3721,9 @@ class Message(DataClassJsonMixin): reaction_counts: "Dict[str, int]" = dc_field( metadata=dc_config(field_name="reaction_counts") ) + reaction_groups: "Dict[str, Optional[ReactionGroupResponse]]" = dc_field( + metadata=dc_config(field_name="reaction_groups") + ) reaction_scores: "Dict[str, int]" = dc_field( metadata=dc_config(field_name="reaction_scores") ) @@ -3757,6 +3773,9 @@ class Message(DataClassJsonMixin): mm_field=fields.DateTime(format="iso"), ), ) + poll_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="poll_id") + ) quoted_message_id: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="quoted_message_id") ) @@ -3929,66 +3948,6 @@ class MessageModerationResult(DataClassJsonMixin): @dataclass class MessagePaginationParams(DataClassJsonMixin): - created_at_after: Optional[datetime] = dc_field( - default=None, - metadata=dc_config( - field_name="created_at_after", - encoder=encode_datetime, - decoder=datetime_from_unix_ns, - mm_field=fields.DateTime(format="iso"), - ), - ) - created_at_after_or_equal: Optional[datetime] = dc_field( - default=None, - metadata=dc_config( - field_name="created_at_after_or_equal", - encoder=encode_datetime, - decoder=datetime_from_unix_ns, - mm_field=fields.DateTime(format="iso"), - ), - ) - created_at_around: Optional[datetime] = dc_field( - default=None, - metadata=dc_config( - field_name="created_at_around", - encoder=encode_datetime, - decoder=datetime_from_unix_ns, - mm_field=fields.DateTime(format="iso"), - ), - ) - created_at_before: Optional[datetime] = dc_field( - default=None, - metadata=dc_config( - field_name="created_at_before", - encoder=encode_datetime, - decoder=datetime_from_unix_ns, - mm_field=fields.DateTime(format="iso"), - ), - ) - created_at_before_or_equal: Optional[datetime] = dc_field( - default=None, - metadata=dc_config( - field_name="created_at_before_or_equal", - encoder=encode_datetime, - decoder=datetime_from_unix_ns, - mm_field=fields.DateTime(format="iso"), - ), - ) - id_around: Optional[str] = dc_field( - default=None, metadata=dc_config(field_name="id_around") - ) - id_gt: Optional[str] = dc_field( - default=None, metadata=dc_config(field_name="id_gt") - ) - id_gte: Optional[str] = dc_field( - default=None, metadata=dc_config(field_name="id_gte") - ) - id_lt: Optional[str] = dc_field( - default=None, metadata=dc_config(field_name="id_lt") - ) - id_lte: Optional[str] = dc_field( - default=None, metadata=dc_config(field_name="id_lte") - ) limit: Optional[int] = dc_field( default=None, metadata=dc_config(field_name="limit") ) @@ -4100,7 +4059,6 @@ class MessageResponse(DataClassJsonMixin): html: str = dc_field(metadata=dc_config(field_name="html")) id: str = dc_field(metadata=dc_config(field_name="id")) pinned: bool = dc_field(metadata=dc_config(field_name="pinned")) - poll_id: str = dc_field(metadata=dc_config(field_name="poll_id")) reply_count: int = dc_field(metadata=dc_config(field_name="reply_count")) shadowed: bool = dc_field(metadata=dc_config(field_name="shadowed")) silent: bool = dc_field(metadata=dc_config(field_name="silent")) @@ -4177,6 +4135,9 @@ class MessageResponse(DataClassJsonMixin): mm_field=fields.DateTime(format="iso"), ), ) + poll_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="poll_id") + ) quoted_message_id: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="quoted_message_id") ) @@ -4201,6 +4162,9 @@ class MessageResponse(DataClassJsonMixin): quoted_message: "Optional[Message]" = dc_field( default=None, metadata=dc_config(field_name="quoted_message") ) + reaction_groups: "Optional[Dict[str, Optional[ReactionGroupResponse]]]" = dc_field( + default=None, metadata=dc_config(field_name="reaction_groups") + ) @dataclass @@ -4230,7 +4194,6 @@ class MessageWithChannelResponse(DataClassJsonMixin): html: str = dc_field(metadata=dc_config(field_name="html")) id: str = dc_field(metadata=dc_config(field_name="id")) pinned: bool = dc_field(metadata=dc_config(field_name="pinned")) - poll_id: str = dc_field(metadata=dc_config(field_name="poll_id")) reply_count: int = dc_field(metadata=dc_config(field_name="reply_count")) shadowed: bool = dc_field(metadata=dc_config(field_name="shadowed")) silent: bool = dc_field(metadata=dc_config(field_name="silent")) @@ -4308,6 +4271,9 @@ class MessageWithChannelResponse(DataClassJsonMixin): mm_field=fields.DateTime(format="iso"), ), ) + poll_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="poll_id") + ) quoted_message_id: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="quoted_message_id") ) @@ -4332,6 +4298,9 @@ class MessageWithChannelResponse(DataClassJsonMixin): quoted_message: "Optional[Message]" = dc_field( default=None, metadata=dc_config(field_name="quoted_message") ) + reaction_groups: "Optional[Dict[str, Optional[ReactionGroupResponse]]]" = dc_field( + default=None, metadata=dc_config(field_name="reaction_groups") + ) @dataclass @@ -4594,18 +4563,6 @@ class OwnUser(DataClassJsonMixin): @dataclass class PaginationParams(DataClassJsonMixin): - id_gt: Optional[int] = dc_field( - default=None, metadata=dc_config(field_name="id_gt") - ) - id_gte: Optional[int] = dc_field( - default=None, metadata=dc_config(field_name="id_gte") - ) - id_lt: Optional[int] = dc_field( - default=None, metadata=dc_config(field_name="id_lt") - ) - id_lte: Optional[int] = dc_field( - default=None, metadata=dc_config(field_name="id_lte") - ) limit: Optional[int] = dc_field( default=None, metadata=dc_config(field_name="limit") ) @@ -5184,42 +5141,6 @@ class QueryBannedUsersRequest(DataClassJsonMixin): filter_conditions: Dict[str, object] = dc_field( metadata=dc_config(field_name="filter_conditions") ) - created_at_after: Optional[datetime] = dc_field( - default=None, - metadata=dc_config( - field_name="created_at_after", - encoder=encode_datetime, - decoder=datetime_from_unix_ns, - mm_field=fields.DateTime(format="iso"), - ), - ) - created_at_after_or_equal: Optional[datetime] = dc_field( - default=None, - metadata=dc_config( - field_name="created_at_after_or_equal", - encoder=encode_datetime, - decoder=datetime_from_unix_ns, - mm_field=fields.DateTime(format="iso"), - ), - ) - created_at_before: Optional[datetime] = dc_field( - default=None, - metadata=dc_config( - field_name="created_at_before", - encoder=encode_datetime, - decoder=datetime_from_unix_ns, - mm_field=fields.DateTime(format="iso"), - ), - ) - created_at_before_or_equal: Optional[datetime] = dc_field( - default=None, - metadata=dc_config( - field_name="created_at_before_or_equal", - encoder=encode_datetime, - decoder=datetime_from_unix_ns, - mm_field=fields.DateTime(format="iso"), - ), - ) exclude_expired_bans: Optional[bool] = dc_field( default=None, metadata=dc_config(field_name="exclude_expired_bans") ) @@ -5305,9 +5226,6 @@ class QueryCallsRequest(DataClassJsonMixin): ) 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")) - watch: Optional[bool] = dc_field( - default=None, metadata=dc_config(field_name="watch") - ) sort: "Optional[List[Optional[SortParam]]]" = dc_field( default=None, metadata=dc_config(field_name="sort") ) @@ -5371,42 +5289,6 @@ class QueryMembersRequest(DataClassJsonMixin): filter_conditions: Dict[str, object] = dc_field( metadata=dc_config(field_name="filter_conditions") ) - created_at_after: Optional[datetime] = dc_field( - default=None, - metadata=dc_config( - field_name="created_at_after", - encoder=encode_datetime, - decoder=datetime_from_unix_ns, - mm_field=fields.DateTime(format="iso"), - ), - ) - created_at_after_or_equal: Optional[datetime] = dc_field( - default=None, - metadata=dc_config( - field_name="created_at_after_or_equal", - encoder=encode_datetime, - decoder=datetime_from_unix_ns, - mm_field=fields.DateTime(format="iso"), - ), - ) - created_at_before: Optional[datetime] = dc_field( - default=None, - metadata=dc_config( - field_name="created_at_before", - encoder=encode_datetime, - decoder=datetime_from_unix_ns, - mm_field=fields.DateTime(format="iso"), - ), - ) - created_at_before_or_equal: Optional[datetime] = dc_field( - default=None, - metadata=dc_config( - field_name="created_at_before_or_equal", - encoder=encode_datetime, - decoder=datetime_from_unix_ns, - mm_field=fields.DateTime(format="iso"), - ), - ) id: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="id")) limit: Optional[int] = dc_field( default=None, metadata=dc_config(field_name="limit") @@ -5417,18 +5299,6 @@ class QueryMembersRequest(DataClassJsonMixin): user_id: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="user_id") ) - user_id_gt: Optional[str] = dc_field( - default=None, metadata=dc_config(field_name="user_id_gt") - ) - user_id_gte: Optional[str] = dc_field( - default=None, metadata=dc_config(field_name="user_id_gte") - ) - user_id_lt: Optional[str] = dc_field( - default=None, metadata=dc_config(field_name="user_id_lt") - ) - user_id_lte: Optional[str] = dc_field( - default=None, metadata=dc_config(field_name="user_id_lte") - ) members: "Optional[List[Optional[ChannelMember]]]" = dc_field( default=None, metadata=dc_config(field_name="members") ) @@ -5511,6 +5381,37 @@ class QueryPollsResponse(DataClassJsonMixin): prev: Optional[str] = dc_field(default=None, metadata=dc_config(field_name="prev")) +@dataclass +class QueryReactionsRequest(DataClassJsonMixin): + 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")) + user_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="user_id") + ) + sort: "Optional[List[Optional[SortParam]]]" = dc_field( + default=None, metadata=dc_config(field_name="sort") + ) + 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 QueryReactionsResponse(DataClassJsonMixin): + duration: str = dc_field(metadata=dc_config(field_name="duration")) + reactions: "List[ReactionResponse]" = 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 QueryThreadsRequest(DataClassJsonMixin): limit: Optional[int] = dc_field( @@ -5547,18 +5448,6 @@ class QueryUsersPayload(DataClassJsonMixin): filter_conditions: Dict[str, object] = dc_field( metadata=dc_config(field_name="filter_conditions") ) - id_gt: Optional[str] = dc_field( - default=None, metadata=dc_config(field_name="id_gt") - ) - id_gte: Optional[str] = dc_field( - default=None, metadata=dc_config(field_name="id_gte") - ) - id_lt: Optional[str] = dc_field( - default=None, metadata=dc_config(field_name="id_lt") - ) - id_lte: Optional[str] = dc_field( - default=None, metadata=dc_config(field_name="id_lte") - ) include_deactivated_users: Optional[bool] = dc_field( default=None, metadata=dc_config(field_name="include_deactivated_users") ) @@ -5623,6 +5512,28 @@ class Reaction(DataClassJsonMixin): ) +@dataclass +class ReactionGroupResponse(DataClassJsonMixin): + count: int = dc_field(metadata=dc_config(field_name="count")) + first_reaction_at: datetime = dc_field( + metadata=dc_config( + field_name="first_reaction_at", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ) + ) + last_reaction_at: datetime = dc_field( + metadata=dc_config( + field_name="last_reaction_at", + encoder=encode_datetime, + decoder=datetime_from_unix_ns, + mm_field=fields.DateTime(format="iso"), + ) + ) + sum_scores: int = dc_field(metadata=dc_config(field_name="sum_scores")) + + @dataclass class ReactionRemovalResponse(DataClassJsonMixin): duration: str = dc_field(metadata=dc_config(field_name="duration")) @@ -5979,7 +5890,6 @@ class SearchResultMessage(DataClassJsonMixin): html: str = dc_field(metadata=dc_config(field_name="html")) id: str = dc_field(metadata=dc_config(field_name="id")) pinned: bool = dc_field(metadata=dc_config(field_name="pinned")) - poll_id: str = dc_field(metadata=dc_config(field_name="poll_id")) reply_count: int = dc_field(metadata=dc_config(field_name="reply_count")) shadowed: bool = dc_field(metadata=dc_config(field_name="shadowed")) silent: bool = dc_field(metadata=dc_config(field_name="silent")) @@ -6009,6 +5919,9 @@ class SearchResultMessage(DataClassJsonMixin): reaction_counts: "Dict[str, int]" = dc_field( metadata=dc_config(field_name="reaction_counts") ) + reaction_groups: "Dict[str, Optional[ReactionGroupResponse]]" = dc_field( + metadata=dc_config(field_name="reaction_groups") + ) reaction_scores: "Dict[str, int]" = dc_field( metadata=dc_config(field_name="reaction_scores") ) @@ -6058,6 +5971,9 @@ class SearchResultMessage(DataClassJsonMixin): mm_field=fields.DateTime(format="iso"), ), ) + poll_id: Optional[str] = dc_field( + default=None, metadata=dc_config(field_name="poll_id") + ) quoted_message_id: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="quoted_message_id") ) @@ -7519,6 +7435,9 @@ class UpdateUsersRequest(DataClassJsonMixin): @dataclass class UpdateUsersResponse(DataClassJsonMixin): duration: str = dc_field(metadata=dc_config(field_name="duration")) + membership_deletion_task_id: str = dc_field( + metadata=dc_config(field_name="membership_deletion_task_id") + ) users: "Dict[str, FullUserResponse]" = dc_field( metadata=dc_config(field_name="users") ) @@ -7781,6 +7700,12 @@ class UserSessionStats(DataClassJsonMixin): freeze_duration_seconds: int = dc_field( metadata=dc_config(field_name="freeze_duration_seconds") ) + max_freeze_fraction: float = dc_field( + metadata=dc_config(field_name="max_freeze_fraction") + ) + max_freezes_duration_seconds: int = dc_field( + metadata=dc_config(field_name="max_freezes_duration_seconds") + ) packet_loss_fraction: float = dc_field( metadata=dc_config(field_name="packet_loss_fraction") ) @@ -7812,6 +7737,9 @@ class UserSessionStats(DataClassJsonMixin): device_version: Optional[str] = dc_field( default=None, metadata=dc_config(field_name="device_version") ) + distance_to_sfu_kilometers: Optional[float] = dc_field( + default=None, metadata=dc_config(field_name="distance_to_sfu_kilometers") + ) max_fir_per_second: Optional[float] = dc_field( default=None, metadata=dc_config(field_name="max_fir_per_second") ) @@ -7859,6 +7787,12 @@ class UserSessionStats(DataClassJsonMixin): max_receiving_video_quality: "Optional[VideoQuality]" = dc_field( default=None, metadata=dc_config(field_name="max_receiving_video_quality") ) + publisher_audio_mos: "Optional[MOSStats]" = dc_field( + default=None, metadata=dc_config(field_name="publisher_audio_mos") + ) + subscriber_audio_mos: "Optional[MOSStats]" = dc_field( + default=None, metadata=dc_config(field_name="subscriber_audio_mos") + ) timeline: "Optional[CallTimeline]" = dc_field( default=None, metadata=dc_config(field_name="timeline") ) diff --git a/getstream/stream.py b/getstream/stream.py index ba287a9..ab7f74e 100644 --- a/getstream/stream.py +++ b/getstream/stream.py @@ -5,6 +5,7 @@ from getstream.chat.client import ChatClient from getstream.common.client import CommonClient +from getstream.models import UserRequest from getstream.utils import validate_and_clean_url from getstream.video.client import VideoClient @@ -67,6 +68,15 @@ def chat(self): timeout=self.timeout, ) + def upsert_users(self, *users: UserRequest): + """ + Creates or updates users. This method performs an "upsert" operation, + where it checks if each user already exists and updates their information + if they do, or creates a new user entry if they do not. + """ + users_map = {u.id: u for u in users} + return self.update_users(users_map) + def create_token( self, user_id: str, diff --git a/getstream/video/call.py b/getstream/video/call.py index 557069c..19d87ec 100644 --- a/getstream/video/call.py +++ b/getstream/video/call.py @@ -266,3 +266,5 @@ def update_user_permissions( ) self._sync_from_response(response.data) return response + + create = get_or_create diff --git a/getstream/video/rest_client.py b/getstream/video/rest_client.py index e8eac3d..4a4466e 100644 --- a/getstream/video/rest_client.py +++ b/getstream/video/rest_client.py @@ -511,30 +511,21 @@ def update_user_permissions( def query_calls( self, - connection_id: Optional[str] = None, limit: Optional[int] = None, next: Optional[str] = None, prev: Optional[str] = None, - watch: Optional[bool] = None, sort: Optional[List[Optional[SortParam]]] = None, filter_conditions: Optional[Dict[str, object]] = None, ) -> StreamResponse[QueryCallsResponse]: - query_params = build_query_param(connection_id=connection_id) json = build_body_dict( limit=limit, next=next, prev=prev, - watch=watch, sort=sort, filter_conditions=filter_conditions, ) - return self.post( - "/api/v2/video/calls", - QueryCallsResponse, - query_params=query_params, - json=json, - ) + return self.post("/api/v2/video/calls", QueryCallsResponse, json=json) def list_call_types(self) -> StreamResponse[ListCallTypeResponse]: return self.get("/api/v2/video/calltypes", ListCallTypeResponse) diff --git a/tests/test_video_examples.py b/tests/test_video_examples.py index f1e47e6..b16b02f 100644 --- a/tests/test_video_examples.py +++ b/tests/test_video_examples.py @@ -14,15 +14,13 @@ def test_setup_client(): def test_create_user(client: Stream): from getstream.models import UserRequest - client.update_users( - users={ - "tommaso-id": UserRequest( - id="tommaso-id", name="tommaso", role="admin", custom={"country": "NL"} - ), - "thierry-id": UserRequest( - id="thierry-id", name="thierry", role="admin", custom={"country": "US"} - ), - } + client.upsert_users( + UserRequest( + id="tommaso-id", name="tommaso", role="admin", custom={"country": "NL"} + ), + UserRequest( + id="thierry-id", name="thierry", role="admin", custom={"country": "US"} + ), ) token = client.create_token("tommaso-id") diff --git a/tests/test_integration.py b/tests/test_video_integration.py similarity index 90% rename from tests/test_integration.py rename to tests/test_video_integration.py index 1bb9b9f..8a4f210 100644 --- a/tests/test_integration.py +++ b/tests/test_video_integration.py @@ -16,6 +16,8 @@ NotificationSettings, EventNotificationSettings, APNS, + UserRequest, + QueryUsersPayload, ) from getstream.stream import Stream @@ -42,6 +44,44 @@ def test_create_token_with_expiration(client: Stream): assert decoded["user_id"] == "tommaso" +def test_teams(client: Stream): + call_id = str(uuid.uuid4()) + user_id = str(uuid.uuid4()) + response = client.upsert_users(UserRequest(id=user_id, teams=["red", "blue"])) + assert response.data.users[user_id].teams == ["red", "blue"] + call = client.video.call("default", call_id) + response = call.create( + data=CallRequest( + created_by_id=user_id, + team="blue", + ) + ) + assert response.data.call.team == "blue" + + response = client.query_users( + QueryUsersPayload( + filter_conditions={"id": user_id, "teams": {"$in": ["red", "blue"]}} + ) + ) + assert len(response.data.users) > 0 + assert user_id in [u.id for u in response.data.users] + + response = client.query_users( + QueryUsersPayload( + filter_conditions={ + "teams": None, + } + ) + ) + assert len([u for u in response.data.users if len(u.teams) > 0]) == 0 + + response = client.video.query_calls( + filter_conditions={"id": call_id, "team": {"$eq": "blue"}} + ) + + assert len(response.data.calls) > 0 + + class TestExternalStorage: def test_creating_storage_with_reserved_name_should_fail(self, client: Stream): with pytest.raises(Exception) as exc_info: