diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e23c4b14..03c78552 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @10printhello @totalimmersion +* @10printhello @totalimmersion @slavabobik diff --git a/stream_chat/async_chat/client.py b/stream_chat/async_chat/client.py index b7a10997..44b3763d 100644 --- a/stream_chat/async_chat/client.py +++ b/stream_chat/async_chat/client.py @@ -190,6 +190,13 @@ async def restore_users(self, user_ids: Iterable[str]) -> StreamResponse: async def deactivate_user(self, user_id: str, **options: Any) -> StreamResponse: return await self.post(f"users/{user_id}/deactivate", data=options) + async def deactivate_users( + self, user_ids: Iterable[str], **options: Any + ) -> StreamResponse: + return await self.post( + "users/deactivate", data=dict(options, user_ids=user_ids) + ) + async def reactivate_user(self, user_id: str, **options: Any) -> StreamResponse: return await self.post(f"users/{user_id}/reactivate", data=options) diff --git a/stream_chat/base/client.py b/stream_chat/base/client.py index a8b624b4..c2e0557f 100644 --- a/stream_chat/base/client.py +++ b/stream_chat/base/client.py @@ -256,6 +256,21 @@ def deactivate_user( """ pass + @abc.abstractmethod + def deactivate_users( + self, user_ids: Iterable[str], **options: Any + ) -> Union[StreamResponse, Awaitable[StreamResponse]]: + """ + Deactivates multiple users in a batch operation. + Deactivated users cannot connect to Stream Chat, and can't send or receive messages. + To reactivate users, use `reactivate_user` method for each user. + + :param user_ids: a list of user IDs to deactivate + :param options: additional options + :return: task_id + """ + pass + @abc.abstractmethod def reactivate_user( self, user_id: str, **options: Any diff --git a/stream_chat/client.py b/stream_chat/client.py index 85c1e8b9..920f4715 100644 --- a/stream_chat/client.py +++ b/stream_chat/client.py @@ -178,6 +178,11 @@ def restore_users(self, user_ids: Iterable[str]) -> StreamResponse: def deactivate_user(self, user_id: str, **options: Any) -> StreamResponse: return self.post(f"users/{user_id}/deactivate", data=options) + def deactivate_users( + self, user_ids: Iterable[str], **options: Any + ) -> StreamResponse: + return self.post("users/deactivate", data=dict(options, user_ids=user_ids)) + def reactivate_user(self, user_id: str, **options: Any) -> StreamResponse: return self.post(f"users/{user_id}/reactivate", data=options) diff --git a/stream_chat/tests/async_chat/test_client.py b/stream_chat/tests/async_chat/test_client.py index 550d5c83..271bbd3d 100644 --- a/stream_chat/tests/async_chat/test_client.py +++ b/stream_chat/tests/async_chat/test_client.py @@ -194,6 +194,27 @@ async def test_deactivate_user(self, client: StreamChatAsync, random_user: Dict) assert "user" in response assert random_user["id"] == response["user"]["id"] + async def test_deactivate_users(self, client: StreamChatAsync, random_users: Dict): + user_ids = [user["id"] for user in random_users] + response = await client.deactivate_users(user_ids) + assert "task_id" in response + assert len(response["task_id"]) == 36 + + async def f(): + r = await client.get_task(response["task_id"]) + return r["status"] == "completed" + + await wait_for_async(f) + + response = await client.get_task(response["task_id"]) + assert response["status"] == "completed" + assert "result" in response + assert "users" in response["result"] + # Verify that all users in the response have deactivated_at field + for user in response["result"]["users"]: + assert "deactivated_at" in user + assert user["id"] in user_ids + async def test_reactivate_user(self, client: StreamChatAsync, random_user: Dict): response = await client.deactivate_user(random_user["id"]) assert "user" in response diff --git a/stream_chat/tests/test_client.py b/stream_chat/tests/test_client.py index 85a24b8e..ca800a76 100644 --- a/stream_chat/tests/test_client.py +++ b/stream_chat/tests/test_client.py @@ -197,6 +197,23 @@ def test_deactivate_user(self, client: StreamChat, random_user: Dict): assert "user" in response assert random_user["id"] == response["user"]["id"] + def test_deactivate_users(self, client: StreamChat, random_users: Dict): + user_ids = [user["id"] for user in random_users] + response = client.deactivate_users(user_ids) + assert "task_id" in response + assert len(response["task_id"]) == 36 # task_id is a UUID + + wait_for(lambda: client.get_task(response["task_id"])["status"] == "completed") + + response = client.get_task(response["task_id"]) + assert response["status"] == "completed" + assert "result" in response + assert "users" in response["result"] + # Verify that all users in the response have deactivated_at field + for user in response["result"]["users"]: + assert "deactivated_at" in user + assert user["id"] in user_ids + def test_reactivate_user(self, client: StreamChat, random_user: Dict): response = client.deactivate_user(random_user["id"]) assert "user" in response