stream-chat 4.24.0__py3-none-any.whl → 4.26.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
stream_chat/__pkg__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  __author__ = "Tommaso Barbugli"
2
2
  __copyright__ = "Copyright 2019-2022, Stream.io, Inc"
3
- __version__ = "4.24.0"
3
+ __version__ = "4.26.0"
4
4
  __maintainer__ = "Tommaso Barbugli"
5
5
  __email__ = "support@getstream.io"
6
6
  __status__ = "Production"
@@ -1,5 +1,5 @@
1
1
  import json
2
- from typing import Any, Dict, Iterable, List, Union
2
+ from typing import Any, Dict, Iterable, List, Optional, Union
3
3
 
4
4
  from stream_chat.base.channel import ChannelInterface, add_user_id
5
5
  from stream_chat.base.exceptions import StreamChannelException
@@ -84,8 +84,8 @@ class Channel(ChannelInterface):
84
84
  payload = {"set": to_set or {}, "unset": to_unset or []}
85
85
  return await self.client.patch(self.url, data=payload)
86
86
 
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})
89
89
 
90
90
  async def truncate(self, **options: Any) -> StreamResponse:
91
91
  return await self.client.post(f"{self.url}/truncate", data=options)
@@ -247,3 +247,23 @@ class Channel(ChannelInterface):
247
247
 
248
248
  payload = {"set": to_set or {}, "unset": to_unset or []}
249
249
  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)
@@ -21,6 +21,7 @@ from stream_chat.async_chat.campaign import Campaign
21
21
  from stream_chat.async_chat.segment import Segment
22
22
  from stream_chat.types.base import SortParam
23
23
  from stream_chat.types.campaign import CampaignData, QueryCampaignsOptions
24
+ from stream_chat.types.draft import QueryDraftsFilter, QueryDraftsOptions
24
25
  from stream_chat.types.segment import (
25
26
  QuerySegmentsOptions,
26
27
  QuerySegmentTargetsOptions,
@@ -28,6 +29,7 @@ from stream_chat.types.segment import (
28
29
  SegmentType,
29
30
  SegmentUpdatableFields,
30
31
  )
32
+ from stream_chat.types.shared_locations import SharedLocationsOptions
31
33
 
32
34
  if sys.version_info >= (3, 8):
33
35
  from typing import Literal
@@ -222,6 +224,22 @@ class StreamChatAsync(StreamChatInterface, AsyncContextManager):
222
224
  "query_banned_users", params={"payload": json.dumps(query_conditions)}
223
225
  )
224
226
 
227
+ async def block_user(
228
+ self, blocked_user_id: str, user_id: str, **options: Any
229
+ ) -> StreamResponse:
230
+ data = {"blocked_user_id": blocked_user_id, "user_id": user_id, **options}
231
+ return await self.post("users/block", data=data)
232
+
233
+ async def unblock_user(
234
+ self, blocked_user_id: str, user_id: str, **options: Any
235
+ ) -> StreamResponse:
236
+ data = {"blocked_user_id": blocked_user_id, "user_id": user_id, **options}
237
+ return await self.post("users/unblock", data=data)
238
+
239
+ async def get_blocked_users(self, user_id: str, **options: Any) -> StreamResponse:
240
+ params = {"user_id": user_id, **options}
241
+ return await self.get("users/block", params=params)
242
+
225
243
  async def run_message_action(self, message_id: str, data: Dict) -> StreamResponse:
226
244
  return await self.post(f"messages/{message_id}/action", data=data)
227
245
 
@@ -360,6 +378,13 @@ class StreamChatAsync(StreamChatInterface, AsyncContextManager):
360
378
  )
361
379
  return await self.post("messages/history", data=params)
362
380
 
381
+ async def query_threads(
382
+ self, filter: Dict = None, sort: List[Dict] = None, **options: Any
383
+ ) -> StreamResponse:
384
+ params = options.copy()
385
+ params.update({"filter": filter, "sort": self.normalize_sort(sort)})
386
+ return await self.post("threads", data=params)
387
+
363
388
  async def query_users(
364
389
  self, filter_conditions: Dict, sort: List[Dict] = None, **options: Any
365
390
  ) -> StreamResponse:
@@ -825,6 +850,125 @@ class StreamChatAsync(StreamChatInterface, AsyncContextManager):
825
850
  async def unread_counts_batch(self, user_ids: List[str]) -> StreamResponse:
826
851
  return await self.post("unread_batch", data={"user_ids": user_ids})
827
852
 
853
+ async def query_drafts(
854
+ self,
855
+ user_id: str,
856
+ filter: Optional[QueryDraftsFilter] = None,
857
+ sort: Optional[List[SortParam]] = None,
858
+ options: Optional[QueryDraftsOptions] = None,
859
+ ) -> StreamResponse:
860
+ data: Dict[str, Union[str, Dict[str, Any], List[SortParam]]] = {
861
+ "user_id": user_id
862
+ }
863
+ if filter is not None:
864
+ data["filter"] = cast(dict, filter)
865
+ if sort is not None:
866
+ data["sort"] = cast(dict, sort)
867
+ if options is not None:
868
+ data.update(cast(dict, options))
869
+ return await self.post("drafts/query", data=data)
870
+
871
+ async def create_reminder(
872
+ self,
873
+ message_id: str,
874
+ user_id: str,
875
+ remind_at: Optional[datetime.datetime] = None,
876
+ ) -> StreamResponse:
877
+ """
878
+ Creates a reminder for a message.
879
+
880
+ :param message_id: The ID of the message to create a reminder for
881
+ :param user_id: The ID of the user creating the reminder
882
+ :param remind_at: When to remind the user (optional)
883
+ :return: API response
884
+ """
885
+ data = {"user_id": user_id}
886
+ remind_at_timestamp = ""
887
+ if remind_at is not None:
888
+ if isinstance(remind_at, datetime.datetime):
889
+ remind_at_timestamp = remind_at.isoformat()
890
+ else:
891
+ remind_at_timestamp = str(remind_at)
892
+
893
+ data["remind_at"] = remind_at_timestamp
894
+
895
+ return await self.post(f"messages/{message_id}/reminders", data=data)
896
+
897
+ async def update_reminder(
898
+ self,
899
+ message_id: str,
900
+ user_id: str,
901
+ remind_at: Optional[datetime.datetime] = None,
902
+ ) -> StreamResponse:
903
+ """
904
+ Updates a reminder for a message.
905
+
906
+ :param message_id: The ID of the message with the reminder
907
+ :param user_id: The ID of the user who owns the reminder
908
+ :param remind_at: When to remind the user (optional)
909
+ :return: API response
910
+ """
911
+ data = {"user_id": user_id}
912
+ remind_at_timestamp = ""
913
+ if remind_at is not None:
914
+ if isinstance(remind_at, datetime.datetime):
915
+ remind_at_timestamp = remind_at.isoformat()
916
+ else:
917
+ remind_at_timestamp = str(remind_at)
918
+
919
+ data["remind_at"] = remind_at_timestamp
920
+ return await self.patch(f"messages/{message_id}/reminders", data=data)
921
+
922
+ async def delete_reminder(self, message_id: str, user_id: str) -> StreamResponse:
923
+ """
924
+ Deletes a reminder for a message.
925
+
926
+ :param message_id: The ID of the message with the reminder
927
+ :param user_id: The ID of the user who owns the reminder
928
+ :return: API response
929
+ """
930
+ return await self.delete(
931
+ f"messages/{message_id}/reminders", params={"user_id": user_id}
932
+ )
933
+
934
+ async def query_reminders(
935
+ self,
936
+ user_id: str,
937
+ filter_conditions: Dict = None,
938
+ sort: List[Dict] = None,
939
+ **options: Any,
940
+ ) -> StreamResponse:
941
+ """
942
+ Queries reminders based on filter conditions.
943
+
944
+ :param user_id: The ID of the user whose reminders to query
945
+ :param filter_conditions: Conditions to filter reminders
946
+ :param sort: Sort parameters (default: [{ field: 'remind_at', direction: 1 }])
947
+ :param options: Additional query options like limit, offset
948
+ :return: API response with reminders
949
+ """
950
+ params = options.copy()
951
+ params["filter_conditions"] = filter_conditions or {}
952
+ params["sort"] = sort or [{"field": "remind_at", "direction": 1}]
953
+ params["user_id"] = user_id
954
+ return await self.post("reminders/query", data=params)
955
+
956
+ async def get_user_locations(self, user_id: str, **options: Any) -> StreamResponse:
957
+ params = {"user_id": user_id, **options}
958
+ return await self.get("users/live_locations", params=params)
959
+
960
+ async def update_user_location(
961
+ self,
962
+ user_id: str,
963
+ message_id: str,
964
+ options: Optional[SharedLocationsOptions] = None,
965
+ ) -> StreamResponse:
966
+ data = {"message_id": message_id}
967
+ if options is not None:
968
+ data.update(cast(dict, options))
969
+ params = {"user_id": user_id, **options}
970
+ return await self.put("users/live_locations", data=data, params=params)
971
+
828
972
  async def close(self) -> None:
829
973
  await self.session.close()
830
974
 
@@ -1,5 +1,5 @@
1
1
  import abc
2
- from typing import Any, Awaitable, Dict, Iterable, List, Union
2
+ from typing import Any, Awaitable, Dict, Iterable, List, Optional, Union
3
3
 
4
4
  from stream_chat.base.client import StreamChatInterface
5
5
  from stream_chat.base.exceptions import StreamChannelException
@@ -165,7 +165,9 @@ class ChannelInterface(abc.ABC):
165
165
  pass
166
166
 
167
167
  @abc.abstractmethod
168
- def delete(self) -> Union[StreamResponse, Awaitable[StreamResponse]]:
168
+ def delete(
169
+ self, hard: bool = False
170
+ ) -> Union[StreamResponse, Awaitable[StreamResponse]]:
169
171
  """
170
172
  Delete the channel. Messages are permanently removed.
171
173
 
@@ -486,6 +488,45 @@ class ChannelInterface(abc.ABC):
486
488
  """
487
489
  pass
488
490
 
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
+
489
530
 
490
531
  def add_user_id(payload: Dict, user_id: str) -> Dict:
491
532
  return {**payload, "user": {"id": user_id}}
@@ -9,6 +9,7 @@ from typing import Any, Awaitable, Dict, Iterable, List, Optional, TypeVar, Unio
9
9
 
10
10
  from stream_chat.types.base import SortParam
11
11
  from stream_chat.types.campaign import CampaignData, QueryCampaignsOptions
12
+ from stream_chat.types.draft import QueryDraftsFilter, QueryDraftsOptions
12
13
  from stream_chat.types.segment import (
13
14
  QuerySegmentsOptions,
14
15
  QuerySegmentTargetsOptions,
@@ -16,6 +17,7 @@ from stream_chat.types.segment import (
16
17
  SegmentType,
17
18
  SegmentUpdatableFields,
18
19
  )
20
+ from stream_chat.types.shared_locations import SharedLocationsOptions
19
21
 
20
22
  if sys.version_info >= (3, 8):
21
23
  from typing import Literal
@@ -354,6 +356,37 @@ class StreamChatInterface(abc.ABC):
354
356
  """
355
357
  pass
356
358
 
359
+ @abc.abstractmethod
360
+ def block_user(
361
+ self, blocked_user_id: str, user_id: str, **options: Any
362
+ ) -> Union[StreamResponse, Awaitable[StreamResponse]]:
363
+ """
364
+ Blocks a user. When a user is blocked, they will not be able to communicate with the
365
+ blocking user in 1-on-1 channels, and will not be able to add the blocking user to channels.
366
+ To unblock a user, use `unblock_user` method.
367
+ """
368
+ pass
369
+
370
+ @abc.abstractmethod
371
+ def unblock_user(
372
+ self, blocked_user_id: str, user_id: str, **options: Any
373
+ ) -> Union[StreamResponse, Awaitable[StreamResponse]]:
374
+ """
375
+ Unblocks a user. This allows the previously blocked user to communicate with the
376
+ unblocking user in 1-on-1 channels again, and all previous messages become visible.
377
+ To block a user, use `block_user` method.
378
+ """
379
+ pass
380
+
381
+ @abc.abstractmethod
382
+ def get_blocked_users(
383
+ self, user_id: str, **options: Any
384
+ ) -> Union[StreamResponse, Awaitable[StreamResponse]]:
385
+ """
386
+ Retrieves the list of users that have been blocked by the specified user.
387
+ """
388
+ pass
389
+
357
390
  @abc.abstractmethod
358
391
  def run_message_action(
359
392
  self, message_id: str, data: Dict
@@ -562,6 +595,19 @@ class StreamChatInterface(abc.ABC):
562
595
  """
563
596
  pass
564
597
 
598
+ @abc.abstractmethod
599
+ def query_threads(
600
+ self, filter: Dict = None, sort: List[Dict] = None, **options: Any
601
+ ) -> Union[StreamResponse, Awaitable[StreamResponse]]:
602
+ """
603
+ 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.
604
+
605
+ :param filter: Filter conditions for the query
606
+ :param sort: Sort conditions for the query
607
+ :return: StreamResponse containing the threads
608
+ """
609
+ pass
610
+
565
611
  @abc.abstractmethod
566
612
  def query_users(
567
613
  self, filter_conditions: Dict, sort: List[Dict] = None, **options: Any
@@ -1384,6 +1430,103 @@ class StreamChatInterface(abc.ABC):
1384
1430
  """
1385
1431
  pass
1386
1432
 
1433
+ @abc.abstractmethod
1434
+ def query_drafts(
1435
+ self,
1436
+ user_id: str,
1437
+ filter: Optional[QueryDraftsFilter] = None,
1438
+ sort: Optional[List[SortParam]] = None,
1439
+ options: Optional[QueryDraftsOptions] = None,
1440
+ ) -> Union[StreamResponse, Awaitable[StreamResponse]]:
1441
+ pass
1442
+
1443
+ @abc.abstractmethod
1444
+ def create_reminder(
1445
+ self,
1446
+ message_id: str,
1447
+ user_id: str,
1448
+ remind_at: Optional[datetime.datetime] = None,
1449
+ ) -> Union[StreamResponse, Awaitable[StreamResponse]]:
1450
+ """
1451
+ Creates a reminder for a message.
1452
+
1453
+ :param message_id: The ID of the message to create a reminder for
1454
+ :param user_id: The ID of the user creating the reminder
1455
+ :param remind_at: When to remind the user (optional)
1456
+ :return: API response
1457
+ """
1458
+ pass
1459
+
1460
+ @abc.abstractmethod
1461
+ def update_reminder(
1462
+ self,
1463
+ message_id: str,
1464
+ user_id: str,
1465
+ remind_at: Optional[datetime.datetime] = None,
1466
+ ) -> Union[StreamResponse, Awaitable[StreamResponse]]:
1467
+ """
1468
+ Updates a reminder for a message.
1469
+
1470
+ :param message_id: The ID of the message with the reminder
1471
+ :param user_id: The ID of the user who owns the reminder
1472
+ :param remind_at: When to remind the user (optional)
1473
+ :return: API response
1474
+ """
1475
+ pass
1476
+
1477
+ @abc.abstractmethod
1478
+ def delete_reminder(
1479
+ self, message_id: str, user_id: str
1480
+ ) -> Union[StreamResponse, Awaitable[StreamResponse]]:
1481
+ """
1482
+ Deletes a reminder for a message.
1483
+
1484
+ :param message_id: The ID of the message with the reminder
1485
+ :param user_id: The ID of the user who owns the reminder
1486
+ :return: API response
1487
+ """
1488
+ pass
1489
+
1490
+ @abc.abstractmethod
1491
+ def query_reminders(
1492
+ self,
1493
+ user_id: str,
1494
+ filter_conditions: Dict = None,
1495
+ sort: List[Dict] = None,
1496
+ **options: Any,
1497
+ ) -> Union[StreamResponse, Awaitable[StreamResponse]]:
1498
+ """
1499
+ Queries reminders based on filter conditions.
1500
+
1501
+ :param user_id: The ID of the user whose reminders to query
1502
+ :param filter_conditions: Conditions to filter reminders
1503
+ :param sort: Sort parameters (default: [{ field: 'remind_at', direction: 1 }])
1504
+ :param options: Additional query options like limit, offset
1505
+ :return: API response with reminders
1506
+ """
1507
+ pass
1508
+
1509
+ @abc.abstractmethod
1510
+ def get_user_locations(
1511
+ self, user_id: str, **options: Any
1512
+ ) -> Union[StreamResponse, Awaitable[StreamResponse]]:
1513
+ """
1514
+ Get the locations of a user.
1515
+ """
1516
+ pass
1517
+
1518
+ @abc.abstractmethod
1519
+ def update_user_location(
1520
+ self,
1521
+ user_id: str,
1522
+ message_id: str,
1523
+ options: Optional[SharedLocationsOptions] = None,
1524
+ ) -> Union[StreamResponse, Awaitable[StreamResponse]]:
1525
+ """
1526
+ Update the location of a user.
1527
+ """
1528
+ pass
1529
+
1387
1530
  #####################
1388
1531
  # Private methods #
1389
1532
  #####################
@@ -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
stream_chat/channel.py CHANGED
@@ -1,5 +1,5 @@
1
1
  import json
2
- from typing import Any, Dict, Iterable, List, Union
2
+ from typing import Any, Dict, Iterable, List, Optional, Union
3
3
 
4
4
  from stream_chat.base.channel import ChannelInterface, add_user_id
5
5
  from stream_chat.base.exceptions import StreamChannelException
@@ -82,8 +82,8 @@ class Channel(ChannelInterface):
82
82
  payload = {"set": to_set or {}, "unset": to_unset or []}
83
83
  return self.client.patch(self.url, data=payload)
84
84
 
85
- def delete(self) -> StreamResponse:
86
- return self.client.delete(self.url)
85
+ def delete(self, hard: bool = False) -> StreamResponse:
86
+ return self.client.delete(self.url, params={"hard_delete": hard})
87
87
 
88
88
  def truncate(self, **options: Any) -> StreamResponse:
89
89
  return self.client.post(f"{self.url}/truncate", data=options)
@@ -248,3 +248,26 @@ class Channel(ChannelInterface):
248
248
 
249
249
  payload = {"set": to_set or {}, "unset": to_unset or []}
250
250
  return self.client.patch(f"{self.url}/member/{user_id}", data=payload)
251
+
252
+ def create_draft(self, message: Dict, user_id: str) -> StreamResponse:
253
+ message["user_id"] = user_id
254
+ payload = {"message": message}
255
+ return self.client.post(f"{self.url}/draft", data=payload)
256
+
257
+ def delete_draft(
258
+ self, user_id: str, parent_id: Optional[str] = None
259
+ ) -> StreamResponse:
260
+ params = {"user_id": user_id}
261
+ if parent_id:
262
+ params["parent_id"] = parent_id
263
+
264
+ return self.client.delete(f"{self.url}/draft", params=params)
265
+
266
+ def get_draft(
267
+ self, user_id: str, parent_id: Optional[str] = None
268
+ ) -> StreamResponse:
269
+ params = {"user_id": user_id}
270
+ if parent_id:
271
+ params["parent_id"] = parent_id
272
+
273
+ return self.client.get(f"{self.url}/draft", params=params)
stream_chat/client.py CHANGED
@@ -10,6 +10,7 @@ from stream_chat.campaign import Campaign
10
10
  from stream_chat.segment import Segment
11
11
  from stream_chat.types.base import SortParam
12
12
  from stream_chat.types.campaign import CampaignData, QueryCampaignsOptions
13
+ from stream_chat.types.draft import QueryDraftsFilter, QueryDraftsOptions
13
14
  from stream_chat.types.segment import (
14
15
  QuerySegmentsOptions,
15
16
  QuerySegmentTargetsOptions,
@@ -17,6 +18,7 @@ from stream_chat.types.segment import (
17
18
  SegmentType,
18
19
  SegmentUpdatableFields,
19
20
  )
21
+ from stream_chat.types.shared_locations import SharedLocationsOptions
20
22
 
21
23
  if sys.version_info >= (3, 8):
22
24
  from typing import Literal
@@ -208,6 +210,22 @@ class StreamChat(StreamChatInterface):
208
210
  "query_banned_users", params={"payload": json.dumps(query_conditions)}
209
211
  )
210
212
 
213
+ def block_user(
214
+ self, blocked_user_id: str, user_id: str, **options: Any
215
+ ) -> StreamResponse:
216
+ data = {"blocked_user_id": blocked_user_id, "user_id": user_id, **options}
217
+ return self.post("users/block", data=data)
218
+
219
+ def unblock_user(
220
+ self, blocked_user_id: str, user_id: str, **options: Any
221
+ ) -> StreamResponse:
222
+ data = {"blocked_user_id": blocked_user_id, "user_id": user_id, **options}
223
+ return self.post("users/unblock", data=data)
224
+
225
+ def get_blocked_users(self, user_id: str, **options: Any) -> StreamResponse:
226
+ params = {"user_id": user_id, **options}
227
+ return self.get("users/block", params=params)
228
+
211
229
  def run_message_action(self, message_id: str, data: Dict) -> StreamResponse:
212
230
  return self.post(f"messages/{message_id}/action", data=data)
213
231
 
@@ -342,6 +360,13 @@ class StreamChat(StreamChatInterface):
342
360
  params.update({"filter": filter, "sort": self.normalize_sort(sort)})
343
361
  return self.post("messages/history", data=params)
344
362
 
363
+ def query_threads(
364
+ self, filter: Dict = None, sort: List[Dict] = None, **options: Any
365
+ ) -> StreamResponse:
366
+ params = options.copy()
367
+ params.update({"filter": filter, "sort": self.normalize_sort(sort)})
368
+ return self.post("threads", data=params)
369
+
345
370
  def query_users(
346
371
  self, filter_conditions: Dict, sort: List[Dict] = None, **options: Any
347
372
  ) -> StreamResponse:
@@ -782,3 +807,111 @@ class StreamChat(StreamChatInterface):
782
807
 
783
808
  def unread_counts_batch(self, user_ids: List[str]) -> StreamResponse:
784
809
  return self.post("unread_batch", data={"user_ids": user_ids})
810
+
811
+ def query_drafts(
812
+ self,
813
+ user_id: str,
814
+ filter: Optional[QueryDraftsFilter] = None,
815
+ sort: Optional[List[SortParam]] = None,
816
+ options: Optional[QueryDraftsOptions] = None,
817
+ ) -> StreamResponse:
818
+ data: Dict[str, Union[str, Dict[str, Any], List[SortParam]]] = {
819
+ "user_id": user_id
820
+ }
821
+ if filter is not None:
822
+ data["filter"] = cast(dict, filter)
823
+ if sort is not None:
824
+ data["sort"] = cast(dict, sort)
825
+ if options is not None:
826
+ data.update(cast(dict, options))
827
+ return self.post("drafts/query", data=data)
828
+
829
+ def create_reminder(
830
+ self,
831
+ message_id: str,
832
+ user_id: str,
833
+ remind_at: Optional[datetime.datetime] = None,
834
+ ) -> StreamResponse:
835
+ """
836
+ Creates a reminder for a message.
837
+
838
+ :param message_id: The ID of the message to create a reminder for
839
+ :param user_id: The ID of the user creating the reminder
840
+ :param remind_at: When to remind the user (optional)
841
+ :return: API response
842
+ """
843
+ data = {"user_id": user_id}
844
+ if remind_at is not None:
845
+ # Format as ISO 8601 date string without microseconds
846
+ data["remind_at"] = remind_at.strftime("%Y-%m-%dT%H:%M:%SZ")
847
+ return self.post(f"messages/{message_id}/reminders", data=data)
848
+
849
+ def update_reminder(
850
+ self,
851
+ message_id: str,
852
+ user_id: str,
853
+ remind_at: Optional[datetime.datetime] = None,
854
+ ) -> StreamResponse:
855
+ """
856
+ Updates a reminder for a message.
857
+
858
+ :param message_id: The ID of the message with the reminder
859
+ :param user_id: The ID of the user who owns the reminder
860
+ :param remind_at: When to remind the user (optional)
861
+ :return: API response
862
+ """
863
+ data = {"user_id": user_id}
864
+ if remind_at is not None:
865
+ # Format as ISO 8601 date string without microseconds
866
+ data["remind_at"] = remind_at.strftime("%Y-%m-%dT%H:%M:%SZ")
867
+ return self.patch(f"messages/{message_id}/reminders", data=data)
868
+
869
+ def delete_reminder(self, message_id: str, user_id: str) -> StreamResponse:
870
+ """
871
+ Deletes a reminder for a message.
872
+
873
+ :param message_id: The ID of the message with the reminder
874
+ :param user_id: The ID of the user who owns the reminder
875
+ :return: API response
876
+ """
877
+ return self.delete(
878
+ f"messages/{message_id}/reminders", params={"user_id": user_id}
879
+ )
880
+
881
+ def query_reminders(
882
+ self,
883
+ user_id: str,
884
+ filter_conditions: Dict = None,
885
+ sort: List[Dict] = None,
886
+ **options: Any,
887
+ ) -> StreamResponse:
888
+ """
889
+ Queries reminders based on filter conditions.
890
+
891
+ :param user_id: The ID of the user whose reminders to query
892
+ :param filter_conditions: Conditions to filter reminders
893
+ :param sort: Sort parameters (default: [{ field: 'remind_at', direction: 1 }])
894
+ :param options: Additional query options like limit, offset
895
+ :return: API response with reminders
896
+ """
897
+ params = options.copy()
898
+ params["filter_conditions"] = filter_conditions or {}
899
+ params["sort"] = sort or [{"field": "remind_at", "direction": 1}]
900
+ params["user_id"] = user_id
901
+ return self.post("reminders/query", data=params)
902
+
903
+ def get_user_locations(self, user_id: str, **options: Any) -> StreamResponse:
904
+ params = {"user_id": user_id, **options}
905
+ return self.get("users/live_locations", params=params)
906
+
907
+ def update_user_location(
908
+ self,
909
+ user_id: str,
910
+ message_id: str,
911
+ options: Optional[SharedLocationsOptions] = None,
912
+ ) -> StreamResponse:
913
+ data = {"message_id": message_id}
914
+ if options is not None:
915
+ data.update(cast(dict, options))
916
+ params = {"user_id": user_id, **options}
917
+ return self.put("users/live_locations", data=data, params=params)
@@ -0,0 +1,15 @@
1
+ from typing import Any, Awaitable, Dict, List, Union
2
+
3
+ from stream_chat.base.query_threads import QueryThreadsInterface
4
+ from stream_chat.types.stream_response import StreamResponse
5
+
6
+
7
+ class QueryThreads(QueryThreadsInterface):
8
+ def query_threads(
9
+ self,
10
+ filter: Dict[str, Dict[str, Any]],
11
+ sort: List[Dict[str, Any]],
12
+ **options: Any,
13
+ ) -> Union[StreamResponse, Awaitable[StreamResponse]]:
14
+ payload = {"filter": filter, "sort": sort, **options}
15
+ return self.client.post(self.url, data=payload)
@@ -0,0 +1,14 @@
1
+ from datetime import datetime
2
+ from typing import Optional, TypedDict
3
+
4
+ from stream_chat.types.base import Pager
5
+
6
+
7
+ class QueryDraftsFilter(TypedDict):
8
+ channel_cid: Optional[str]
9
+ parent_id: Optional[str]
10
+ created_at: Optional[datetime]
11
+
12
+
13
+ class QueryDraftsOptions(Pager):
14
+ pass
@@ -0,0 +1,8 @@
1
+ from datetime import datetime
2
+ from typing import Optional, TypedDict
3
+
4
+
5
+ class SharedLocationsOptions(TypedDict):
6
+ longitude: Optional[int]
7
+ latitude: Optional[int]
8
+ end_at: Optional[datetime]
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: stream-chat
3
- Version: 4.24.0
3
+ Version: 4.26.0
4
4
  Summary: Client for Stream Chat.
5
5
  Home-page: https://github.com/GetStream/stream-chat-python
6
6
  Author: Tommaso Barbugli
7
7
  Author-email: support@getstream.io
8
8
  Project-URL: Bug Tracker, https://github.com/GetStream/stream-chat-python/issues
9
9
  Project-URL: Documentation, https://getstream.io/activity-feeds/docs/python/?language=python
10
- Project-URL: Release Notes, https://github.com/GetStream/stream-chat-python/releases/tag/v4.24.0
10
+ Project-URL: Release Notes, https://github.com/GetStream/stream-chat-python/releases/tag/v4.26.0
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: Intended Audience :: System Administrators
13
13
  Classifier: Operating System :: OS Independent
@@ -1,29 +1,33 @@
1
1
  stream_chat/__init__.py,sha256=xYQuC8xcPLJxJnFWzaNaO-sVUc7IJZYe13OIPRaDBEA,116
2
- stream_chat/__pkg__.py,sha256=IwKYHS4BFoMUTOU36BlaVyW5pU5_TpUKHf_Ja-nfF4Q,206
2
+ stream_chat/__pkg__.py,sha256=WBnBeASAZkPIdtP-mtFIDmizXhGSF3Y9221LiaWXQBM,206
3
3
  stream_chat/campaign.py,sha256=Z7bBo2rGMs02JkA1k9_206J0spcSLecjdhQuRnrc2Eo,2156
4
- stream_chat/channel.py,sha256=LnlHx1CDDnoxq4fCQ2sqlgjzIgPt0MmtKqph4240Uyg,9489
5
- stream_chat/client.py,sha256=xSzqPBVdtdR__tCiInKSvWhcQXb1qvB4Y1PWmWl_rTw,29335
4
+ stream_chat/channel.py,sha256=KP8aSKFMG8iE_YUR1VwVp0-rNLmufETQRriWJ18Omc4,10328
5
+ stream_chat/client.py,sha256=YzZanTE_fQm9xLMkR1KpnrWwDtu9MrmJ-ogsNtD9S_k,34450
6
6
  stream_chat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ stream_chat/query_threads.py,sha256=zz0w7DnTq0FR8OAvNkPH7Q1CSYaWOtoP_NAa8JgsKtE,542
7
8
  stream_chat/segment.py,sha256=MD1de83rVsaqxcyPy8wTXDudFjxz5Mvr70z4pTkW3P0,2691
8
9
  stream_chat/async_chat/__init__.py,sha256=V6x7yDCdXbP3vMuSan6Xm7RE_njZUvflImqOxfKRt4Y,67
9
10
  stream_chat/async_chat/campaign.py,sha256=Bc3iHZigxserUycZK4wDuXU0wXVH2G6fIDiYNVYPkeE,1885
10
- stream_chat/async_chat/channel.py,sha256=-n-Fq3MrIhGy6DzyHwOOHijSrDAudUxV0Akp-OVn7V0,9919
11
- stream_chat/async_chat/client.py,sha256=frzDqBguHqNy_ztABCNwb4veg0GSNBYjzEwKKf7gpNI,31638
11
+ stream_chat/async_chat/channel.py,sha256=R7r8kIJ3SjQN-jlF27Sp49ZGYRJl7ebh1pJ1cSIbSsg,10770
12
+ stream_chat/async_chat/client.py,sha256=1vMEWsnwPeOY0ereMH5aAW_nvT7sx4szIhey1nHtcyo,37156
12
13
  stream_chat/async_chat/segment.py,sha256=G_YEwW2SXIE7huTW3Zu_rim2XkYcuFNYekLZZGDjFkA,2777
13
14
  stream_chat/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
15
  stream_chat/base/campaign.py,sha256=dAVkTYyirEpgyOPn8JyDebNMKeJu02vTuqgmPvdQoWU,1449
15
- stream_chat/base/channel.py,sha256=bK-bbDFQquPskktXSu3UspWgOsH0EOBaHVpyg4vt2VM,15684
16
- stream_chat/base/client.py,sha256=jxqWN5Q00Hu_bw4SoiWxvrlSPMnEvn8AOqEaFBeFSU4,42151
16
+ stream_chat/base/channel.py,sha256=FSYnKbfPPPpjYO8ODGw3E3udRwaV-phngsEoMgV1T9o,16986
17
+ stream_chat/base/client.py,sha256=3wty1PSXacU_lLqUC27jt8fiar1vtdywiqZ9UU4w008,46968
17
18
  stream_chat/base/exceptions.py,sha256=eh1qW5d6zjUrlgsHNEBebAr0jVH2UupZ06w8sp2cseI,819
19
+ stream_chat/base/query_threads.py,sha256=LfC09Atsw6cwL98MJjL-cGzQU4V1r7CRbRLitgBV-x8,934
18
20
  stream_chat/base/segment.py,sha256=X82DX8Y-cERJ1OvF2tz9iIM4CBNW6tx8HGaTEXBva9I,2364
19
21
  stream_chat/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
22
  stream_chat/types/base.py,sha256=JKlOxQVPvMClTo0ev63Ya-K-dX-98j95qSE-KKzziEE,858
21
23
  stream_chat/types/campaign.py,sha256=JyAn08oMaEsxPSqmVTdsfJK4xpfErPQV7Xr7zLQm99M,2293
24
+ stream_chat/types/draft.py,sha256=EJP1JkCtDFnz-DTC8p7WFWXfTazA8x5XKE7ghag7gJM,288
22
25
  stream_chat/types/rate_limit.py,sha256=v3Z4Ur0yoEdFLiHa1CNABEej2nxPlHQ6Bpy2XxW-TYQ,165
23
26
  stream_chat/types/segment.py,sha256=KzOi5N-VzLfj0m4zeZ9U_29ey9dxDtewtcNv9g4Aums,1273
27
+ stream_chat/types/shared_locations.py,sha256=2rO4e0G1RX9DXGHcg3HJt5gp33G-LRKox62hfc0skGA,200
24
28
  stream_chat/types/stream_response.py,sha256=jWKPrOU7u6dZ2SyOK53uQCXTstrL1HshO9fA7R6Bt_A,2391
25
- stream_chat-4.24.0.dist-info/LICENSE,sha256=H66SBDuPWSRHzKPEdyjAk3C0THQRcGPfqqve4naQuu0,14424
26
- stream_chat-4.24.0.dist-info/METADATA,sha256=LAu1aIfiqQ9v-60T1xavXjxxY9s15kh5O-zBDIIN7pA,7405
27
- stream_chat-4.24.0.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
28
- stream_chat-4.24.0.dist-info/top_level.txt,sha256=26uTfg4bWcEaFrVKlzGGgfONH1p5DDe21G07EKfYSvo,12
29
- stream_chat-4.24.0.dist-info/RECORD,,
29
+ stream_chat-4.26.0.dist-info/LICENSE,sha256=H66SBDuPWSRHzKPEdyjAk3C0THQRcGPfqqve4naQuu0,14424
30
+ stream_chat-4.26.0.dist-info/METADATA,sha256=nu30qax59vfLVQN-1bJm3sf-hMEVOaRrQOWlbTXR8Ag,7405
31
+ stream_chat-4.26.0.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
32
+ stream_chat-4.26.0.dist-info/top_level.txt,sha256=26uTfg4bWcEaFrVKlzGGgfONH1p5DDe21G07EKfYSvo,12
33
+ stream_chat-4.26.0.dist-info/RECORD,,