1010import traceback
1111import types
1212import urllib .parse
13+ import warnings
1314from configparser import ConfigParser
1415from datetime import datetime
1516from typing import (
@@ -901,19 +902,61 @@ 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+ return {"result" : "success" , "msg" : "" }
942+
910943 def mark_all_as_read (self ) -> Dict [str , Any ]:
911944 """
912945 Example usage:
913946
914947 >>> client.mark_all_as_read()
915948 {'result': 'success', 'msg': ''}
916949 """
950+ warnings .warn (
951+ "`mark_all_as_read` is deprecated. Use `update_message_flags_for_narrow` instead." ,
952+ DeprecationWarning ,
953+ stacklevel = 2 ,
954+ )
955+ if self .feature_level >= 155 :
956+ res = self ._mark_as_read_using_narrow ([{"operator" : "is" , "operand" : "unread" }])
957+ res ["complete" ] = True
958+ return res
959+
917960 return self .call_endpoint (
918961 url = "mark_all_as_read" ,
919962 method = "POST" ,
@@ -926,6 +969,14 @@ def mark_stream_as_read(self, stream_id: int) -> Dict[str, Any]:
926969 >>> client.mark_stream_as_read(42)
927970 {'result': 'success', 'msg': ''}
928971 """
972+ warnings .warn (
973+ "`mark_stream_as_read` is deprecated. Use `update_message_flags_for_narrow` instead." ,
974+ DeprecationWarning ,
975+ stacklevel = 2 ,
976+ )
977+ if self .feature_level >= 155 :
978+ return self ._mark_as_read_using_narrow ([{"operator" : "is" , "operand" : "unread" }])
979+
929980 return self .call_endpoint (
930981 url = "mark_stream_as_read" ,
931982 method = "POST" ,
@@ -936,9 +987,23 @@ def mark_topic_as_read(self, stream_id: int, topic_name: str) -> Dict[str, Any]:
936987 """
937988 Example usage:
938989
939- >>> client.mark_all_as_read (42, 'new coffee machine')
990+ >>> client.mark_topic_as_read (42, 'new coffee machine')
940991 {'result': 'success', 'msg': ''}
941992 """
993+ warnings .warn (
994+ "`mark_topic_as_read` is deprecated. Use `update_message_flags_for_narrow` instead." ,
995+ DeprecationWarning ,
996+ stacklevel = 2 ,
997+ )
998+ if self .feature_level >= 155 :
999+ return self ._mark_as_read_using_narrow (
1000+ [
1001+ {"operator" : "stream" , "operand" : stream_id },
1002+ {"operator" : "topic" , "operand" : topic_name },
1003+ {"operator" : "is" , "operand" : "unread" },
1004+ ]
1005+ )
1006+
9421007 return self .call_endpoint (
9431008 url = "mark_topic_as_read" ,
9441009 method = "POST" ,
0 commit comments