1010import traceback
1111import types
1212import urllib .parse
13+ import warnings
1314from configparser import ConfigParser
1415from datetime import datetime
1516from typing import (
@@ -901,19 +902,58 @@ 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+ while True :
932+ res = self .update_message_flags_for_narrow (request )
933+ if res .get ("result" ) != "success" :
934+ return res
935+ if res .get ("found_newest" , True ):
936+ break
937+ if res .get ("last_processed_id" ) is None :
938+ break
939+ request ["anchor" ] = res ["last_processed_id" ]
940+ return {"result" : "success" , "msg" : "" , "complete" : True }
941+
910942 def mark_all_as_read (self ) -> Dict [str , Any ]:
911943 """
912944 Example usage:
913945
914946 >>> client.mark_all_as_read()
915947 {'result': 'success', 'msg': ''}
916948 """
949+ warnings .warn (
950+ "`mark_all_as_read` is deprecated. Use `update_message_flags_for_narrow` instead." ,
951+ DeprecationWarning ,
952+ stacklevel = 2 ,
953+ )
954+ if self .feature_level >= 155 :
955+ return self ._mark_as_read_using_narrow ([{"operator" : "is" , "operand" : "unread" }])
956+
917957 return self .call_endpoint (
918958 url = "mark_all_as_read" ,
919959 method = "POST" ,
@@ -926,6 +966,19 @@ def mark_stream_as_read(self, stream_id: int) -> Dict[str, Any]:
926966 >>> client.mark_stream_as_read(42)
927967 {'result': 'success', 'msg': ''}
928968 """
969+ warnings .warn (
970+ "`mark_stream_as_read` is deprecated. Use `update_message_flags_for_narrow` instead." ,
971+ DeprecationWarning ,
972+ stacklevel = 2 ,
973+ )
974+ if self .feature_level >= 155 :
975+ return self ._mark_as_read_using_narrow (
976+ [
977+ {"operator" : "stream" , "operand" : stream_id },
978+ {"operator" : "is" , "operand" : "unread" },
979+ ]
980+ )
981+
929982 return self .call_endpoint (
930983 url = "mark_stream_as_read" ,
931984 method = "POST" ,
@@ -936,9 +989,23 @@ def mark_topic_as_read(self, stream_id: int, topic_name: str) -> Dict[str, Any]:
936989 """
937990 Example usage:
938991
939- >>> client.mark_all_as_read (42, 'new coffee machine')
992+ >>> client.mark_topic_as_read (42, 'new coffee machine')
940993 {'result': 'success', 'msg': ''}
941994 """
995+ warnings .warn (
996+ "`mark_topic_as_read` is deprecated. Use `update_message_flags_for_narrow` instead." ,
997+ DeprecationWarning ,
998+ stacklevel = 2 ,
999+ )
1000+ if self .feature_level >= 155 :
1001+ return self ._mark_as_read_using_narrow (
1002+ [
1003+ {"operator" : "stream" , "operand" : stream_id },
1004+ {"operator" : "topic" , "operand" : topic_name },
1005+ {"operator" : "is" , "operand" : "unread" },
1006+ ]
1007+ )
1008+
9421009 return self .call_endpoint (
9431010 url = "mark_topic_as_read" ,
9441011 method = "POST" ,
0 commit comments