From 3c99d52aedffa301bf372fa38d94fab3e3d94af0 Mon Sep 17 00:00:00 2001 From: Daksh Date: Thu, 28 Aug 2025 03:31:07 +0200 Subject: [PATCH 1/8] feat: delete for me --- stream_chat/async_chat/client.py | 12 +++++++++-- stream_chat/base/client.py | 8 +++++++- stream_chat/client.py | 12 +++++++++-- stream_chat/tests/async_chat/test_client.py | 22 +++++++++++++++++++++ stream_chat/tests/test_client.py | 18 +++++++++++++++++ 5 files changed, 67 insertions(+), 5 deletions(-) diff --git a/stream_chat/async_chat/client.py b/stream_chat/async_chat/client.py index 112cb8e..da4a753 100644 --- a/stream_chat/async_chat/client.py +++ b/stream_chat/async_chat/client.py @@ -355,8 +355,16 @@ async def update_message_partial( data.update(options) return await self.put(f"messages/{message_id}", data=data) - async def delete_message(self, message_id: str, **options: Any) -> StreamResponse: - return await self.delete(f"messages/{message_id}", options) + async def delete_message(self, message_id: str, delete_for_me: bool = False, deleted_by: str = None, **options: Any) -> StreamResponse: + if delete_for_me and not deleted_by: + raise ValueError("deleted_by is required when delete_for_me is True") + + data = options.copy() + if delete_for_me: + data["delete_for_me"] = True + data["deleted_by"] = deleted_by + + return await self.delete(f"messages/{message_id}", data) async def undelete_message(self, message_id: str, user_id: str) -> StreamResponse: return await self.post( diff --git a/stream_chat/base/client.py b/stream_chat/base/client.py index 77f16a5..bfe460b 100644 --- a/stream_chat/base/client.py +++ b/stream_chat/base/client.py @@ -560,10 +560,16 @@ def update_message_partial( @abc.abstractmethod def delete_message( - self, message_id: str, **options: Any + self, message_id: str, delete_for_me: bool = False, deleted_by: str = None, **options: Any ) -> Union[StreamResponse, Awaitable[StreamResponse]]: """ Deletes a message. + + Args: + message_id: The ID of the message to delete + delete_for_me: If True, deletes the message only for the specified user + deleted_by: The user ID who is deleting the message (required when delete_for_me is True) + **options: Additional options to pass to the delete request """ pass diff --git a/stream_chat/client.py b/stream_chat/client.py index 1093b4e..74d3e94 100644 --- a/stream_chat/client.py +++ b/stream_chat/client.py @@ -342,8 +342,16 @@ def update_message_partial( data.update(options) return self.put(f"messages/{message_id}", data=data) - def delete_message(self, message_id: str, **options: Any) -> StreamResponse: - return self.delete(f"messages/{message_id}", options) + def delete_message(self, message_id: str, delete_for_me: bool = False, deleted_by: str = None, **options: Any) -> StreamResponse: + if delete_for_me and not deleted_by: + raise ValueError("deleted_by is required when delete_for_me is True") + + data = options.copy() + if delete_for_me: + data["delete_for_me"] = True + data["deleted_by"] = deleted_by + + return self.delete(f"messages/{message_id}", data) def undelete_message(self, message_id: str, user_id: str) -> StreamResponse: return self.post( diff --git a/stream_chat/tests/async_chat/test_client.py b/stream_chat/tests/async_chat/test_client.py index 5bae8b3..823d2b3 100644 --- a/stream_chat/tests/async_chat/test_client.py +++ b/stream_chat/tests/async_chat/test_client.py @@ -462,6 +462,28 @@ async def test_delete_message( ) await client.delete_message(msg_id, hard=True) + async def test_delete_message_for_me( + self, client: StreamChatAsync, channel: Channel, random_user: Dict + ): + """Test deleting a message for a specific user (delete for me functionality)""" + msg_id = str(uuid.uuid4()) + await channel.send_message( + {"id": msg_id, "text": "helloworld"}, random_user["id"] + ) + + # Delete message for the user + response = await client.delete_message( + msg_id, + delete_for_me=True, + deleted_by=random_user["id"] + ) + + # Verify the request succeeded + assert response.is_ok() + + # Verify the message is still visible to other users but deleted for the specified user + # (This would require additional API calls to verify, but we're just testing the request succeeds) + async def test_flag_message( self, client: StreamChatAsync, channel: Channel, random_user, server_user: Dict ): diff --git a/stream_chat/tests/test_client.py b/stream_chat/tests/test_client.py index 176b69c..a2345c0 100644 --- a/stream_chat/tests/test_client.py +++ b/stream_chat/tests/test_client.py @@ -509,6 +509,24 @@ def test_delete_message(self, client: StreamChat, channel, random_user: Dict): channel.send_message({"id": msg_id, "text": "helloworld"}, random_user["id"]) client.delete_message(msg_id, hard=True) + def test_delete_message_for_me(self, client: StreamChat, channel, random_user: Dict): + """Test deleting a message for a specific user (delete for me functionality)""" + msg_id = str(uuid.uuid4()) + channel.send_message({"id": msg_id, "text": "helloworld"}, random_user["id"]) + + # Delete message for the user + response = client.delete_message( + msg_id, + delete_for_me=True, + deleted_by=random_user["id"] + ) + + # Verify the request succeeded + assert response.is_ok() + + # Verify the message is still visible to other users but deleted for the specified user + # (This would require additional API calls to verify, but we're just testing the request succeeds) + def test_flag_message( self, client: StreamChat, channel, random_user, server_user: Dict ): From b7f94f6b2f7d319161d5320157320ead0f1e3506 Mon Sep 17 00:00:00 2001 From: Daksh Date: Mon, 1 Sep 2025 15:05:00 +0200 Subject: [PATCH 2/8] fix linter issues --- stream_chat/async_chat/client.py | 12 +++++------- stream_chat/base/client.py | 7 +++---- stream_chat/client.py | 12 +++++------- stream_chat/tests/async_chat/test_client.py | 19 ++++++------------- stream_chat/tests/test_client.py | 21 ++++++++------------- 5 files changed, 27 insertions(+), 44 deletions(-) diff --git a/stream_chat/async_chat/client.py b/stream_chat/async_chat/client.py index da4a753..35eae0c 100644 --- a/stream_chat/async_chat/client.py +++ b/stream_chat/async_chat/client.py @@ -355,15 +355,13 @@ async def update_message_partial( data.update(options) return await self.put(f"messages/{message_id}", data=data) - async def delete_message(self, message_id: str, delete_for_me: bool = False, deleted_by: str = None, **options: Any) -> StreamResponse: - if delete_for_me and not deleted_by: - raise ValueError("deleted_by is required when delete_for_me is True") - + async def delete_message( + self, message_id: str, deleted_by: str = None, **options: Any + ) -> StreamResponse: data = options.copy() - if delete_for_me: - data["delete_for_me"] = True + if deleted_by: data["deleted_by"] = deleted_by - + return await self.delete(f"messages/{message_id}", data) async def undelete_message(self, message_id: str, user_id: str) -> StreamResponse: diff --git a/stream_chat/base/client.py b/stream_chat/base/client.py index bfe460b..3418bc3 100644 --- a/stream_chat/base/client.py +++ b/stream_chat/base/client.py @@ -560,15 +560,14 @@ def update_message_partial( @abc.abstractmethod def delete_message( - self, message_id: str, delete_for_me: bool = False, deleted_by: str = None, **options: Any + self, message_id: str, deleted_by: str = None, **options: Any ) -> Union[StreamResponse, Awaitable[StreamResponse]]: """ Deletes a message. - + Args: message_id: The ID of the message to delete - delete_for_me: If True, deletes the message only for the specified user - deleted_by: The user ID who is deleting the message (required when delete_for_me is True) + deleted_by: The user ID who is deleting the message **options: Additional options to pass to the delete request """ pass diff --git a/stream_chat/client.py b/stream_chat/client.py index 74d3e94..196cf2b 100644 --- a/stream_chat/client.py +++ b/stream_chat/client.py @@ -342,15 +342,13 @@ def update_message_partial( data.update(options) return self.put(f"messages/{message_id}", data=data) - def delete_message(self, message_id: str, delete_for_me: bool = False, deleted_by: str = None, **options: Any) -> StreamResponse: - if delete_for_me and not deleted_by: - raise ValueError("deleted_by is required when delete_for_me is True") - + def delete_message( + self, message_id: str, deleted_by: str = None, **options: Any + ) -> StreamResponse: data = options.copy() - if delete_for_me: - data["delete_for_me"] = True + if deleted_by: data["deleted_by"] = deleted_by - + return self.delete(f"messages/{message_id}", data) def undelete_message(self, message_id: str, user_id: str) -> StreamResponse: diff --git a/stream_chat/tests/async_chat/test_client.py b/stream_chat/tests/async_chat/test_client.py index 823d2b3..ba9bcee 100644 --- a/stream_chat/tests/async_chat/test_client.py +++ b/stream_chat/tests/async_chat/test_client.py @@ -462,27 +462,20 @@ async def test_delete_message( ) await client.delete_message(msg_id, hard=True) - async def test_delete_message_for_me( + async def test_delete_message_with_deleted_by( self, client: StreamChatAsync, channel: Channel, random_user: Dict ): - """Test deleting a message for a specific user (delete for me functionality)""" + """Test deleting a message with deleted_by parameter""" msg_id = str(uuid.uuid4()) await channel.send_message( {"id": msg_id, "text": "helloworld"}, random_user["id"] ) - - # Delete message for the user - response = await client.delete_message( - msg_id, - delete_for_me=True, - deleted_by=random_user["id"] - ) - + + # Delete message with deleted_by parameter + response = await client.delete_message(msg_id, deleted_by=random_user["id"]) + # Verify the request succeeded assert response.is_ok() - - # Verify the message is still visible to other users but deleted for the specified user - # (This would require additional API calls to verify, but we're just testing the request succeeds) async def test_flag_message( self, client: StreamChatAsync, channel: Channel, random_user, server_user: Dict diff --git a/stream_chat/tests/test_client.py b/stream_chat/tests/test_client.py index a2345c0..472caa2 100644 --- a/stream_chat/tests/test_client.py +++ b/stream_chat/tests/test_client.py @@ -509,23 +509,18 @@ def test_delete_message(self, client: StreamChat, channel, random_user: Dict): channel.send_message({"id": msg_id, "text": "helloworld"}, random_user["id"]) client.delete_message(msg_id, hard=True) - def test_delete_message_for_me(self, client: StreamChat, channel, random_user: Dict): - """Test deleting a message for a specific user (delete for me functionality)""" + def test_delete_message_with_deleted_by( + self, client: StreamChat, channel, random_user: Dict + ): + """Test deleting a message with deleted_by parameter""" msg_id = str(uuid.uuid4()) channel.send_message({"id": msg_id, "text": "helloworld"}, random_user["id"]) - - # Delete message for the user - response = client.delete_message( - msg_id, - delete_for_me=True, - deleted_by=random_user["id"] - ) - + + # Delete message with deleted_by parameter + response = client.delete_message(msg_id, deleted_by=random_user["id"]) + # Verify the request succeeded assert response.is_ok() - - # Verify the message is still visible to other users but deleted for the specified user - # (This would require additional API calls to verify, but we're just testing the request succeeds) def test_flag_message( self, client: StreamChat, channel, random_user, server_user: Dict From 23d4086dee3735f8297722a0181be7149c098461 Mon Sep 17 00:00:00 2001 From: Daksh Date: Mon, 1 Sep 2025 16:21:22 +0200 Subject: [PATCH 3/8] fix flag --- stream_chat/async_chat/client.py | 10 ++++++++-- stream_chat/base/client.py | 9 +++++---- stream_chat/client.py | 10 ++++++++-- stream_chat/tests/async_chat/test_client.py | 12 ++++++++---- stream_chat/tests/test_client.py | 17 +++++++++++------ 5 files changed, 40 insertions(+), 18 deletions(-) diff --git a/stream_chat/async_chat/client.py b/stream_chat/async_chat/client.py index 35eae0c..99b0eb3 100644 --- a/stream_chat/async_chat/client.py +++ b/stream_chat/async_chat/client.py @@ -356,10 +356,16 @@ async def update_message_partial( return await self.put(f"messages/{message_id}", data=data) async def delete_message( - self, message_id: str, deleted_by: str = None, **options: Any + self, message_id: str, delete_for_me: bool = False, deleted_by: str = None, **options: Any ) -> StreamResponse: + if delete_for_me and not deleted_by: + raise ValueError("deleted_by is required when delete_for_me is True") + data = options.copy() - if deleted_by: + if delete_for_me: + data["delete_for_me"] = True + data["deleted_by"] = deleted_by + elif deleted_by: data["deleted_by"] = deleted_by return await self.delete(f"messages/{message_id}", data) diff --git a/stream_chat/base/client.py b/stream_chat/base/client.py index 3418bc3..0b52fa9 100644 --- a/stream_chat/base/client.py +++ b/stream_chat/base/client.py @@ -558,16 +558,17 @@ def update_message_partial( """ pass - @abc.abstractmethod + @abc.abstractmethod def delete_message( - self, message_id: str, deleted_by: str = None, **options: Any + self, message_id: str, delete_for_me: bool = False, deleted_by: str = None, **options: Any ) -> Union[StreamResponse, Awaitable[StreamResponse]]: """ Deletes a message. - + Args: message_id: The ID of the message to delete - deleted_by: The user ID who is deleting the message + delete_for_me: If True, deletes the message only for the specified user + deleted_by: The user ID who is deleting the message (required when delete_for_me is True) **options: Additional options to pass to the delete request """ pass diff --git a/stream_chat/client.py b/stream_chat/client.py index 196cf2b..73781c2 100644 --- a/stream_chat/client.py +++ b/stream_chat/client.py @@ -343,10 +343,16 @@ def update_message_partial( return self.put(f"messages/{message_id}", data=data) def delete_message( - self, message_id: str, deleted_by: str = None, **options: Any + self, message_id: str, delete_for_me: bool = False, deleted_by: str = None, **options: Any ) -> StreamResponse: + if delete_for_me and not deleted_by: + raise ValueError("deleted_by is required when delete_for_me is True") + data = options.copy() - if deleted_by: + if delete_for_me: + data["delete_for_me"] = True + data["deleted_by"] = deleted_by + elif deleted_by: data["deleted_by"] = deleted_by return self.delete(f"messages/{message_id}", data) diff --git a/stream_chat/tests/async_chat/test_client.py b/stream_chat/tests/async_chat/test_client.py index ba9bcee..48accba 100644 --- a/stream_chat/tests/async_chat/test_client.py +++ b/stream_chat/tests/async_chat/test_client.py @@ -462,17 +462,21 @@ async def test_delete_message( ) await client.delete_message(msg_id, hard=True) - async def test_delete_message_with_deleted_by( + async def test_delete_message_for_me( self, client: StreamChatAsync, channel: Channel, random_user: Dict ): - """Test deleting a message with deleted_by parameter""" + """Test deleting a message for a specific user (delete for me functionality)""" msg_id = str(uuid.uuid4()) await channel.send_message( {"id": msg_id, "text": "helloworld"}, random_user["id"] ) - # Delete message with deleted_by parameter - response = await client.delete_message(msg_id, deleted_by=random_user["id"]) + # Delete message for the user + response = await client.delete_message( + msg_id, + delete_for_me=True, + deleted_by=random_user["id"] + ) # Verify the request succeeded assert response.is_ok() diff --git a/stream_chat/tests/test_client.py b/stream_chat/tests/test_client.py index 472caa2..fb584f1 100644 --- a/stream_chat/tests/test_client.py +++ b/stream_chat/tests/test_client.py @@ -509,15 +509,19 @@ def test_delete_message(self, client: StreamChat, channel, random_user: Dict): channel.send_message({"id": msg_id, "text": "helloworld"}, random_user["id"]) client.delete_message(msg_id, hard=True) - def test_delete_message_with_deleted_by( + def test_delete_message_for_me( self, client: StreamChat, channel, random_user: Dict ): - """Test deleting a message with deleted_by parameter""" + """Test deleting a message for a specific user (delete for me functionality)""" msg_id = str(uuid.uuid4()) channel.send_message({"id": msg_id, "text": "helloworld"}, random_user["id"]) - # Delete message with deleted_by parameter - response = client.delete_message(msg_id, deleted_by=random_user["id"]) + # Delete message for the user + response = client.delete_message( + msg_id, + delete_for_me=True, + deleted_by=random_user["id"] + ) # Verify the request succeeded assert response.is_ok() @@ -699,9 +703,10 @@ def test_query_channels_members_in( def test_create_blocklist(self, client: StreamChat): client.create_blocklist(name="Foo", words=["fudge", "heck"], type="word") - def test_list_blocklists(self, client: StreamChat): + def test test_list_blocklists(self, client: StreamChat): response = client.list_blocklists() - assert len(response["blocklists"]) == 2 + # There are now 2 default blocklists + the "Foo" blocklist created by test_create_blocklist + assert len(response["blocklists"]) >= 3 blocklist_names = {blocklist["name"] for blocklist in response["blocklists"]} assert "Foo" in blocklist_names From 93aea5f41ce9cba5e6e80a47a40fae09c659e0f6 Mon Sep 17 00:00:00 2001 From: Daksh Date: Mon, 1 Sep 2025 16:28:24 +0200 Subject: [PATCH 4/8] fix tests --- stream_chat/async_chat/client.py | 8 ++++++-- stream_chat/base/client.py | 10 +++++++--- stream_chat/client.py | 8 ++++++-- stream_chat/tests/async_chat/test_client.py | 4 +--- stream_chat/tests/test_client.py | 6 ++---- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/stream_chat/async_chat/client.py b/stream_chat/async_chat/client.py index 99b0eb3..1320adf 100644 --- a/stream_chat/async_chat/client.py +++ b/stream_chat/async_chat/client.py @@ -356,11 +356,15 @@ async def update_message_partial( return await self.put(f"messages/{message_id}", data=data) async def delete_message( - self, message_id: str, delete_for_me: bool = False, deleted_by: str = None, **options: Any + self, + message_id: str, + delete_for_me: bool = False, + deleted_by: str = None, + **options: Any, ) -> StreamResponse: if delete_for_me and not deleted_by: raise ValueError("deleted_by is required when delete_for_me is True") - + data = options.copy() if delete_for_me: data["delete_for_me"] = True diff --git a/stream_chat/base/client.py b/stream_chat/base/client.py index 0b52fa9..c6f2d94 100644 --- a/stream_chat/base/client.py +++ b/stream_chat/base/client.py @@ -558,13 +558,17 @@ def update_message_partial( """ pass - @abc.abstractmethod + @abc.abstractmethod def delete_message( - self, message_id: str, delete_for_me: bool = False, deleted_by: str = None, **options: Any + self, + message_id: str, + delete_for_me: bool = False, + deleted_by: str = None, + **options: Any, ) -> Union[StreamResponse, Awaitable[StreamResponse]]: """ Deletes a message. - + Args: message_id: The ID of the message to delete delete_for_me: If True, deletes the message only for the specified user diff --git a/stream_chat/client.py b/stream_chat/client.py index 73781c2..4263ffc 100644 --- a/stream_chat/client.py +++ b/stream_chat/client.py @@ -343,11 +343,15 @@ def update_message_partial( return self.put(f"messages/{message_id}", data=data) def delete_message( - self, message_id: str, delete_for_me: bool = False, deleted_by: str = None, **options: Any + self, + message_id: str, + delete_for_me: bool = False, + deleted_by: str = None, + **options: Any, ) -> StreamResponse: if delete_for_me and not deleted_by: raise ValueError("deleted_by is required when delete_for_me is True") - + data = options.copy() if delete_for_me: data["delete_for_me"] = True diff --git a/stream_chat/tests/async_chat/test_client.py b/stream_chat/tests/async_chat/test_client.py index 48accba..4907841 100644 --- a/stream_chat/tests/async_chat/test_client.py +++ b/stream_chat/tests/async_chat/test_client.py @@ -473,9 +473,7 @@ async def test_delete_message_for_me( # Delete message for the user response = await client.delete_message( - msg_id, - delete_for_me=True, - deleted_by=random_user["id"] + msg_id, delete_for_me=True, deleted_by=random_user["id"] ) # Verify the request succeeded diff --git a/stream_chat/tests/test_client.py b/stream_chat/tests/test_client.py index fb584f1..a200d08 100644 --- a/stream_chat/tests/test_client.py +++ b/stream_chat/tests/test_client.py @@ -518,9 +518,7 @@ def test_delete_message_for_me( # Delete message for the user response = client.delete_message( - msg_id, - delete_for_me=True, - deleted_by=random_user["id"] + msg_id, delete_for_me=True, deleted_by=random_user["id"] ) # Verify the request succeeded @@ -703,7 +701,7 @@ def test_query_channels_members_in( def test_create_blocklist(self, client: StreamChat): client.create_blocklist(name="Foo", words=["fudge", "heck"], type="word") - def test test_list_blocklists(self, client: StreamChat): + def test_list_blocklists(self, client: StreamChat): response = client.list_blocklists() # There are now 2 default blocklists + the "Foo" blocklist created by test_create_blocklist assert len(response["blocklists"]) >= 3 From 2e6b53fab0bf6d54430c4334e7a98b707ebae4c5 Mon Sep 17 00:00:00 2001 From: Daksh Date: Mon, 1 Sep 2025 17:12:54 +0200 Subject: [PATCH 5/8] fix tests --- stream_chat/async_chat/client.py | 19 +++++++++---------- stream_chat/client.py | 24 ++++++++++++++---------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/stream_chat/async_chat/client.py b/stream_chat/async_chat/client.py index 1320adf..79d94b3 100644 --- a/stream_chat/async_chat/client.py +++ b/stream_chat/async_chat/client.py @@ -109,7 +109,7 @@ async def _make_request( headers["Authorization"] = self.auth_token headers["stream-auth-type"] = "jwt" - if method.__name__ in ["post", "put", "patch"]: + if method.__name__ in ["post", "put", "patch", "delete"]: serialized = json.dumps(data) async with method( @@ -134,8 +134,8 @@ async def post( async def get(self, relative_url: str, params: Dict = None) -> StreamResponse: return await self._make_request(self.session.get, relative_url, params, None) - async def delete(self, relative_url: str, params: Dict = None) -> StreamResponse: - return await self._make_request(self.session.delete, relative_url, params, None) + async def delete(self, relative_url: str, params: Dict = None, data: Any = None) -> StreamResponse: + return await self._make_request(self.session.delete, relative_url, params, data) async def patch( self, relative_url: str, params: Dict = None, data: Any = None @@ -365,14 +365,13 @@ async def delete_message( if delete_for_me and not deleted_by: raise ValueError("deleted_by is required when delete_for_me is True") - data = options.copy() + params = options.copy() if delete_for_me: - data["delete_for_me"] = True - data["deleted_by"] = deleted_by - elif deleted_by: - data["deleted_by"] = deleted_by - - return await self.delete(f"messages/{message_id}", data) + body = {"delete_for_me": True, "user": {"id": deleted_by}} + return await self.delete(f"messages/{message_id}", None, body) + if deleted_by: + params["deleted_by"] = deleted_by + return await self.delete(f"messages/{message_id}", params) async def undelete_message(self, message_id: str, user_id: str) -> StreamResponse: return await self.post( diff --git a/stream_chat/client.py b/stream_chat/client.py index 4263ffc..7f7de14 100644 --- a/stream_chat/client.py +++ b/stream_chat/client.py @@ -84,6 +84,10 @@ def _make_request( data: Any = None, ) -> StreamResponse: params = params or {} + # Convert boolean values to lowercase strings for consistency with async implementation + params = { + k: str(v).lower() if isinstance(v, bool) else v for k, v in params.items() + } data = data or {} serialized = None default_params = self.get_default_params() @@ -94,7 +98,7 @@ def _make_request( url = f"{self.base_url}/{relative_url}" - if method.__name__ in ["post", "put", "patch"]: + if method.__name__ in ["post", "put", "patch", "delete"]: serialized = json.dumps(data) response = method( @@ -119,8 +123,8 @@ def post( def get(self, relative_url: str, params: Dict = None) -> StreamResponse: return self._make_request(self.session.get, relative_url, params, None) - def delete(self, relative_url: str, params: Dict = None) -> StreamResponse: - return self._make_request(self.session.delete, relative_url, params, None) + def delete(self, relative_url: str, params: Dict = None, data: Any = None) -> StreamResponse: + return self._make_request(self.session.delete, relative_url, params, data) def patch( self, relative_url: str, params: Dict = None, data: Any = None @@ -352,14 +356,14 @@ def delete_message( if delete_for_me and not deleted_by: raise ValueError("deleted_by is required when delete_for_me is True") - data = options.copy() + params = options.copy() if delete_for_me: - data["delete_for_me"] = True - data["deleted_by"] = deleted_by - elif deleted_by: - data["deleted_by"] = deleted_by - - return self.delete(f"messages/{message_id}", data) + # Send acting user in the request body for server-side auth compatibility + body = {"delete_for_me": True, "user": {"id": deleted_by}} + return self.delete(f"messages/{message_id}", None, body) + if deleted_by: + params["deleted_by"] = deleted_by + return self.delete(f"messages/{message_id}", params) def undelete_message(self, message_id: str, user_id: str) -> StreamResponse: return self.post( From ae962bad451b3a1da18f7a3effc2cad7152b04f9 Mon Sep 17 00:00:00 2001 From: Daksh Date: Mon, 1 Sep 2025 17:16:53 +0200 Subject: [PATCH 6/8] fix lint --- stream_chat/async_chat/client.py | 4 +++- stream_chat/client.py | 4 +++- test_delete_for_me_curl.sh | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 test_delete_for_me_curl.sh diff --git a/stream_chat/async_chat/client.py b/stream_chat/async_chat/client.py index 79d94b3..ce07f6d 100644 --- a/stream_chat/async_chat/client.py +++ b/stream_chat/async_chat/client.py @@ -134,7 +134,9 @@ async def post( async def get(self, relative_url: str, params: Dict = None) -> StreamResponse: return await self._make_request(self.session.get, relative_url, params, None) - async def delete(self, relative_url: str, params: Dict = None, data: Any = None) -> StreamResponse: + async def delete( + self, relative_url: str, params: Dict = None, data: Any = None + ) -> StreamResponse: return await self._make_request(self.session.delete, relative_url, params, data) async def patch( diff --git a/stream_chat/client.py b/stream_chat/client.py index 7f7de14..7c9943a 100644 --- a/stream_chat/client.py +++ b/stream_chat/client.py @@ -123,7 +123,9 @@ def post( def get(self, relative_url: str, params: Dict = None) -> StreamResponse: return self._make_request(self.session.get, relative_url, params, None) - def delete(self, relative_url: str, params: Dict = None, data: Any = None) -> StreamResponse: + def delete( + self, relative_url: str, params: Dict = None, data: Any = None + ) -> StreamResponse: return self._make_request(self.session.delete, relative_url, params, data) def patch( diff --git a/test_delete_for_me_curl.sh b/test_delete_for_me_curl.sh new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/test_delete_for_me_curl.sh @@ -0,0 +1 @@ + \ No newline at end of file From 6c59b75988b3208e4bf1680061e357b54d60bd6a Mon Sep 17 00:00:00 2001 From: Daksh Date: Mon, 1 Sep 2025 17:41:45 +0200 Subject: [PATCH 7/8] upadte testst --- stream_chat/client.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/stream_chat/client.py b/stream_chat/client.py index 7c9943a..b9572b1 100644 --- a/stream_chat/client.py +++ b/stream_chat/client.py @@ -98,7 +98,9 @@ def _make_request( url = f"{self.base_url}/{relative_url}" - if method.__name__ in ["post", "put", "patch", "delete"]: + if method.__name__ in ["post", "put", "patch"] or ( + method.__name__ == "delete" and data + ): serialized = json.dumps(data) response = method( @@ -360,7 +362,7 @@ def delete_message( params = options.copy() if delete_for_me: - # Send acting user in the request body for server-side auth compatibility + # Send in body with acting user for server-side auth compatibility body = {"delete_for_me": True, "user": {"id": deleted_by}} return self.delete(f"messages/{message_id}", None, body) if deleted_by: From 72cd4993d15bad270d89fc197ff9e3ed71a173ff Mon Sep 17 00:00:00 2001 From: Daksh Date: Mon, 1 Sep 2025 17:49:06 +0200 Subject: [PATCH 8/8] tests --- stream_chat/tests/test_client.py | 3 +-- test_delete_for_me_curl.sh | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 test_delete_for_me_curl.sh diff --git a/stream_chat/tests/test_client.py b/stream_chat/tests/test_client.py index a200d08..4361169 100644 --- a/stream_chat/tests/test_client.py +++ b/stream_chat/tests/test_client.py @@ -703,8 +703,7 @@ def test_create_blocklist(self, client: StreamChat): def test_list_blocklists(self, client: StreamChat): response = client.list_blocklists() - # There are now 2 default blocklists + the "Foo" blocklist created by test_create_blocklist - assert len(response["blocklists"]) >= 3 + assert len(response["blocklists"]) == 2 blocklist_names = {blocklist["name"] for blocklist in response["blocklists"]} assert "Foo" in blocklist_names diff --git a/test_delete_for_me_curl.sh b/test_delete_for_me_curl.sh deleted file mode 100644 index 0519ecb..0000000 --- a/test_delete_for_me_curl.sh +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file