Skip to content

Commit 7c2ab4b

Browse files
Merge branch 'master' into message_reminders
# Conflicts: # stream_chat/async_chat/client.py # stream_chat/base/client.py # stream_chat/client.py
2 parents 75eb696 + 6364604 commit 7c2ab4b

23 files changed

+1070
-183
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
* @10printhello @totalimmersion
1+
* @10printhello @totalimmersion @slavabobik

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ secrets.*sh
6060
.idea
6161

6262
.venv
63+
venv
6364
.python-version
6465
pip-selfcheck.json
6566
.idea

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
44

5+
## [4.24.0](https://github.com/GetStream/stream-chat-python/compare/v4.23.0...v4.24.0) (2025-04-07)
6+
7+
## [4.23.0](https://github.com/GetStream/stream-chat-python/compare/v4.22.0...v4.23.0) (2025-03-11)
8+
59
## [4.22.0](https://github.com/GetStream/stream-chat-python/compare/v4.21.0...v4.22.0) (2025-02-18)
610

711
## [4.21.0](https://github.com/GetStream/stream-chat-python/compare/v4.20.0...v4.21.0) (2025-02-11)

stream_chat/__pkg__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
__author__ = "Tommaso Barbugli"
22
__copyright__ = "Copyright 2019-2022, Stream.io, Inc"
3-
__version__ = "4.22.0"
3+
__version__ = "4.24.0"
44
__maintainer__ = "Tommaso Barbugli"
55
__email__ = "[email protected]"
66
__status__ = "Production"

stream_chat/async_chat/channel.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import json
2-
from typing import Any, Dict, Iterable, List, Union
2+
from typing import Any, Dict, Iterable, List, Optional, Union
33

44
from stream_chat.base.channel import ChannelInterface, add_user_id
55
from stream_chat.base.exceptions import StreamChannelException
@@ -84,8 +84,8 @@ async def update_partial(
8484
payload = {"set": to_set or {}, "unset": to_unset or []}
8585
return await self.client.patch(self.url, data=payload)
8686

87-
async def delete(self) -> StreamResponse:
88-
return await self.client.delete(self.url)
87+
async def delete(self, hard: bool = False) -> StreamResponse:
88+
return await self.client.delete(self.url, {"hard_delete": hard})
8989

9090
async def truncate(self, **options: Any) -> StreamResponse:
9191
return await self.client.post(f"{self.url}/truncate", data=options)
@@ -247,3 +247,23 @@ async def update_member_partial(
247247

248248
payload = {"set": to_set or {}, "unset": to_unset or []}
249249
return await self.client.patch(f"{self.url}/member/{user_id}", data=payload)
250+
251+
async def create_draft(self, message: Dict, user_id: str) -> StreamResponse:
252+
payload = {"message": add_user_id(message, user_id)}
253+
return await self.client.post(f"{self.url}/draft", data=payload)
254+
255+
async def delete_draft(
256+
self, user_id: str, parent_id: Optional[str] = None
257+
) -> StreamResponse:
258+
params = {"user_id": user_id}
259+
if parent_id:
260+
params["parent_id"] = parent_id
261+
return await self.client.delete(f"{self.url}/draft", params=params)
262+
263+
async def get_draft(
264+
self, user_id: str, parent_id: Optional[str] = None
265+
) -> StreamResponse:
266+
params = {"user_id": user_id}
267+
if parent_id:
268+
params["parent_id"] = parent_id
269+
return await self.client.get(f"{self.url}/draft", params=params)

stream_chat/async_chat/client.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from stream_chat.async_chat.segment import Segment
2222
from stream_chat.types.base import SortParam
2323
from stream_chat.types.campaign import CampaignData, QueryCampaignsOptions
24+
from stream_chat.types.draft import QueryDraftsFilter, QueryDraftsOptions
2425
from stream_chat.types.segment import (
2526
QuerySegmentsOptions,
2627
QuerySegmentTargetsOptions,
@@ -190,6 +191,13 @@ async def restore_users(self, user_ids: Iterable[str]) -> StreamResponse:
190191
async def deactivate_user(self, user_id: str, **options: Any) -> StreamResponse:
191192
return await self.post(f"users/{user_id}/deactivate", data=options)
192193

194+
async def deactivate_users(
195+
self, user_ids: Iterable[str], **options: Any
196+
) -> StreamResponse:
197+
return await self.post(
198+
"users/deactivate", data=dict(options, user_ids=user_ids)
199+
)
200+
193201
async def reactivate_user(self, user_id: str, **options: Any) -> StreamResponse:
194202
return await self.post(f"users/{user_id}/reactivate", data=options)
195203

@@ -215,6 +223,22 @@ async def query_banned_users(self, query_conditions: Dict) -> StreamResponse:
215223
"query_banned_users", params={"payload": json.dumps(query_conditions)}
216224
)
217225

226+
async def block_user(
227+
self, blocked_user_id: str, user_id: str, **options: Any
228+
) -> StreamResponse:
229+
data = {"blocked_user_id": blocked_user_id, "user_id": user_id, **options}
230+
return await self.post("users/block", data=data)
231+
232+
async def unblock_user(
233+
self, blocked_user_id: str, user_id: str, **options: Any
234+
) -> StreamResponse:
235+
data = {"blocked_user_id": blocked_user_id, "user_id": user_id, **options}
236+
return await self.post("users/unblock", data=data)
237+
238+
async def get_blocked_users(self, user_id: str, **options: Any) -> StreamResponse:
239+
params = {"user_id": user_id, **options}
240+
return await self.get("users/block", params=params)
241+
218242
async def run_message_action(self, message_id: str, data: Dict) -> StreamResponse:
219243
return await self.post(f"messages/{message_id}/action", data=data)
220244

@@ -353,6 +377,13 @@ async def query_message_history(
353377
)
354378
return await self.post("messages/history", data=params)
355379

380+
async def query_threads(
381+
self, filter: Dict = None, sort: List[Dict] = None, **options: Any
382+
) -> StreamResponse:
383+
params = options.copy()
384+
params.update({"filter": filter, "sort": self.normalize_sort(sort)})
385+
return await self.post("threads", data=params)
386+
356387
async def query_users(
357388
self, filter_conditions: Dict, sort: List[Dict] = None, **options: Any
358389
) -> StreamResponse:
@@ -818,6 +849,28 @@ async def unread_counts(self, user_id: str) -> StreamResponse:
818849
async def unread_counts_batch(self, user_ids: List[str]) -> StreamResponse:
819850
return await self.post("unread_batch", data={"user_ids": user_ids})
820851

852+
async def query_drafts(
853+
self,
854+
user_id: str,
855+
filter: Optional[QueryDraftsFilter] = None,
856+
sort: Optional[List[SortParam]] = None,
857+
options: Optional[QueryDraftsOptions] = None,
858+
) -> StreamResponse:
859+
data: Dict[str, Union[str, Dict[str, Any], List[SortParam]]] = {
860+
"user_id": user_id
861+
}
862+
863+
if filter is not None:
864+
data["filter"] = cast(dict, filter)
865+
866+
if sort is not None:
867+
data["sort"] = cast(dict, sort)
868+
869+
if options is not None:
870+
data.update(cast(dict, options))
871+
872+
return await self.post("drafts/query", data=data)
873+
821874
async def create_reminder(
822875
self,
823876
message_id: str,

stream_chat/base/channel.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import abc
2-
from typing import Any, Awaitable, Dict, Iterable, List, Union
2+
from typing import Any, Awaitable, Dict, Iterable, List, Optional, Union
33

44
from stream_chat.base.client import StreamChatInterface
55
from stream_chat.base.exceptions import StreamChannelException
@@ -165,7 +165,9 @@ def update_partial(
165165
pass
166166

167167
@abc.abstractmethod
168-
def delete(self) -> Union[StreamResponse, Awaitable[StreamResponse]]:
168+
def delete(
169+
self, hard: bool = False
170+
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
169171
"""
170172
Delete the channel. Messages are permanently removed.
171173
@@ -486,6 +488,45 @@ def update_member_partial(
486488
"""
487489
pass
488490

491+
@abc.abstractmethod
492+
def create_draft(
493+
self, message: Dict, user_id: str
494+
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
495+
"""
496+
Creates or updates a draft message in a channel.
497+
498+
:param message: The message object
499+
:param user_id: The ID of the user creating the draft
500+
:return: The Server Response
501+
"""
502+
pass
503+
504+
@abc.abstractmethod
505+
def delete_draft(
506+
self, user_id: str, parent_id: Optional[str] = None
507+
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
508+
"""
509+
Deletes a draft message from a channel.
510+
511+
:param user_id: The ID of the user who owns the draft
512+
:param parent_id: Optional ID of the parent message if this is a thread draft
513+
:return: The Server Response
514+
"""
515+
pass
516+
517+
@abc.abstractmethod
518+
def get_draft(
519+
self, user_id: str, parent_id: Optional[str] = None
520+
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
521+
"""
522+
Retrieves a draft message from a channel.
523+
524+
:param user_id: The ID of the user who owns the draft
525+
:param parent_id: Optional ID of the parent message if this is a thread draft
526+
:return: The Server Response
527+
"""
528+
pass
529+
489530

490531
def add_user_id(payload: Dict, user_id: str) -> Dict:
491532
return {**payload, "user": {"id": user_id}}

stream_chat/base/client.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from stream_chat.types.base import SortParam
1111
from stream_chat.types.campaign import CampaignData, QueryCampaignsOptions
12+
from stream_chat.types.draft import QueryDraftsFilter, QueryDraftsOptions
1213
from stream_chat.types.segment import (
1314
QuerySegmentsOptions,
1415
QuerySegmentTargetsOptions,
@@ -256,6 +257,21 @@ def deactivate_user(
256257
"""
257258
pass
258259

260+
@abc.abstractmethod
261+
def deactivate_users(
262+
self, user_ids: Iterable[str], **options: Any
263+
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
264+
"""
265+
Deactivates multiple users in a batch operation.
266+
Deactivated users cannot connect to Stream Chat, and can't send or receive messages.
267+
To reactivate users, use `reactivate_user` method for each user.
268+
269+
:param user_ids: a list of user IDs to deactivate
270+
:param options: additional options
271+
:return: task_id
272+
"""
273+
pass
274+
259275
@abc.abstractmethod
260276
def reactivate_user(
261277
self, user_id: str, **options: Any
@@ -339,6 +355,37 @@ def query_banned_users(
339355
"""
340356
pass
341357

358+
@abc.abstractmethod
359+
def block_user(
360+
self, blocked_user_id: str, user_id: str, **options: Any
361+
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
362+
"""
363+
Blocks a user. When a user is blocked, they will not be able to communicate with the
364+
blocking user in 1-on-1 channels, and will not be able to add the blocking user to channels.
365+
To unblock a user, use `unblock_user` method.
366+
"""
367+
pass
368+
369+
@abc.abstractmethod
370+
def unblock_user(
371+
self, blocked_user_id: str, user_id: str, **options: Any
372+
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
373+
"""
374+
Unblocks a user. This allows the previously blocked user to communicate with the
375+
unblocking user in 1-on-1 channels again, and all previous messages become visible.
376+
To block a user, use `block_user` method.
377+
"""
378+
pass
379+
380+
@abc.abstractmethod
381+
def get_blocked_users(
382+
self, user_id: str, **options: Any
383+
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
384+
"""
385+
Retrieves the list of users that have been blocked by the specified user.
386+
"""
387+
pass
388+
342389
@abc.abstractmethod
343390
def run_message_action(
344391
self, message_id: str, data: Dict
@@ -547,6 +594,19 @@ def query_message_history(
547594
"""
548595
pass
549596

597+
@abc.abstractmethod
598+
def query_threads(
599+
self, filter: Dict = None, sort: List[Dict] = None, **options: Any
600+
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
601+
"""
602+
Allows you to query threads using filter and sort. You can find the complete list of supported operators in the query syntax section of the docs.
603+
604+
:param filter: Filter conditions for the query
605+
:param sort: Sort conditions for the query
606+
:return: StreamResponse containing the threads
607+
"""
608+
pass
609+
550610
@abc.abstractmethod
551611
def query_users(
552612
self, filter_conditions: Dict, sort: List[Dict] = None, **options: Any
@@ -1369,6 +1429,16 @@ def unread_counts_batch(
13691429
"""
13701430
pass
13711431

1432+
@abc.abstractmethod
1433+
def query_drafts(
1434+
self,
1435+
user_id: str,
1436+
filter: Optional[QueryDraftsFilter] = None,
1437+
sort: Optional[List[SortParam]] = None,
1438+
options: Optional[QueryDraftsOptions] = None,
1439+
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
1440+
pass
1441+
13721442
@abc.abstractmethod
13731443
def create_reminder(
13741444
self,

stream_chat/base/query_threads.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import abc
2+
from typing import Any, Awaitable, Dict, List, Union
3+
4+
from stream_chat.base.client import StreamChatInterface
5+
from stream_chat.types.stream_response import StreamResponse
6+
7+
8+
class QueryThreadsInterface(abc.ABC):
9+
@abc.abstractmethod
10+
def __init__(self, client: StreamChatInterface):
11+
self.client = client
12+
13+
@property
14+
def url(self) -> str:
15+
return "threads"
16+
17+
@abc.abstractmethod
18+
def query_threads(
19+
self,
20+
filter: Dict[str, Dict[str, Any]],
21+
sort: List[Dict[str, Any]],
22+
**options: Any,
23+
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
24+
"""
25+
Get a list of threads given filter and sort options
26+
27+
:param filter: filter conditions (e.g. {"created_by_user_id": {"$eq": "user_123"}})
28+
:param sort: sort options (e.g. [{"field": "last_message_at", "direction": -1}])
29+
:return: the Server Response
30+
"""
31+
pass

0 commit comments

Comments
 (0)