Skip to content

Commit bf130af

Browse files
committed
api: Use batch-based narrow updates for marking messages as read.
Fixes #820.
1 parent 9960360 commit bf130af

1 file changed

Lines changed: 77 additions & 1 deletion

File tree

zulip/zulip/__init__.py

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import traceback
1111
import types
1212
import urllib.parse
13+
import warnings
1314
from configparser import ConfigParser
1415
from datetime import datetime
1516
from typing import (
@@ -901,19 +902,67 @@ def delete_message(self, message_id: int) -> Dict[str, Any]:
901902
"""
902903
return self.call_endpoint(url=f"messages/{message_id}", method="DELETE")
903904

905+
def update_message_flags_for_narrow(self, update_data: Dict[str, Any]) -> Dict[str, Any]:
906+
"""
907+
See https://zulip.com/api/update-message-flags-for-narrow for usage.
908+
"""
909+
return self.call_endpoint(url="messages/flags/narrow", method="POST", request=update_data)
910+
904911
def update_message_flags(self, update_data: Dict[str, Any]) -> Dict[str, Any]:
905912
"""
906913
See examples/update-flags for example usage.
907914
"""
908915
return self.call_endpoint(url="messages/flags", method="POST", request=update_data)
909916

917+
def _mark_as_read_using_narrow(self, narrow: List[Dict[str, Any]]) -> Dict[str, Any]:
918+
"""
919+
Helper method to batch mark messages as read using a narrow.
920+
This prevents server-side timeouts when marking a large number of messages
921+
as read (fixes Issue #820) by paginating through unread messages.
922+
"""
923+
request: Dict[str, Any] = {
924+
"anchor": "first_unread",
925+
"num_before": 0,
926+
"num_after": 1000,
927+
"narrow": narrow,
928+
"op": "add",
929+
"flag": "read",
930+
}
931+
res: Dict[str, Any] = {}
932+
while True:
933+
res = self.update_message_flags_for_narrow(request)
934+
if res.get("result") != "success":
935+
return res
936+
if res.get("found_newest", True):
937+
break
938+
if res.get("last_processed_id") is None:
939+
break
940+
request["anchor"] = res["last_processed_id"]
941+
942+
clean_res = {
943+
"result": res.get("result"),
944+
"msg": res.get("msg"),
945+
}
946+
if "complete" in res:
947+
clean_res["complete"] = res.get("complete")
948+
949+
return clean_res
950+
910951
def mark_all_as_read(self) -> Dict[str, Any]:
911952
"""
912953
Example usage:
913954
914955
>>> client.mark_all_as_read()
915956
{'result': 'success', 'msg': ''}
916957
"""
958+
warnings.warn(
959+
"`mark_all_as_read` is deprecated. Use `update_message_flags_for_narrow` instead.",
960+
DeprecationWarning,
961+
stacklevel=2,
962+
)
963+
if self.feature_level >= 155:
964+
return self._mark_as_read_using_narrow([{"operator": "is", "operand": "unread"}])
965+
917966
return self.call_endpoint(
918967
url="mark_all_as_read",
919968
method="POST",
@@ -926,6 +975,19 @@ def mark_stream_as_read(self, stream_id: int) -> Dict[str, Any]:
926975
>>> client.mark_stream_as_read(42)
927976
{'result': 'success', 'msg': ''}
928977
"""
978+
warnings.warn(
979+
"`mark_stream_as_read` is deprecated. Use `update_message_flags_for_narrow` instead.",
980+
DeprecationWarning,
981+
stacklevel=2,
982+
)
983+
if self.feature_level >= 155:
984+
return self._mark_as_read_using_narrow(
985+
[
986+
{"operator": "stream", "operand": stream_id},
987+
{"operator": "is", "operand": "unread"},
988+
]
989+
)
990+
929991
return self.call_endpoint(
930992
url="mark_stream_as_read",
931993
method="POST",
@@ -936,9 +998,23 @@ def mark_topic_as_read(self, stream_id: int, topic_name: str) -> Dict[str, Any]:
936998
"""
937999
Example usage:
9381000
939-
>>> client.mark_all_as_read(42, 'new coffee machine')
1001+
>>> client.mark_topic_as_read(42, 'new coffee machine')
9401002
{'result': 'success', 'msg': ''}
9411003
"""
1004+
warnings.warn(
1005+
"`mark_topic_as_read` is deprecated. Use `update_message_flags_for_narrow` instead.",
1006+
DeprecationWarning,
1007+
stacklevel=2,
1008+
)
1009+
if self.feature_level >= 155:
1010+
return self._mark_as_read_using_narrow(
1011+
[
1012+
{"operator": "stream", "operand": stream_id},
1013+
{"operator": "topic", "operand": topic_name},
1014+
{"operator": "is", "operand": "unread"},
1015+
]
1016+
)
1017+
9421018
return self.call_endpoint(
9431019
url="mark_topic_as_read",
9441020
method="POST",

0 commit comments

Comments
 (0)