stream-chat 4.23.0__py3-none-any.whl → 4.25.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.23.0"
3
+ __version__ = "4.25.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,
@@ -222,6 +223,22 @@ class StreamChatAsync(StreamChatInterface, AsyncContextManager):
222
223
  "query_banned_users", params={"payload": json.dumps(query_conditions)}
223
224
  )
224
225
 
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
+
225
242
  async def run_message_action(self, message_id: str, data: Dict) -> StreamResponse:
226
243
  return await self.post(f"messages/{message_id}/action", data=data)
227
244
 
@@ -360,6 +377,13 @@ class StreamChatAsync(StreamChatInterface, AsyncContextManager):
360
377
  )
361
378
  return await self.post("messages/history", data=params)
362
379
 
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
+
363
387
  async def query_users(
364
388
  self, filter_conditions: Dict, sort: List[Dict] = None, **options: Any
365
389
  ) -> StreamResponse:
@@ -825,6 +849,113 @@ class StreamChatAsync(StreamChatInterface, AsyncContextManager):
825
849
  async def unread_counts_batch(self, user_ids: List[str]) -> StreamResponse:
826
850
  return await self.post("unread_batch", data={"user_ids": user_ids})
827
851
 
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
+
874
+ async def create_reminder(
875
+ self,
876
+ message_id: str,
877
+ user_id: str,
878
+ remind_at: Optional[datetime.datetime] = None,
879
+ ) -> StreamResponse:
880
+ """
881
+ Creates a reminder for a message.
882
+
883
+ :param message_id: The ID of the message to create a reminder for
884
+ :param user_id: The ID of the user creating the reminder
885
+ :param remind_at: When to remind the user (optional)
886
+ :return: API response
887
+ """
888
+ data = {"user_id": user_id}
889
+ remind_at_timestamp = ""
890
+ if remind_at is not None:
891
+ if isinstance(remind_at, datetime.datetime):
892
+ remind_at_timestamp = remind_at.isoformat()
893
+ else:
894
+ remind_at_timestamp = str(remind_at)
895
+
896
+ data["remind_at"] = remind_at_timestamp
897
+
898
+ return await self.post(f"messages/{message_id}/reminders", data=data)
899
+
900
+ async def update_reminder(
901
+ self,
902
+ message_id: str,
903
+ user_id: str,
904
+ remind_at: Optional[datetime.datetime] = None,
905
+ ) -> StreamResponse:
906
+ """
907
+ Updates a reminder for a message.
908
+
909
+ :param message_id: The ID of the message with the reminder
910
+ :param user_id: The ID of the user who owns the reminder
911
+ :param remind_at: When to remind the user (optional)
912
+ :return: API response
913
+ """
914
+ data = {"user_id": user_id}
915
+ remind_at_timestamp = ""
916
+ if remind_at is not None:
917
+ if isinstance(remind_at, datetime.datetime):
918
+ remind_at_timestamp = remind_at.isoformat()
919
+ else:
920
+ remind_at_timestamp = str(remind_at)
921
+
922
+ data["remind_at"] = remind_at_timestamp
923
+ return await self.patch(f"messages/{message_id}/reminders", data=data)
924
+
925
+ async def delete_reminder(self, message_id: str, user_id: str) -> StreamResponse:
926
+ """
927
+ Deletes a reminder for a message.
928
+
929
+ :param message_id: The ID of the message with the reminder
930
+ :param user_id: The ID of the user who owns the reminder
931
+ :return: API response
932
+ """
933
+ return await self.delete(
934
+ f"messages/{message_id}/reminders", params={"user_id": user_id}
935
+ )
936
+
937
+ async def query_reminders(
938
+ self,
939
+ user_id: str,
940
+ filter_conditions: Dict = None,
941
+ sort: List[Dict] = None,
942
+ **options: Any,
943
+ ) -> StreamResponse:
944
+ """
945
+ Queries reminders based on filter conditions.
946
+
947
+ :param user_id: The ID of the user whose reminders to query
948
+ :param filter_conditions: Conditions to filter reminders
949
+ :param sort: Sort parameters (default: [{ field: 'remind_at', direction: 1 }])
950
+ :param options: Additional query options like limit, offset
951
+ :return: API response with reminders
952
+ """
953
+ params = options.copy()
954
+ params["filter_conditions"] = filter_conditions or {}
955
+ params["sort"] = sort or [{"field": "remind_at", "direction": 1}]
956
+ params["user_id"] = user_id
957
+ return await self.post("reminders/query", data=params)
958
+
828
959
  async def close(self) -> None:
829
960
  await self.session.close()
830
961
 
@@ -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,
@@ -354,6 +355,37 @@ class StreamChatInterface(abc.ABC):
354
355
  """
355
356
  pass
356
357
 
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
+
357
389
  @abc.abstractmethod
358
390
  def run_message_action(
359
391
  self, message_id: str, data: Dict
@@ -562,6 +594,19 @@ class StreamChatInterface(abc.ABC):
562
594
  """
563
595
  pass
564
596
 
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
+
565
610
  @abc.abstractmethod
566
611
  def query_users(
567
612
  self, filter_conditions: Dict, sort: List[Dict] = None, **options: Any
@@ -1384,6 +1429,82 @@ class StreamChatInterface(abc.ABC):
1384
1429
  """
1385
1430
  pass
1386
1431
 
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
+
1442
+ @abc.abstractmethod
1443
+ def create_reminder(
1444
+ self,
1445
+ message_id: str,
1446
+ user_id: str,
1447
+ remind_at: Optional[datetime.datetime] = None,
1448
+ ) -> Union[StreamResponse, Awaitable[StreamResponse]]:
1449
+ """
1450
+ Creates a reminder for a message.
1451
+
1452
+ :param message_id: The ID of the message to create a reminder for
1453
+ :param user_id: The ID of the user creating the reminder
1454
+ :param remind_at: When to remind the user (optional)
1455
+ :return: API response
1456
+ """
1457
+ pass
1458
+
1459
+ @abc.abstractmethod
1460
+ def update_reminder(
1461
+ self,
1462
+ message_id: str,
1463
+ user_id: str,
1464
+ remind_at: Optional[datetime.datetime] = None,
1465
+ ) -> Union[StreamResponse, Awaitable[StreamResponse]]:
1466
+ """
1467
+ Updates a reminder for a message.
1468
+
1469
+ :param message_id: The ID of the message with the reminder
1470
+ :param user_id: The ID of the user who owns the reminder
1471
+ :param remind_at: When to remind the user (optional)
1472
+ :return: API response
1473
+ """
1474
+ pass
1475
+
1476
+ @abc.abstractmethod
1477
+ def delete_reminder(
1478
+ self, message_id: str, user_id: str
1479
+ ) -> Union[StreamResponse, Awaitable[StreamResponse]]:
1480
+ """
1481
+ Deletes a reminder for a message.
1482
+
1483
+ :param message_id: The ID of the message with the reminder
1484
+ :param user_id: The ID of the user who owns the reminder
1485
+ :return: API response
1486
+ """
1487
+ pass
1488
+
1489
+ @abc.abstractmethod
1490
+ def query_reminders(
1491
+ self,
1492
+ user_id: str,
1493
+ filter_conditions: Dict = None,
1494
+ sort: List[Dict] = None,
1495
+ **options: Any,
1496
+ ) -> Union[StreamResponse, Awaitable[StreamResponse]]:
1497
+ """
1498
+ Queries reminders based on filter conditions.
1499
+
1500
+ :param user_id: The ID of the user whose reminders to query
1501
+ :param filter_conditions: Conditions to filter reminders
1502
+ :param sort: Sort parameters (default: [{ field: 'remind_at', direction: 1 }])
1503
+ :param options: Additional query options like limit, offset
1504
+ :return: API response with reminders
1505
+ """
1506
+ pass
1507
+
1387
1508
  #####################
1388
1509
  # Private methods #
1389
1510
  #####################
@@ -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,
@@ -208,6 +209,22 @@ class StreamChat(StreamChatInterface):
208
209
  "query_banned_users", params={"payload": json.dumps(query_conditions)}
209
210
  )
210
211
 
212
+ def block_user(
213
+ self, blocked_user_id: str, user_id: str, **options: Any
214
+ ) -> StreamResponse:
215
+ data = {"blocked_user_id": blocked_user_id, "user_id": user_id, **options}
216
+ return self.post("users/block", data=data)
217
+
218
+ def unblock_user(
219
+ self, blocked_user_id: str, user_id: str, **options: Any
220
+ ) -> StreamResponse:
221
+ data = {"blocked_user_id": blocked_user_id, "user_id": user_id, **options}
222
+ return self.post("users/unblock", data=data)
223
+
224
+ def get_blocked_users(self, user_id: str, **options: Any) -> StreamResponse:
225
+ params = {"user_id": user_id, **options}
226
+ return self.get("users/block", params=params)
227
+
211
228
  def run_message_action(self, message_id: str, data: Dict) -> StreamResponse:
212
229
  return self.post(f"messages/{message_id}/action", data=data)
213
230
 
@@ -342,6 +359,13 @@ class StreamChat(StreamChatInterface):
342
359
  params.update({"filter": filter, "sort": self.normalize_sort(sort)})
343
360
  return self.post("messages/history", data=params)
344
361
 
362
+ def query_threads(
363
+ self, filter: Dict = None, sort: List[Dict] = None, **options: Any
364
+ ) -> StreamResponse:
365
+ params = options.copy()
366
+ params.update({"filter": filter, "sort": self.normalize_sort(sort)})
367
+ return self.post("threads", data=params)
368
+
345
369
  def query_users(
346
370
  self, filter_conditions: Dict, sort: List[Dict] = None, **options: Any
347
371
  ) -> StreamResponse:
@@ -782,3 +806,95 @@ class StreamChat(StreamChatInterface):
782
806
 
783
807
  def unread_counts_batch(self, user_ids: List[str]) -> StreamResponse:
784
808
  return self.post("unread_batch", data={"user_ids": user_ids})
809
+
810
+ def query_drafts(
811
+ self,
812
+ user_id: str,
813
+ filter: Optional[QueryDraftsFilter] = None,
814
+ sort: Optional[List[SortParam]] = None,
815
+ options: Optional[QueryDraftsOptions] = None,
816
+ ) -> StreamResponse:
817
+ data: Dict[str, Union[str, Dict[str, Any], List[SortParam]]] = {
818
+ "user_id": user_id
819
+ }
820
+ if filter is not None:
821
+ data["filter"] = cast(dict, filter)
822
+ if sort is not None:
823
+ data["sort"] = cast(dict, sort)
824
+ if options is not None:
825
+ data.update(cast(dict, options))
826
+ return self.post("drafts/query", data=data)
827
+
828
+ def create_reminder(
829
+ self,
830
+ message_id: str,
831
+ user_id: str,
832
+ remind_at: Optional[datetime.datetime] = None,
833
+ ) -> StreamResponse:
834
+ """
835
+ Creates a reminder for a message.
836
+
837
+ :param message_id: The ID of the message to create a reminder for
838
+ :param user_id: The ID of the user creating the reminder
839
+ :param remind_at: When to remind the user (optional)
840
+ :return: API response
841
+ """
842
+ data = {"user_id": user_id}
843
+ if remind_at is not None:
844
+ # Format as ISO 8601 date string without microseconds
845
+ data["remind_at"] = remind_at.strftime("%Y-%m-%dT%H:%M:%SZ")
846
+ return self.post(f"messages/{message_id}/reminders", data=data)
847
+
848
+ def update_reminder(
849
+ self,
850
+ message_id: str,
851
+ user_id: str,
852
+ remind_at: Optional[datetime.datetime] = None,
853
+ ) -> StreamResponse:
854
+ """
855
+ Updates a reminder for a message.
856
+
857
+ :param message_id: The ID of the message with the reminder
858
+ :param user_id: The ID of the user who owns the reminder
859
+ :param remind_at: When to remind the user (optional)
860
+ :return: API response
861
+ """
862
+ data = {"user_id": user_id}
863
+ if remind_at is not None:
864
+ # Format as ISO 8601 date string without microseconds
865
+ data["remind_at"] = remind_at.strftime("%Y-%m-%dT%H:%M:%SZ")
866
+ return self.patch(f"messages/{message_id}/reminders", data=data)
867
+
868
+ def delete_reminder(self, message_id: str, user_id: str) -> StreamResponse:
869
+ """
870
+ Deletes a reminder for a message.
871
+
872
+ :param message_id: The ID of the message with the reminder
873
+ :param user_id: The ID of the user who owns the reminder
874
+ :return: API response
875
+ """
876
+ return self.delete(
877
+ f"messages/{message_id}/reminders", params={"user_id": user_id}
878
+ )
879
+
880
+ def query_reminders(
881
+ self,
882
+ user_id: str,
883
+ filter_conditions: Dict = None,
884
+ sort: List[Dict] = None,
885
+ **options: Any,
886
+ ) -> StreamResponse:
887
+ """
888
+ Queries reminders based on filter conditions.
889
+
890
+ :param user_id: The ID of the user whose reminders to query
891
+ :param filter_conditions: Conditions to filter reminders
892
+ :param sort: Sort parameters (default: [{ field: 'remind_at', direction: 1 }])
893
+ :param options: Additional query options like limit, offset
894
+ :return: API response with reminders
895
+ """
896
+ params = options.copy()
897
+ params["filter_conditions"] = filter_conditions or {}
898
+ params["sort"] = sort or [{"field": "remind_at", "direction": 1}]
899
+ params["user_id"] = user_id
900
+ return self.post("reminders/query", data=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
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: stream-chat
3
- Version: 4.23.0
3
+ Version: 4.25.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.23.0
10
+ Project-URL: Release Notes, https://github.com/GetStream/stream-chat-python/releases/tag/v4.25.0
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: Intended Audience :: System Administrators
13
13
  Classifier: Operating System :: OS Independent
@@ -1,29 +1,32 @@
1
1
  stream_chat/__init__.py,sha256=xYQuC8xcPLJxJnFWzaNaO-sVUc7IJZYe13OIPRaDBEA,116
2
- stream_chat/__pkg__.py,sha256=yY9To71nWkYKV795IUKgyX4xLM2i7sf5lHQFJRW3Bs4,206
2
+ stream_chat/__pkg__.py,sha256=WwppLHryS6nJerG5x3TNJ-ETXWjeMTqzKIs4cJCEaWY,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=dBC4J_z-kfey8G8HahsCAd84TT0qjTkn2-sDmKy1EE0,33768
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=dMwlzK7eAGQpfwLB3GU9a7rmTFlM54mRpofpFr08ko0,36454
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=jvNHiNtLDn7ErYysSDsDzsHC8IMovCRwgV8V3QpeHlM,46360
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
24
27
  stream_chat/types/stream_response.py,sha256=jWKPrOU7u6dZ2SyOK53uQCXTstrL1HshO9fA7R6Bt_A,2391
25
- stream_chat-4.23.0.dist-info/LICENSE,sha256=H66SBDuPWSRHzKPEdyjAk3C0THQRcGPfqqve4naQuu0,14424
26
- stream_chat-4.23.0.dist-info/METADATA,sha256=qErwYreb3GgmbHsHF2t3B9juYcoWkor-8L8IC-0uqoA,7405
27
- stream_chat-4.23.0.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
28
- stream_chat-4.23.0.dist-info/top_level.txt,sha256=26uTfg4bWcEaFrVKlzGGgfONH1p5DDe21G07EKfYSvo,12
29
- stream_chat-4.23.0.dist-info/RECORD,,
28
+ stream_chat-4.25.0.dist-info/LICENSE,sha256=H66SBDuPWSRHzKPEdyjAk3C0THQRcGPfqqve4naQuu0,14424
29
+ stream_chat-4.25.0.dist-info/METADATA,sha256=YBaA1MwUQDzJt8QakLoPZhB3kgFMX7xGQ9EZeaOQvI8,7405
30
+ stream_chat-4.25.0.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
31
+ stream_chat-4.25.0.dist-info/top_level.txt,sha256=26uTfg4bWcEaFrVKlzGGgfONH1p5DDe21G07EKfYSvo,12
32
+ stream_chat-4.25.0.dist-info/RECORD,,