stream-chat 4.25.0__py3-none-any.whl → 4.27.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 +1 -1
- stream_chat/async_chat/channel.py +21 -0
- stream_chat/async_chat/client.py +81 -9
- stream_chat/base/channel.py +27 -1
- stream_chat/base/client.py +59 -1
- stream_chat/channel.py +21 -0
- stream_chat/client.py +92 -5
- stream_chat/types/campaign.py +17 -0
- stream_chat/types/delivery_receipts.py +58 -0
- stream_chat/types/shared_locations.py +8 -0
- {stream_chat-4.25.0.dist-info → stream_chat-4.27.0.dist-info}/METADATA +31 -19
- {stream_chat-4.25.0.dist-info → stream_chat-4.27.0.dist-info}/RECORD +15 -13
- {stream_chat-4.25.0.dist-info → stream_chat-4.27.0.dist-info}/WHEEL +1 -1
- {stream_chat-4.25.0.dist-info → stream_chat-4.27.0.dist-info/licenses}/LICENSE +0 -0
- {stream_chat-4.25.0.dist-info → stream_chat-4.27.0.dist-info}/top_level.txt +0 -0
stream_chat/__pkg__.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import datetime
|
|
1
2
|
import json
|
|
2
3
|
from typing import Any, Dict, Iterable, List, Optional, Union
|
|
3
4
|
|
|
@@ -94,6 +95,10 @@ class Channel(ChannelInterface):
|
|
|
94
95
|
self, members: Iterable[Dict], message: Dict = None, **options: Any
|
|
95
96
|
) -> StreamResponse:
|
|
96
97
|
payload = {"add_members": members, "message": message, **options}
|
|
98
|
+
if "hide_history_before" in payload and isinstance(
|
|
99
|
+
payload["hide_history_before"], datetime.datetime
|
|
100
|
+
):
|
|
101
|
+
payload["hide_history_before"] = payload["hide_history_before"].isoformat()
|
|
97
102
|
return await self.client.post(self.url, data=payload)
|
|
98
103
|
|
|
99
104
|
async def assign_roles(
|
|
@@ -267,3 +272,19 @@ class Channel(ChannelInterface):
|
|
|
267
272
|
if parent_id:
|
|
268
273
|
params["parent_id"] = parent_id
|
|
269
274
|
return await self.client.get(f"{self.url}/draft", params=params)
|
|
275
|
+
|
|
276
|
+
async def add_filter_tags(
|
|
277
|
+
self,
|
|
278
|
+
tags: Iterable[str],
|
|
279
|
+
message: Dict = None,
|
|
280
|
+
) -> StreamResponse:
|
|
281
|
+
payload = {"add_filter_tags": tags, "message": message}
|
|
282
|
+
return await self.client.post(self.url, data=payload)
|
|
283
|
+
|
|
284
|
+
async def remove_filter_tags(
|
|
285
|
+
self,
|
|
286
|
+
tags: Iterable[str],
|
|
287
|
+
message: Dict = None,
|
|
288
|
+
) -> StreamResponse:
|
|
289
|
+
payload = {"remove_filter_tags": tags, "message": message}
|
|
290
|
+
return await self.client.post(self.url, data=payload)
|
stream_chat/async_chat/client.py
CHANGED
|
@@ -29,6 +29,7 @@ from stream_chat.types.segment import (
|
|
|
29
29
|
SegmentType,
|
|
30
30
|
SegmentUpdatableFields,
|
|
31
31
|
)
|
|
32
|
+
from stream_chat.types.shared_locations import SharedLocationsOptions
|
|
32
33
|
|
|
33
34
|
if sys.version_info >= (3, 8):
|
|
34
35
|
from typing import Literal
|
|
@@ -108,7 +109,7 @@ class StreamChatAsync(StreamChatInterface, AsyncContextManager):
|
|
|
108
109
|
headers["Authorization"] = self.auth_token
|
|
109
110
|
headers["stream-auth-type"] = "jwt"
|
|
110
111
|
|
|
111
|
-
if method.__name__ in ["post", "put", "patch"]:
|
|
112
|
+
if method.__name__ in ["post", "put", "patch", "delete"]:
|
|
112
113
|
serialized = json.dumps(data)
|
|
113
114
|
|
|
114
115
|
async with method(
|
|
@@ -133,8 +134,10 @@ class StreamChatAsync(StreamChatInterface, AsyncContextManager):
|
|
|
133
134
|
async def get(self, relative_url: str, params: Dict = None) -> StreamResponse:
|
|
134
135
|
return await self._make_request(self.session.get, relative_url, params, None)
|
|
135
136
|
|
|
136
|
-
async def delete(
|
|
137
|
-
|
|
137
|
+
async def delete(
|
|
138
|
+
self, relative_url: str, params: Dict = None, data: Any = None
|
|
139
|
+
) -> StreamResponse:
|
|
140
|
+
return await self._make_request(self.session.delete, relative_url, params, data)
|
|
138
141
|
|
|
139
142
|
async def patch(
|
|
140
143
|
self, relative_url: str, params: Dict = None, data: Any = None
|
|
@@ -354,8 +357,23 @@ class StreamChatAsync(StreamChatInterface, AsyncContextManager):
|
|
|
354
357
|
data.update(options)
|
|
355
358
|
return await self.put(f"messages/{message_id}", data=data)
|
|
356
359
|
|
|
357
|
-
async def delete_message(
|
|
358
|
-
|
|
360
|
+
async def delete_message(
|
|
361
|
+
self,
|
|
362
|
+
message_id: str,
|
|
363
|
+
delete_for_me: bool = False,
|
|
364
|
+
deleted_by: str = None,
|
|
365
|
+
**options: Any,
|
|
366
|
+
) -> StreamResponse:
|
|
367
|
+
if delete_for_me and not deleted_by:
|
|
368
|
+
raise ValueError("deleted_by is required when delete_for_me is True")
|
|
369
|
+
|
|
370
|
+
params = options.copy()
|
|
371
|
+
if delete_for_me:
|
|
372
|
+
body = {"delete_for_me": True, "user": {"id": deleted_by}}
|
|
373
|
+
return await self.delete(f"messages/{message_id}", None, body)
|
|
374
|
+
if deleted_by:
|
|
375
|
+
params["deleted_by"] = deleted_by
|
|
376
|
+
return await self.delete(f"messages/{message_id}", params)
|
|
359
377
|
|
|
360
378
|
async def undelete_message(self, message_id: str, user_id: str) -> StreamResponse:
|
|
361
379
|
return await self.post(
|
|
@@ -859,16 +877,12 @@ class StreamChatAsync(StreamChatInterface, AsyncContextManager):
|
|
|
859
877
|
data: Dict[str, Union[str, Dict[str, Any], List[SortParam]]] = {
|
|
860
878
|
"user_id": user_id
|
|
861
879
|
}
|
|
862
|
-
|
|
863
880
|
if filter is not None:
|
|
864
881
|
data["filter"] = cast(dict, filter)
|
|
865
|
-
|
|
866
882
|
if sort is not None:
|
|
867
883
|
data["sort"] = cast(dict, sort)
|
|
868
|
-
|
|
869
884
|
if options is not None:
|
|
870
885
|
data.update(cast(dict, options))
|
|
871
|
-
|
|
872
886
|
return await self.post("drafts/query", data=data)
|
|
873
887
|
|
|
874
888
|
async def create_reminder(
|
|
@@ -956,6 +970,64 @@ class StreamChatAsync(StreamChatInterface, AsyncContextManager):
|
|
|
956
970
|
params["user_id"] = user_id
|
|
957
971
|
return await self.post("reminders/query", data=params)
|
|
958
972
|
|
|
973
|
+
async def get_user_locations(self, user_id: str, **options: Any) -> StreamResponse:
|
|
974
|
+
params = {"user_id": user_id, **options}
|
|
975
|
+
return await self.get("users/live_locations", params=params)
|
|
976
|
+
|
|
977
|
+
async def update_user_location(
|
|
978
|
+
self,
|
|
979
|
+
user_id: str,
|
|
980
|
+
message_id: str,
|
|
981
|
+
options: Optional[SharedLocationsOptions] = None,
|
|
982
|
+
) -> StreamResponse:
|
|
983
|
+
data = {"message_id": message_id}
|
|
984
|
+
if options is not None:
|
|
985
|
+
data.update(cast(dict, options))
|
|
986
|
+
params = {"user_id": user_id, **options}
|
|
987
|
+
return await self.put("users/live_locations", data=data, params=params)
|
|
988
|
+
|
|
989
|
+
async def mark_delivered(self, data: Dict[str, Any]) -> Optional[StreamResponse]:
|
|
990
|
+
"""
|
|
991
|
+
Send the mark delivered event for this user, only works if the `delivery_receipts` setting is enabled
|
|
992
|
+
|
|
993
|
+
:param data: MarkDeliveredOptions containing latest_delivered_messages and other optional fields
|
|
994
|
+
:return: The server response or None if delivery receipts are disabled
|
|
995
|
+
"""
|
|
996
|
+
# Validate required fields
|
|
997
|
+
if not data.get("latest_delivered_messages"):
|
|
998
|
+
raise ValueError("latest_delivered_messages must not be empty")
|
|
999
|
+
|
|
1000
|
+
# Ensure either user or user_id is provided
|
|
1001
|
+
if not data.get("user") and not data.get("user_id"):
|
|
1002
|
+
raise ValueError("either user or user_id must be provided")
|
|
1003
|
+
|
|
1004
|
+
return await self.post("channels/delivered", data=data)
|
|
1005
|
+
|
|
1006
|
+
async def mark_delivered_simple(
|
|
1007
|
+
self, user_id: str, message_id: str, channel_cid: str
|
|
1008
|
+
) -> Optional[StreamResponse]:
|
|
1009
|
+
"""
|
|
1010
|
+
Convenience method to mark a message as delivered for a specific user.
|
|
1011
|
+
|
|
1012
|
+
:param user_id: The user ID
|
|
1013
|
+
:param message_id: The message ID
|
|
1014
|
+
:param channel_cid: The channel CID (channel_type:channel_id)
|
|
1015
|
+
:return: The server response or None if delivery receipts are disabled
|
|
1016
|
+
"""
|
|
1017
|
+
if not user_id:
|
|
1018
|
+
raise ValueError("user ID must not be empty")
|
|
1019
|
+
if not message_id:
|
|
1020
|
+
raise ValueError("message ID must not be empty")
|
|
1021
|
+
if not channel_cid:
|
|
1022
|
+
raise ValueError("channel CID must not be empty")
|
|
1023
|
+
|
|
1024
|
+
data = {
|
|
1025
|
+
"latest_delivered_messages": [{"cid": channel_cid, "id": message_id}],
|
|
1026
|
+
"user_id": user_id,
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
return await self.mark_delivered(data)
|
|
1030
|
+
|
|
959
1031
|
async def close(self) -> None:
|
|
960
1032
|
await self.session.close()
|
|
961
1033
|
|
stream_chat/base/channel.py
CHANGED
|
@@ -196,7 +196,7 @@ class ChannelInterface(abc.ABC):
|
|
|
196
196
|
|
|
197
197
|
:param members: member objects to add
|
|
198
198
|
:param message: An optional to show
|
|
199
|
-
:param options: additional options such as hide_history
|
|
199
|
+
:param options: additional options such as hide_history or hide_history_before
|
|
200
200
|
:return:
|
|
201
201
|
"""
|
|
202
202
|
pass
|
|
@@ -527,6 +527,32 @@ class ChannelInterface(abc.ABC):
|
|
|
527
527
|
"""
|
|
528
528
|
pass
|
|
529
529
|
|
|
530
|
+
@abc.abstractmethod
|
|
531
|
+
def add_filter_tags(
|
|
532
|
+
self, tags: Iterable[str], message: Dict = None
|
|
533
|
+
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
|
|
534
|
+
"""
|
|
535
|
+
Adds filter tags to the channel
|
|
536
|
+
|
|
537
|
+
:param tags: list of tags to add
|
|
538
|
+
:param message: optional system message
|
|
539
|
+
:return: The server response
|
|
540
|
+
"""
|
|
541
|
+
pass
|
|
542
|
+
|
|
543
|
+
@abc.abstractmethod
|
|
544
|
+
def remove_filter_tags(
|
|
545
|
+
self, tags: Iterable[str], message: Dict = None
|
|
546
|
+
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
|
|
547
|
+
"""
|
|
548
|
+
Removes filter tags from the channel
|
|
549
|
+
|
|
550
|
+
:param tags: list of tags to remove
|
|
551
|
+
:param message: optional system message
|
|
552
|
+
:return: The server response
|
|
553
|
+
"""
|
|
554
|
+
pass
|
|
555
|
+
|
|
530
556
|
|
|
531
557
|
def add_user_id(payload: Dict, user_id: str) -> Dict:
|
|
532
558
|
return {**payload, "user": {"id": user_id}}
|
stream_chat/base/client.py
CHANGED
|
@@ -17,6 +17,7 @@ from stream_chat.types.segment import (
|
|
|
17
17
|
SegmentType,
|
|
18
18
|
SegmentUpdatableFields,
|
|
19
19
|
)
|
|
20
|
+
from stream_chat.types.shared_locations import SharedLocationsOptions
|
|
20
21
|
|
|
21
22
|
if sys.version_info >= (3, 8):
|
|
22
23
|
from typing import Literal
|
|
@@ -559,10 +560,20 @@ class StreamChatInterface(abc.ABC):
|
|
|
559
560
|
|
|
560
561
|
@abc.abstractmethod
|
|
561
562
|
def delete_message(
|
|
562
|
-
self,
|
|
563
|
+
self,
|
|
564
|
+
message_id: str,
|
|
565
|
+
delete_for_me: bool = False,
|
|
566
|
+
deleted_by: str = None,
|
|
567
|
+
**options: Any,
|
|
563
568
|
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
|
|
564
569
|
"""
|
|
565
570
|
Deletes a message.
|
|
571
|
+
|
|
572
|
+
Args:
|
|
573
|
+
message_id: The ID of the message to delete
|
|
574
|
+
delete_for_me: If True, deletes the message only for the specified user
|
|
575
|
+
deleted_by: The user ID who is deleting the message (required when delete_for_me is True)
|
|
576
|
+
**options: Additional options to pass to the delete request
|
|
566
577
|
"""
|
|
567
578
|
pass
|
|
568
579
|
|
|
@@ -1505,6 +1516,53 @@ class StreamChatInterface(abc.ABC):
|
|
|
1505
1516
|
"""
|
|
1506
1517
|
pass
|
|
1507
1518
|
|
|
1519
|
+
@abc.abstractmethod
|
|
1520
|
+
def get_user_locations(
|
|
1521
|
+
self, user_id: str, **options: Any
|
|
1522
|
+
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
|
|
1523
|
+
"""
|
|
1524
|
+
Get the locations of a user.
|
|
1525
|
+
"""
|
|
1526
|
+
pass
|
|
1527
|
+
|
|
1528
|
+
@abc.abstractmethod
|
|
1529
|
+
def update_user_location(
|
|
1530
|
+
self,
|
|
1531
|
+
user_id: str,
|
|
1532
|
+
message_id: str,
|
|
1533
|
+
options: Optional[SharedLocationsOptions] = None,
|
|
1534
|
+
) -> Union[StreamResponse, Awaitable[StreamResponse]]:
|
|
1535
|
+
"""
|
|
1536
|
+
Update the location of a user.
|
|
1537
|
+
"""
|
|
1538
|
+
pass
|
|
1539
|
+
|
|
1540
|
+
@abc.abstractmethod
|
|
1541
|
+
def mark_delivered(
|
|
1542
|
+
self, data: Dict[str, Any]
|
|
1543
|
+
) -> Union[StreamResponse, Awaitable[StreamResponse], None]:
|
|
1544
|
+
"""
|
|
1545
|
+
Send the mark delivered event for this user, only works if the `delivery_receipts` setting is enabled
|
|
1546
|
+
|
|
1547
|
+
:param data: MarkDeliveredOptions containing latest_delivered_messages and other optional fields
|
|
1548
|
+
:return: The server response or None if delivery receipts are disabled
|
|
1549
|
+
"""
|
|
1550
|
+
pass
|
|
1551
|
+
|
|
1552
|
+
@abc.abstractmethod
|
|
1553
|
+
def mark_delivered_simple(
|
|
1554
|
+
self, user_id: str, message_id: str, channel_cid: str
|
|
1555
|
+
) -> Union[StreamResponse, Awaitable[StreamResponse], None]:
|
|
1556
|
+
"""
|
|
1557
|
+
Convenience method to mark a message as delivered for a specific user.
|
|
1558
|
+
|
|
1559
|
+
:param user_id: The user ID
|
|
1560
|
+
:param message_id: The message ID
|
|
1561
|
+
:param channel_cid: The channel CID (channel_type:channel_id)
|
|
1562
|
+
:return: The server response or None if delivery receipts are disabled
|
|
1563
|
+
"""
|
|
1564
|
+
pass
|
|
1565
|
+
|
|
1508
1566
|
#####################
|
|
1509
1567
|
# Private methods #
|
|
1510
1568
|
#####################
|
stream_chat/channel.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import datetime
|
|
1
2
|
import json
|
|
2
3
|
from typing import Any, Dict, Iterable, List, Optional, Union
|
|
3
4
|
|
|
@@ -95,6 +96,10 @@ class Channel(ChannelInterface):
|
|
|
95
96
|
**options: Any,
|
|
96
97
|
) -> StreamResponse:
|
|
97
98
|
payload = {"add_members": members, "message": message, **options}
|
|
99
|
+
if "hide_history_before" in payload and isinstance(
|
|
100
|
+
payload["hide_history_before"], datetime.datetime
|
|
101
|
+
):
|
|
102
|
+
payload["hide_history_before"] = payload["hide_history_before"].isoformat()
|
|
98
103
|
return self.client.post(self.url, data=payload)
|
|
99
104
|
|
|
100
105
|
def assign_roles(
|
|
@@ -271,3 +276,19 @@ class Channel(ChannelInterface):
|
|
|
271
276
|
params["parent_id"] = parent_id
|
|
272
277
|
|
|
273
278
|
return self.client.get(f"{self.url}/draft", params=params)
|
|
279
|
+
|
|
280
|
+
def add_filter_tags(
|
|
281
|
+
self,
|
|
282
|
+
tags: Iterable[str],
|
|
283
|
+
message: Dict = None,
|
|
284
|
+
) -> StreamResponse:
|
|
285
|
+
payload = {"add_filter_tags": tags, "message": message}
|
|
286
|
+
return self.client.post(self.url, data=payload)
|
|
287
|
+
|
|
288
|
+
def remove_filter_tags(
|
|
289
|
+
self,
|
|
290
|
+
tags: Iterable[str],
|
|
291
|
+
message: Dict = None,
|
|
292
|
+
) -> StreamResponse:
|
|
293
|
+
payload = {"remove_filter_tags": tags, "message": message}
|
|
294
|
+
return self.client.post(self.url, data=payload)
|
stream_chat/client.py
CHANGED
|
@@ -18,6 +18,7 @@ from stream_chat.types.segment import (
|
|
|
18
18
|
SegmentType,
|
|
19
19
|
SegmentUpdatableFields,
|
|
20
20
|
)
|
|
21
|
+
from stream_chat.types.shared_locations import SharedLocationsOptions
|
|
21
22
|
|
|
22
23
|
if sys.version_info >= (3, 8):
|
|
23
24
|
from typing import Literal
|
|
@@ -83,6 +84,10 @@ class StreamChat(StreamChatInterface):
|
|
|
83
84
|
data: Any = None,
|
|
84
85
|
) -> StreamResponse:
|
|
85
86
|
params = params or {}
|
|
87
|
+
# Convert boolean values to lowercase strings for consistency with async implementation
|
|
88
|
+
params = {
|
|
89
|
+
k: str(v).lower() if isinstance(v, bool) else v for k, v in params.items()
|
|
90
|
+
}
|
|
86
91
|
data = data or {}
|
|
87
92
|
serialized = None
|
|
88
93
|
default_params = self.get_default_params()
|
|
@@ -93,7 +98,9 @@ class StreamChat(StreamChatInterface):
|
|
|
93
98
|
|
|
94
99
|
url = f"{self.base_url}/{relative_url}"
|
|
95
100
|
|
|
96
|
-
if method.__name__ in ["post", "put", "patch"]
|
|
101
|
+
if method.__name__ in ["post", "put", "patch"] or (
|
|
102
|
+
method.__name__ == "delete" and data
|
|
103
|
+
):
|
|
97
104
|
serialized = json.dumps(data)
|
|
98
105
|
|
|
99
106
|
response = method(
|
|
@@ -118,8 +125,10 @@ class StreamChat(StreamChatInterface):
|
|
|
118
125
|
def get(self, relative_url: str, params: Dict = None) -> StreamResponse:
|
|
119
126
|
return self._make_request(self.session.get, relative_url, params, None)
|
|
120
127
|
|
|
121
|
-
def delete(
|
|
122
|
-
|
|
128
|
+
def delete(
|
|
129
|
+
self, relative_url: str, params: Dict = None, data: Any = None
|
|
130
|
+
) -> StreamResponse:
|
|
131
|
+
return self._make_request(self.session.delete, relative_url, params, data)
|
|
123
132
|
|
|
124
133
|
def patch(
|
|
125
134
|
self, relative_url: str, params: Dict = None, data: Any = None
|
|
@@ -341,8 +350,24 @@ class StreamChat(StreamChatInterface):
|
|
|
341
350
|
data.update(options)
|
|
342
351
|
return self.put(f"messages/{message_id}", data=data)
|
|
343
352
|
|
|
344
|
-
def delete_message(
|
|
345
|
-
|
|
353
|
+
def delete_message(
|
|
354
|
+
self,
|
|
355
|
+
message_id: str,
|
|
356
|
+
delete_for_me: bool = False,
|
|
357
|
+
deleted_by: str = None,
|
|
358
|
+
**options: Any,
|
|
359
|
+
) -> StreamResponse:
|
|
360
|
+
if delete_for_me and not deleted_by:
|
|
361
|
+
raise ValueError("deleted_by is required when delete_for_me is True")
|
|
362
|
+
|
|
363
|
+
params = options.copy()
|
|
364
|
+
if delete_for_me:
|
|
365
|
+
# Send in body with acting user for server-side auth compatibility
|
|
366
|
+
body = {"delete_for_me": True, "user": {"id": deleted_by}}
|
|
367
|
+
return self.delete(f"messages/{message_id}", None, body)
|
|
368
|
+
if deleted_by:
|
|
369
|
+
params["deleted_by"] = deleted_by
|
|
370
|
+
return self.delete(f"messages/{message_id}", params)
|
|
346
371
|
|
|
347
372
|
def undelete_message(self, message_id: str, user_id: str) -> StreamResponse:
|
|
348
373
|
return self.post(
|
|
@@ -898,3 +923,65 @@ class StreamChat(StreamChatInterface):
|
|
|
898
923
|
params["sort"] = sort or [{"field": "remind_at", "direction": 1}]
|
|
899
924
|
params["user_id"] = user_id
|
|
900
925
|
return self.post("reminders/query", data=params)
|
|
926
|
+
|
|
927
|
+
def get_user_locations(self, user_id: str, **options: Any) -> StreamResponse:
|
|
928
|
+
params = {"user_id": user_id, **options}
|
|
929
|
+
return self.get("users/live_locations", params=params)
|
|
930
|
+
|
|
931
|
+
def update_user_location(
|
|
932
|
+
self,
|
|
933
|
+
user_id: str,
|
|
934
|
+
message_id: str,
|
|
935
|
+
options: Optional[SharedLocationsOptions] = None,
|
|
936
|
+
) -> StreamResponse:
|
|
937
|
+
data = {"message_id": message_id}
|
|
938
|
+
if options is not None:
|
|
939
|
+
data.update(cast(dict, options))
|
|
940
|
+
params = {"user_id": user_id, **options}
|
|
941
|
+
return self.put("users/live_locations", data=data, params=params)
|
|
942
|
+
|
|
943
|
+
def mark_delivered(self, data: Dict[str, Any]) -> Optional[StreamResponse]:
|
|
944
|
+
"""
|
|
945
|
+
Send the mark delivered event for this user, only works if the `delivery_receipts` setting is enabled
|
|
946
|
+
|
|
947
|
+
:param data: MarkDeliveredOptions containing latest_delivered_messages and other optional fields
|
|
948
|
+
:return: The server response or None if delivery receipts are disabled
|
|
949
|
+
"""
|
|
950
|
+
# Validate required fields
|
|
951
|
+
if not data.get("latest_delivered_messages"):
|
|
952
|
+
raise ValueError("latest_delivered_messages must not be empty")
|
|
953
|
+
|
|
954
|
+
# Ensure either user or user_id is provided
|
|
955
|
+
if not data.get("user") and not data.get("user_id"):
|
|
956
|
+
raise ValueError("either user or user_id must be provided")
|
|
957
|
+
|
|
958
|
+
# Extract user_id from data
|
|
959
|
+
user_id = data.get("user_id") or data.get("user", {}).get("id")
|
|
960
|
+
if not user_id:
|
|
961
|
+
raise ValueError("user_id must be provided")
|
|
962
|
+
|
|
963
|
+
params = {"user_id": user_id}
|
|
964
|
+
return self.post("channels/delivered", data=data, params=params)
|
|
965
|
+
|
|
966
|
+
def mark_delivered_simple(
|
|
967
|
+
self, user_id: str, message_id: str, channel_cid: str
|
|
968
|
+
) -> Optional[StreamResponse]:
|
|
969
|
+
"""
|
|
970
|
+
Convenience method to mark a message as delivered for a specific user.
|
|
971
|
+
|
|
972
|
+
:param user_id: The user ID
|
|
973
|
+
:param message_id: The message ID
|
|
974
|
+
:param channel_cid: The channel CID (channel_type:channel_id)
|
|
975
|
+
:return: The server response or None if delivery receipts are disabled
|
|
976
|
+
"""
|
|
977
|
+
if not user_id:
|
|
978
|
+
raise ValueError("user ID must not be empty")
|
|
979
|
+
if not message_id:
|
|
980
|
+
raise ValueError("message ID must not be empty")
|
|
981
|
+
if not channel_cid:
|
|
982
|
+
raise ValueError("channel CID must not be empty")
|
|
983
|
+
data = {
|
|
984
|
+
"latest_delivered_messages": [{"cid": channel_cid, "id": message_id}],
|
|
985
|
+
"user_id": user_id,
|
|
986
|
+
}
|
|
987
|
+
return self.mark_delivered(data=data)
|
stream_chat/types/campaign.py
CHANGED
|
@@ -24,6 +24,21 @@ class MessageTemplate(TypedDict, total=False):
|
|
|
24
24
|
custom: Optional[Dict]
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
class MemberTemplate(TypedDict, total=False):
|
|
28
|
+
"""
|
|
29
|
+
Represents the data structure for a member in the members_template.
|
|
30
|
+
|
|
31
|
+
Parameters:
|
|
32
|
+
user_id: The ID of the user.
|
|
33
|
+
channel_role: The role of the user in the channel.
|
|
34
|
+
custom: Custom data for the member.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
user_id: str
|
|
38
|
+
channel_role: Optional[str]
|
|
39
|
+
custom: Optional[Dict]
|
|
40
|
+
|
|
41
|
+
|
|
27
42
|
class ChannelTemplate(TypedDict, total=False):
|
|
28
43
|
"""
|
|
29
44
|
Represents the data structure for a channel template.
|
|
@@ -32,12 +47,14 @@ class ChannelTemplate(TypedDict, total=False):
|
|
|
32
47
|
type: The type of channel.
|
|
33
48
|
id: The ID of the channel.
|
|
34
49
|
members: List of member IDs.
|
|
50
|
+
members_template: List of member templates with roles and custom data.
|
|
35
51
|
custom: Custom data.
|
|
36
52
|
"""
|
|
37
53
|
|
|
38
54
|
type: str
|
|
39
55
|
id: Optional[str]
|
|
40
56
|
members: Optional[List[str]]
|
|
57
|
+
members_template: Optional[List[MemberTemplate]]
|
|
41
58
|
custom: Optional[Dict]
|
|
42
59
|
|
|
43
60
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from typing import Dict, List, Optional
|
|
3
|
+
|
|
4
|
+
if sys.version_info >= (3, 8):
|
|
5
|
+
from typing import TypedDict
|
|
6
|
+
else:
|
|
7
|
+
from typing_extensions import TypedDict
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DeliveredMessageConfirmation(TypedDict):
|
|
11
|
+
"""
|
|
12
|
+
Confirmation of a delivered message.
|
|
13
|
+
|
|
14
|
+
Parameters:
|
|
15
|
+
cid: Channel CID (channel_type:channel_id)
|
|
16
|
+
id: Message ID
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
cid: str
|
|
20
|
+
id: str
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class MarkDeliveredOptions(TypedDict, total=False):
|
|
24
|
+
"""
|
|
25
|
+
Options for marking messages as delivered.
|
|
26
|
+
|
|
27
|
+
Parameters:
|
|
28
|
+
latest_delivered_messages: List of delivered message confirmations
|
|
29
|
+
user: Optional user object
|
|
30
|
+
user_id: Optional user ID
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
latest_delivered_messages: List[DeliveredMessageConfirmation]
|
|
34
|
+
user: Optional[Dict] # UserResponse equivalent
|
|
35
|
+
user_id: Optional[str]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ChannelReadStatus(TypedDict, total=False):
|
|
39
|
+
"""
|
|
40
|
+
Channel read status information.
|
|
41
|
+
|
|
42
|
+
Parameters:
|
|
43
|
+
last_read: Last read timestamp
|
|
44
|
+
unread_messages: Number of unread messages
|
|
45
|
+
user: User information
|
|
46
|
+
first_unread_message_id: ID of first unread message
|
|
47
|
+
last_read_message_id: ID of last read message
|
|
48
|
+
last_delivered_at: Last delivered timestamp
|
|
49
|
+
last_delivered_message_id: ID of last delivered message
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
last_read: str # ISO format string for timestamp
|
|
53
|
+
unread_messages: int
|
|
54
|
+
user: Dict # UserResponse equivalent
|
|
55
|
+
first_unread_message_id: Optional[str]
|
|
56
|
+
last_read_message_id: Optional[str]
|
|
57
|
+
last_delivered_at: Optional[str] # ISO format string for timestamp
|
|
58
|
+
last_delivered_message_id: Optional[str]
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: stream-chat
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.27.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.
|
|
10
|
+
Project-URL: Release Notes, https://github.com/GetStream/stream-chat-python/releases/tag/v4.27.0
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
12
|
Classifier: Intended Audience :: System Administrators
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
@@ -24,23 +24,35 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
24
24
|
Requires-Python: >=3.8
|
|
25
25
|
Description-Content-Type: text/markdown
|
|
26
26
|
License-File: LICENSE
|
|
27
|
-
Requires-Dist: requests
|
|
28
|
-
Requires-Dist: aiodns
|
|
29
|
-
Requires-Dist: aiohttp
|
|
30
|
-
Requires-Dist: aiofile
|
|
31
|
-
Requires-Dist: pyjwt
|
|
32
|
-
Requires-Dist:
|
|
33
|
-
Provides-Extra: ci
|
|
34
|
-
Requires-Dist: black ; extra == 'ci'
|
|
35
|
-
Requires-Dist: flake8 ; extra == 'ci'
|
|
36
|
-
Requires-Dist: flake8-isort ; extra == 'ci'
|
|
37
|
-
Requires-Dist: flake8-bugbear ; extra == 'ci'
|
|
38
|
-
Requires-Dist: pytest-cov ; extra == 'ci'
|
|
39
|
-
Requires-Dist: mypy ; extra == 'ci'
|
|
40
|
-
Requires-Dist: types-requests ; extra == 'ci'
|
|
27
|
+
Requires-Dist: requests<3,>=2.22.0
|
|
28
|
+
Requires-Dist: aiodns>=2.0.0
|
|
29
|
+
Requires-Dist: aiohttp<4,>=3.6.0
|
|
30
|
+
Requires-Dist: aiofile<4,>=3.1
|
|
31
|
+
Requires-Dist: pyjwt<3,>=2.0.0
|
|
32
|
+
Requires-Dist: typing_extensions; python_version < "3.8"
|
|
41
33
|
Provides-Extra: test
|
|
42
|
-
Requires-Dist: pytest
|
|
43
|
-
Requires-Dist: pytest-asyncio
|
|
34
|
+
Requires-Dist: pytest==8.1.1; extra == "test"
|
|
35
|
+
Requires-Dist: pytest-asyncio<=0.21.1; extra == "test"
|
|
36
|
+
Provides-Extra: ci
|
|
37
|
+
Requires-Dist: black; extra == "ci"
|
|
38
|
+
Requires-Dist: flake8; extra == "ci"
|
|
39
|
+
Requires-Dist: flake8-isort; extra == "ci"
|
|
40
|
+
Requires-Dist: flake8-bugbear; extra == "ci"
|
|
41
|
+
Requires-Dist: pytest-cov; extra == "ci"
|
|
42
|
+
Requires-Dist: mypy; extra == "ci"
|
|
43
|
+
Requires-Dist: types-requests; extra == "ci"
|
|
44
|
+
Dynamic: author
|
|
45
|
+
Dynamic: author-email
|
|
46
|
+
Dynamic: classifier
|
|
47
|
+
Dynamic: description
|
|
48
|
+
Dynamic: description-content-type
|
|
49
|
+
Dynamic: home-page
|
|
50
|
+
Dynamic: license-file
|
|
51
|
+
Dynamic: project-url
|
|
52
|
+
Dynamic: provides-extra
|
|
53
|
+
Dynamic: requires-dist
|
|
54
|
+
Dynamic: requires-python
|
|
55
|
+
Dynamic: summary
|
|
44
56
|
|
|
45
57
|
# Official Python SDK for [Stream Chat](https://getstream.io/chat/)
|
|
46
58
|
|
|
@@ -1,32 +1,34 @@
|
|
|
1
1
|
stream_chat/__init__.py,sha256=xYQuC8xcPLJxJnFWzaNaO-sVUc7IJZYe13OIPRaDBEA,116
|
|
2
|
-
stream_chat/__pkg__.py,sha256=
|
|
2
|
+
stream_chat/__pkg__.py,sha256=3vFq6KVLE2mFiPgVLpZrtO2SYgLCXYD2UEIWqWZ_dDc,206
|
|
3
3
|
stream_chat/campaign.py,sha256=Z7bBo2rGMs02JkA1k9_206J0spcSLecjdhQuRnrc2Eo,2156
|
|
4
|
-
stream_chat/channel.py,sha256=
|
|
5
|
-
stream_chat/client.py,sha256=
|
|
4
|
+
stream_chat/channel.py,sha256=40q61hI0A0iy_Q2Xdv6D94oSG47Bu1PYaBXMRX2k03g,11059
|
|
5
|
+
stream_chat/client.py,sha256=KOl4FRjlN2Af9p_yhBn5B8WFVYD9CoPDz1tZySfBIqg,37292
|
|
6
6
|
stream_chat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
stream_chat/query_threads.py,sha256=zz0w7DnTq0FR8OAvNkPH7Q1CSYaWOtoP_NAa8JgsKtE,542
|
|
8
8
|
stream_chat/segment.py,sha256=MD1de83rVsaqxcyPy8wTXDudFjxz5Mvr70z4pTkW3P0,2691
|
|
9
9
|
stream_chat/async_chat/__init__.py,sha256=V6x7yDCdXbP3vMuSan6Xm7RE_njZUvflImqOxfKRt4Y,67
|
|
10
10
|
stream_chat/async_chat/campaign.py,sha256=Bc3iHZigxserUycZK4wDuXU0wXVH2G6fIDiYNVYPkeE,1885
|
|
11
|
-
stream_chat/async_chat/channel.py,sha256=
|
|
12
|
-
stream_chat/async_chat/client.py,sha256=
|
|
11
|
+
stream_chat/async_chat/channel.py,sha256=20dj1jQVm6dU_VUDpFJ1rUqxZVJtLhQeFxjJvcFm56s,11525
|
|
12
|
+
stream_chat/async_chat/client.py,sha256=FGJaySh2YeJuWmFGz1s5JncavW4Ig_tjYhKkBdXvSMg,39437
|
|
13
13
|
stream_chat/async_chat/segment.py,sha256=G_YEwW2SXIE7huTW3Zu_rim2XkYcuFNYekLZZGDjFkA,2777
|
|
14
14
|
stream_chat/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
15
|
stream_chat/base/campaign.py,sha256=dAVkTYyirEpgyOPn8JyDebNMKeJu02vTuqgmPvdQoWU,1449
|
|
16
|
-
stream_chat/base/channel.py,sha256=
|
|
17
|
-
stream_chat/base/client.py,sha256=
|
|
16
|
+
stream_chat/base/channel.py,sha256=FC3NVtA7Oz2g4cJMu3a8jXfTjkjteqV7PPJjMI-K6Fc,17758
|
|
17
|
+
stream_chat/base/client.py,sha256=1n8JQngKNRWT7cnVKzxmVjWTCXrb0Dj2v1e2tc0eEVE,48391
|
|
18
18
|
stream_chat/base/exceptions.py,sha256=eh1qW5d6zjUrlgsHNEBebAr0jVH2UupZ06w8sp2cseI,819
|
|
19
19
|
stream_chat/base/query_threads.py,sha256=LfC09Atsw6cwL98MJjL-cGzQU4V1r7CRbRLitgBV-x8,934
|
|
20
20
|
stream_chat/base/segment.py,sha256=X82DX8Y-cERJ1OvF2tz9iIM4CBNW6tx8HGaTEXBva9I,2364
|
|
21
21
|
stream_chat/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
22
|
stream_chat/types/base.py,sha256=JKlOxQVPvMClTo0ev63Ya-K-dX-98j95qSE-KKzziEE,858
|
|
23
|
-
stream_chat/types/campaign.py,sha256=
|
|
23
|
+
stream_chat/types/campaign.py,sha256=3Hsgf3SGKA5jh-szQkGLJlmIuswKVTFQBW7vxpJVu-g,2795
|
|
24
|
+
stream_chat/types/delivery_receipts.py,sha256=ir1EYIvRCKo2pw5nMPJ_JNJck1c_9xRXOANEW_803gk,1607
|
|
24
25
|
stream_chat/types/draft.py,sha256=EJP1JkCtDFnz-DTC8p7WFWXfTazA8x5XKE7ghag7gJM,288
|
|
25
26
|
stream_chat/types/rate_limit.py,sha256=v3Z4Ur0yoEdFLiHa1CNABEej2nxPlHQ6Bpy2XxW-TYQ,165
|
|
26
27
|
stream_chat/types/segment.py,sha256=KzOi5N-VzLfj0m4zeZ9U_29ey9dxDtewtcNv9g4Aums,1273
|
|
28
|
+
stream_chat/types/shared_locations.py,sha256=2rO4e0G1RX9DXGHcg3HJt5gp33G-LRKox62hfc0skGA,200
|
|
27
29
|
stream_chat/types/stream_response.py,sha256=jWKPrOU7u6dZ2SyOK53uQCXTstrL1HshO9fA7R6Bt_A,2391
|
|
28
|
-
stream_chat-4.
|
|
29
|
-
stream_chat-4.
|
|
30
|
-
stream_chat-4.
|
|
31
|
-
stream_chat-4.
|
|
32
|
-
stream_chat-4.
|
|
30
|
+
stream_chat-4.27.0.dist-info/licenses/LICENSE,sha256=H66SBDuPWSRHzKPEdyjAk3C0THQRcGPfqqve4naQuu0,14424
|
|
31
|
+
stream_chat-4.27.0.dist-info/METADATA,sha256=9g8l7CtgHK6EXUPy4QAK2VHfo9ajjiK-0fFWQAHIRRU,7638
|
|
32
|
+
stream_chat-4.27.0.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
|
|
33
|
+
stream_chat-4.27.0.dist-info/top_level.txt,sha256=26uTfg4bWcEaFrVKlzGGgfONH1p5DDe21G07EKfYSvo,12
|
|
34
|
+
stream_chat-4.27.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|