mirror of
				https://github.com/zulip/zulip.git
				synced 2025-10-31 20:13:46 +00:00 
			
		
		
		
	mark_unread: Add support for empty topic name.
This commit is a part of the work to support empty string as a topic name. Previously, empty string was not a valid topic name. Now, mark unread operation supports empty topic name. Adds backward compatibility for: - `topic` field in the `update_message_flags` event type when removing `read` flag
This commit is contained in:
		
				
					committed by
					
						 Tim Abbott
						Tim Abbott
					
				
			
			
				
	
			
			
			
						parent
						
							293db85f67
						
					
				
				
					commit
					79e55b1563
				
			| @@ -43,6 +43,7 @@ format used by the Zulip server that they are interacting with. | ||||
|     * `orig_subject` and `subject` fields in the `update_message` event type | ||||
|     * `topic_name` field in the `user_topic` event type | ||||
|     * `topic` field in the `typing` event type | ||||
|     * `topic` field in the `update_message_flags` event type when removing `read` flag | ||||
|  | ||||
| * [`GET /messages`](/api/get-messages), | ||||
|   [`GET /messages/{message_id}`](/api/get-message): Added `allow_empty_topic_name` | ||||
|   | ||||
| @@ -3129,6 +3129,17 @@ paths: | ||||
|                                           Present only if `type` is `"stream"`. | ||||
| 
 | ||||
|                                           Name of the topic where the message was sent. | ||||
| 
 | ||||
|                                           For clients that don't support the `empty_topic_name` [client capability][client-capabilities], | ||||
|                                           if the actual topic name is empty string, this field's value will instead | ||||
|                                           be the value of `realm_empty_topic_display_name` found in the | ||||
|                                           [`POST /register`](/api/register-queue) response. | ||||
| 
 | ||||
|                                           **Changes**: Before 10.0 (feature level 334), `empty_topic_name` | ||||
|                                           client capability didn't exist and empty string as the topic name for | ||||
|                                           channel messages wasn't allowed. | ||||
| 
 | ||||
|                                           [client-capabilities]: /api/register-queue#parameter-client_capabilities | ||||
|                                       unmuted_stream_msg: | ||||
|                                         type: boolean | ||||
|                                         deprecated: true | ||||
|   | ||||
| @@ -377,7 +377,14 @@ class EmptyTopicNameTest(ZulipTestCase): | ||||
|             apply_markdown=True, | ||||
|             client_type_name="website", | ||||
|             empty_topic_name=True, | ||||
|             event_types=["message", "update_message", "delete_message", "user_topic", "typing"], | ||||
|             event_types=[ | ||||
|                 "message", | ||||
|                 "update_message", | ||||
|                 "delete_message", | ||||
|                 "user_topic", | ||||
|                 "typing", | ||||
|                 "update_message_flags", | ||||
|             ], | ||||
|             last_connection_time=time.time(), | ||||
|             queue_timeout=600, | ||||
|             realm_id=hamlet.realm.id, | ||||
| @@ -425,10 +432,10 @@ class EmptyTopicNameTest(ZulipTestCase): | ||||
|         self.assertEqual(events[5]["topic"], "") | ||||
|  | ||||
|         # reset | ||||
|         self.send_stream_message( | ||||
|         message_id = self.send_stream_message( | ||||
|             iago, "Denmark", topic_name="", skip_capture_on_commit_callbacks=True | ||||
|         ) | ||||
|         self.send_stream_message( | ||||
|         message_id_2 = self.send_stream_message( | ||||
|             iago, | ||||
|             "Verona", | ||||
|             topic_name=Message.EMPTY_TOPIC_FALLBACK_NAME, | ||||
| @@ -473,6 +480,25 @@ class EmptyTopicNameTest(ZulipTestCase): | ||||
|         self.assertEqual(events[8]["topic"], "") | ||||
|         self.assertEqual(events[9]["topic"], "") | ||||
|  | ||||
|         # Prep to mark it as read before marking it as unread. | ||||
|         params = { | ||||
|             "messages": orjson.dumps([message_id, message_id_2]).decode(), | ||||
|             "op": "add", | ||||
|             "flag": "read", | ||||
|         } | ||||
|         self.client_post("/json/messages/flags", params) | ||||
|  | ||||
|         with self.captureOnCommitCallbacks(execute=True): | ||||
|             params = { | ||||
|                 "messages": orjson.dumps([message_id, message_id_2]).decode(), | ||||
|                 "op": "remove", | ||||
|                 "flag": "read", | ||||
|             } | ||||
|             self.client_post("/json/messages/flags", params) | ||||
|         events = client.event_queue.contents() | ||||
|         self.assertEqual(events[10]["message_details"][str(message_id)]["topic"], "") | ||||
|         self.assertEqual(events[10]["message_details"][str(message_id_2)]["topic"], "") | ||||
|  | ||||
|     def test_client_not_supports_empty_topic_name(self) -> None: | ||||
|         iago = self.example_user("iago") | ||||
|         hamlet = self.example_user("hamlet") | ||||
| @@ -481,7 +507,14 @@ class EmptyTopicNameTest(ZulipTestCase): | ||||
|             apply_markdown=True, | ||||
|             client_type_name="zulip-mobile", | ||||
|             empty_topic_name=False, | ||||
|             event_types=["message", "update_message", "delete_message", "user_topic", "typing"], | ||||
|             event_types=[ | ||||
|                 "message", | ||||
|                 "update_message", | ||||
|                 "delete_message", | ||||
|                 "user_topic", | ||||
|                 "typing", | ||||
|                 "update_message_flags", | ||||
|             ], | ||||
|             last_connection_time=time.time(), | ||||
|             queue_timeout=600, | ||||
|             realm_id=hamlet.realm.id, | ||||
| @@ -529,10 +562,10 @@ class EmptyTopicNameTest(ZulipTestCase): | ||||
|         self.assertEqual(events[5]["topic"], Message.EMPTY_TOPIC_FALLBACK_NAME) | ||||
|  | ||||
|         # reset | ||||
|         self.send_stream_message( | ||||
|         message_id = self.send_stream_message( | ||||
|             iago, "Denmark", topic_name="", skip_capture_on_commit_callbacks=True | ||||
|         ) | ||||
|         self.send_stream_message( | ||||
|         message_id_2 = self.send_stream_message( | ||||
|             iago, | ||||
|             "Verona", | ||||
|             topic_name=Message.EMPTY_TOPIC_FALLBACK_NAME, | ||||
| @@ -577,6 +610,31 @@ class EmptyTopicNameTest(ZulipTestCase): | ||||
|         self.assertEqual(events[8]["topic"], Message.EMPTY_TOPIC_FALLBACK_NAME) | ||||
|         self.assertEqual(events[9]["topic"], Message.EMPTY_TOPIC_FALLBACK_NAME) | ||||
|  | ||||
|         # Prep to mark it as read before marking it as unread. | ||||
|         params = { | ||||
|             "messages": orjson.dumps([message_id, message_id_2]).decode(), | ||||
|             "op": "add", | ||||
|             "flag": "read", | ||||
|         } | ||||
|         self.client_post("/json/messages/flags", params) | ||||
|  | ||||
|         with self.captureOnCommitCallbacks(execute=True): | ||||
|             params = { | ||||
|                 "messages": orjson.dumps([message_id, message_id_2]).decode(), | ||||
|                 "op": "remove", | ||||
|                 "flag": "read", | ||||
|             } | ||||
|             self.client_post("/json/messages/flags", params) | ||||
|         events = client.event_queue.contents() | ||||
|         self.assertEqual( | ||||
|             events[10]["message_details"][str(message_id)]["topic"], | ||||
|             Message.EMPTY_TOPIC_FALLBACK_NAME, | ||||
|         ) | ||||
|         self.assertEqual( | ||||
|             events[10]["message_details"][str(message_id_2)]["topic"], | ||||
|             Message.EMPTY_TOPIC_FALLBACK_NAME, | ||||
|         ) | ||||
|  | ||||
|     def test_fetch_messages(self) -> None: | ||||
|         hamlet = self.example_user("hamlet") | ||||
|         self.login_user(hamlet) | ||||
|   | ||||
| @@ -1663,6 +1663,25 @@ def process_stream_typing_notification_event( | ||||
|                 client.add_event(empty_topic_name_fallback_event) | ||||
|  | ||||
|  | ||||
| def process_mark_message_unread_event(event: Mapping[str, Any], users: Iterable[int]) -> None: | ||||
|     empty_topic_name_fallback_event = copy.deepcopy(dict(event)) | ||||
|     for message_id, message_detail in empty_topic_name_fallback_event["message_details"].items(): | ||||
|         if message_detail["type"] == "stream" and message_detail.get("topic") == "": | ||||
|             empty_topic_name_fallback_event["message_details"][message_id]["topic"] = ( | ||||
|                 Message.EMPTY_TOPIC_FALLBACK_NAME | ||||
|             ) | ||||
|  | ||||
|     for user_profile_id in users: | ||||
|         for client in get_client_descriptors_for_user(user_profile_id): | ||||
|             if not client.accepts_event(event): | ||||
|                 continue | ||||
|  | ||||
|             if client.empty_topic_name: | ||||
|                 client.add_event(event) | ||||
|             else: | ||||
|                 client.add_event(empty_topic_name_fallback_event) | ||||
|  | ||||
|  | ||||
| def process_notification(notice: Mapping[str, Any]) -> None: | ||||
|     event: Mapping[str, Any] = notice["event"] | ||||
|     users: list[int] | list[Mapping[str, Any]] = notice["users"] | ||||
| @@ -1695,6 +1714,12 @@ def process_notification(notice: Mapping[str, Any]) -> None: | ||||
|         process_user_topic_event(event, cast(list[int], users)) | ||||
|     elif event["type"] == "typing" and event["message_type"] == "stream": | ||||
|         process_stream_typing_notification_event(event, cast(list[int], users)) | ||||
|     elif ( | ||||
|         event["type"] == "update_message_flags" | ||||
|         and event["op"] == "remove" | ||||
|         and event["flag"] == "read" | ||||
|     ): | ||||
|         process_mark_message_unread_event(event, cast(list[int], users)) | ||||
|     elif event["type"] == "cleanup_queue": | ||||
|         # cleanup_event_queue may generate this event to forward cleanup | ||||
|         # requests to the right shard. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user