mirror of
				https://github.com/zulip/zulip.git
				synced 2025-10-31 20:13:46 +00:00 
			
		
		
		
	api: Rename edit typing endpoint to /messages/{message_id}/typing.
				
					
				
			This is more consistent with how other URLs work in Zulip.
Replaces `/message_edit_typing` with `/messages/{message_id}/typing`.
The `message_id` parameter, previously passed in the request body,
is now included in the URL path.
			
			
This commit is contained in:
		| @@ -20,6 +20,13 @@ format used by the Zulip server that they are interacting with. | |||||||
|  |  | ||||||
| ## Changes in Zulip 10.0 | ## Changes in Zulip 10.0 | ||||||
|  |  | ||||||
|  | **Feature level 361** | ||||||
|  |  | ||||||
|  | * [`POST /messages/{message_id}/typing`](/api/set-typing-status-for-message-edit): | ||||||
|  |   Renamed `POST /messages/{message_id}/typing` to | ||||||
|  |   `POST /message_edit_typing`, passing the one `message_id` parameter | ||||||
|  |   in the URL path, for consistency with the rest of the API. | ||||||
|  |  | ||||||
| **Feature level 360** | **Feature level 360** | ||||||
|  |  | ||||||
| * [`GET /messages/{message_id}`](/api/get-message), [`GET | * [`GET /messages/{message_id}`](/api/get-message), [`GET | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ DESKTOP_WARNING_VERSION = "5.9.3" | |||||||
| # new level means in api_docs/changelog.md, as well as "**Changes**" | # new level means in api_docs/changelog.md, as well as "**Changes**" | ||||||
| # entries in the endpoint's documentation in `zulip.yaml`. | # entries in the endpoint's documentation in `zulip.yaml`. | ||||||
|  |  | ||||||
| API_FEATURE_LEVEL = 360  # Last bumped for allowing access to archived channel messages on read. | API_FEATURE_LEVEL = 361 | ||||||
|  |  | ||||||
| # Bump the minor PROVISION_VERSION to indicate that folks should provision | # Bump the minor PROVISION_VERSION to indicate that folks should provision | ||||||
| # only when going from an old version of the code to a newer version. Bump | # only when going from an old version of the code to a newer version. Bump | ||||||
|   | |||||||
| @@ -51,11 +51,10 @@ function send_message_edit_typing_notification_ajax( | |||||||
|     operation: "start" | "stop", |     operation: "start" | "stop", | ||||||
| ): void { | ): void { | ||||||
|     const data = { |     const data = { | ||||||
|         message_id: JSON.stringify(message_id), |  | ||||||
|         op: operation, |         op: operation, | ||||||
|     }; |     }; | ||||||
|     void channel.post({ |     void channel.post({ | ||||||
|         url: "/json/message_edit_typing", |         url: `/json/messages/${message_id}/typing`, | ||||||
|         data, |         data, | ||||||
|         error(xhr) { |         error(xhr) { | ||||||
|             if (xhr.readyState !== 0) { |             if (xhr.readyState !== 0) { | ||||||
|   | |||||||
| @@ -1608,43 +1608,35 @@ def set_typing_status(client: Client) -> None: | |||||||
|     validate_against_openapi_schema(result, "/typing", "post", "200") |     validate_against_openapi_schema(result, "/typing", "post", "200") | ||||||
|  |  | ||||||
|  |  | ||||||
| @openapi_test_function("/message_edit_typing:post") | @openapi_test_function("/messages/{message_id}/typing:post") | ||||||
| def set_message_edit_typing_status(client: Client) -> None: | def set_message_edit_typing_status(client: Client, message_id: int) -> None: | ||||||
|     message = {"type": "stream", "to": "Verona", "topic": "test_topic", "content": "test content"} |  | ||||||
|     response = client.send_message(message) |  | ||||||
|     message_id = response["id"] |  | ||||||
|     # {code_example|start} |     # {code_example|start} | ||||||
|     # The user has started typing while editing a message |     # The user has started typing while editing a message. | ||||||
|     request = { |     request = { | ||||||
|         "op": "start", |         "op": "start", | ||||||
|         "message_id": message_id, |  | ||||||
|     } |     } | ||||||
|     result = client.call_endpoint( |     result = client.call_endpoint( | ||||||
|         "message_edit_typing", |         f"/messages/{message_id}/typing", | ||||||
|         method="POST", |         method="POST", | ||||||
|         request=request, |         request=request, | ||||||
|     ) |     ) | ||||||
|     # {code_example|end} |     # {code_example|end} | ||||||
|     assert_success_response(result) |     assert_success_response(result) | ||||||
|     validate_against_openapi_schema(result, "/message_edit_typing", "post", "200") |     validate_against_openapi_schema(result, f"/messages/{message_id}/typing", "post", "200") | ||||||
|  |  | ||||||
|     message = {"type": "stream", "to": "Verona", "topic": "test_topic", "content": "test content"} |  | ||||||
|     response = client.send_message(message) |  | ||||||
|     message_id = response["id"] |  | ||||||
|     # {code_example|start} |     # {code_example|start} | ||||||
|     # The user has stopped typing while editing a message. |     # The user has stopped typing while editing a message. | ||||||
|     request = { |     request = { | ||||||
|         "op": "stop", |         "op": "stop", | ||||||
|         "message_id": message_id, |  | ||||||
|     } |     } | ||||||
|     result = client.call_endpoint( |     result = client.call_endpoint( | ||||||
|         "message_edit_typing", |         f"/messages/{message_id}/typing", | ||||||
|         method="POST", |         method="POST", | ||||||
|         request=request, |         request=request, | ||||||
|     ) |     ) | ||||||
|     # {code_example|end} |     # {code_example|end} | ||||||
|     assert_success_response(result) |     assert_success_response(result) | ||||||
|     validate_against_openapi_schema(result, "/message_edit_typing", "post", "200") |     validate_against_openapi_schema(result, "/messages/{message_id}/typing", "post", "200") | ||||||
|  |  | ||||||
|  |  | ||||||
| @openapi_test_function("/realm/emoji/{emoji_name}:post") | @openapi_test_function("/realm/emoji/{emoji_name}:post") | ||||||
| @@ -1794,7 +1786,7 @@ def test_invalid_stream_error(client: Client) -> None: | |||||||
| def test_messages(client: Client, nonadmin_client: Client) -> None: | def test_messages(client: Client, nonadmin_client: Client) -> None: | ||||||
|     render_message(client) |     render_message(client) | ||||||
|     message_id = send_message(client) |     message_id = send_message(client) | ||||||
|     set_message_edit_typing_status(client) |     set_message_edit_typing_status(client, message_id) | ||||||
|     add_reaction(client, message_id) |     add_reaction(client, message_id) | ||||||
|     remove_reaction(client, message_id) |     remove_reaction(client, message_id) | ||||||
|     update_message(client, message_id) |     update_message(client, message_id) | ||||||
|   | |||||||
| @@ -21320,7 +21320,7 @@ paths: | |||||||
|                     description: | |                     description: | | ||||||
|                       An example JSON error response when the user composes a channel message |                       An example JSON error response when the user composes a channel message | ||||||
|                       and `stream_id` is not specified: |                       and `stream_id` is not specified: | ||||||
|   /message_edit_typing: |   /messages/{message_id}/typing: | ||||||
|     post: |     post: | ||||||
|       operationId: set-typing-status-for-message-edit |       operationId: set-typing-status-for-message-edit | ||||||
|       summary: Set "typing" status for message editing |       summary: Set "typing" status for message editing | ||||||
| @@ -21329,10 +21329,25 @@ paths: | |||||||
|         Notify other users whether the current user is editing a message. |         Notify other users whether the current user is editing a message. | ||||||
| 
 | 
 | ||||||
|         Typing notifications for editing messages follow the same protocol as |         Typing notifications for editing messages follow the same protocol as | ||||||
|         [set-typing-status](/api/set-typing-status), see that endpoint for details. |         [set-typing-status](/api/set-typing-status), see that endpoint for | ||||||
|  |         details. | ||||||
| 
 | 
 | ||||||
|         **Changes**: New in Zulip 10.0 (feature level 351). Previously, |         **Changes**: Before Zulip 10.0 (feature level 361), the endpoint was | ||||||
|         typing notifications were not available when editing messages. |         named `/message_edit_typing` with `message_id` a required parameter in | ||||||
|  |         the request body. Clients are recommended to start using sending these | ||||||
|  |         typing notifications starting from this feature level. | ||||||
|  | 
 | ||||||
|  |         New in Zulip 10.0 (feature level 351). Previously, typing notifications were | ||||||
|  |         not available when editing messages. | ||||||
|  |       parameters: | ||||||
|  |         - name: message_id | ||||||
|  |           in: path | ||||||
|  |           description: | | ||||||
|  |             The target message's ID. | ||||||
|  |           schema: | ||||||
|  |             type: integer | ||||||
|  |           example: 47 | ||||||
|  |           required: true | ||||||
|       requestBody: |       requestBody: | ||||||
|         required: true |         required: true | ||||||
|         content: |         content: | ||||||
| @@ -21348,14 +21363,8 @@ paths: | |||||||
|                     - start |                     - start | ||||||
|                     - stop |                     - stop | ||||||
|                   example: start |                   example: start | ||||||
|                 message_id: |  | ||||||
|                   description: | |  | ||||||
|                     Describes the message id of the message being edited. |  | ||||||
|                   type: integer |  | ||||||
|                   example: 47 |  | ||||||
|               required: |               required: | ||||||
|                 - op |                 - op | ||||||
|                 - message_id |  | ||||||
|       responses: |       responses: | ||||||
|         "200": |         "200": | ||||||
|           $ref: "#/components/responses/SimpleSuccess" |           $ref: "#/components/responses/SimpleSuccess" | ||||||
|   | |||||||
| @@ -41,12 +41,13 @@ class TypingValidateOperatorTest(ZulipTestCase): | |||||||
|  |  | ||||||
|     def test_invalid_parameter_message_edit(self) -> None: |     def test_invalid_parameter_message_edit(self) -> None: | ||||||
|         sender = self.example_user("hamlet") |         sender = self.example_user("hamlet") | ||||||
|  |         msg_id = self.send_stream_message( | ||||||
|  |             sender, "Denmark", topic_name="editing", content="before edit" | ||||||
|  |         ) | ||||||
|         params = dict( |         params = dict( | ||||||
|             op="foo", |             op="foo", | ||||||
|             message_id=7, |  | ||||||
|         ) |         ) | ||||||
|         result = self.api_post(sender, "/api/v1/message_edit_typing", params) |         result = self.api_post(sender, f"/api/v1/messages/{msg_id}/typing", params) | ||||||
|         self.assert_json_error(result, "Invalid op") |         self.assert_json_error(result, "Invalid op") | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -112,10 +113,9 @@ class TypingValidateToArgumentsTest(ZulipTestCase): | |||||||
|         ) |         ) | ||||||
|         result = self.api_post( |         result = self.api_post( | ||||||
|             sender, |             sender, | ||||||
|             "/api/v1/message_edit_typing", |             f"/api/v1/messages/{msg_id}/typing", | ||||||
|             { |             { | ||||||
|                 "op": "start", |                 "op": "start", | ||||||
|                 "message_id": str(msg_id), |  | ||||||
|             }, |             }, | ||||||
|         ) |         ) | ||||||
|         self.assert_json_error(result, "You don't have permission to edit this message") |         self.assert_json_error(result, "You don't have permission to edit this message") | ||||||
| @@ -569,7 +569,6 @@ class TypingHappyPathTestStreams(ZulipTestCase): | |||||||
|  |  | ||||||
|         params = dict( |         params = dict( | ||||||
|             op="start", |             op="start", | ||||||
|             message_id=msg_id, |  | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         with self.settings(MAX_STREAM_SIZE_FOR_TYPING_NOTIFICATIONS=5): |         with self.settings(MAX_STREAM_SIZE_FOR_TYPING_NOTIFICATIONS=5): | ||||||
| @@ -577,7 +576,7 @@ class TypingHappyPathTestStreams(ZulipTestCase): | |||||||
|                 self.assert_database_query_count(5), |                 self.assert_database_query_count(5), | ||||||
|                 self.capture_send_event_calls(expected_num_events=0) as events, |                 self.capture_send_event_calls(expected_num_events=0) as events, | ||||||
|             ): |             ): | ||||||
|                 result = self.api_post(sender, "/api/v1/message_edit_typing", params) |                 result = self.api_post(sender, f"/api/v1/messages/{msg_id}/typing", params) | ||||||
|             self.assert_json_success(result) |             self.assert_json_success(result) | ||||||
|             self.assert_length(events, 0) |             self.assert_length(events, 0) | ||||||
|  |  | ||||||
| @@ -747,13 +746,13 @@ class TestSendTypingNotificationsSettings(ZulipTestCase): | |||||||
|         ) |         ) | ||||||
|         expected_user_ids = self.not_long_term_idle_subscriber_ids(channel_name, sender.realm) |         expected_user_ids = self.not_long_term_idle_subscriber_ids(channel_name, sender.realm) | ||||||
|  |  | ||||||
|         params = dict(op="start", message_id=msg_id) |         params = dict(op="start") | ||||||
|  |  | ||||||
|         # Test typing events sent when `send_stream_typing_notifications` set to `True`. |         # Test typing events sent when `send_stream_typing_notifications` set to `True`. | ||||||
|         self.assertTrue(sender.send_stream_typing_notifications) |         self.assertTrue(sender.send_stream_typing_notifications) | ||||||
|  |  | ||||||
|         with self.capture_send_event_calls(expected_num_events=1) as events: |         with self.capture_send_event_calls(expected_num_events=1) as events: | ||||||
|             result = self.api_post(sender, "/api/v1/message_edit_typing", params) |             result = self.api_post(sender, f"/api/v1/messages/{msg_id}/typing", params) | ||||||
|         self.assert_json_success(result) |         self.assert_json_success(result) | ||||||
|         self.assert_length(events, 1) |         self.assert_length(events, 1) | ||||||
|         self.assertEqual(orjson.loads(result.content)["msg"], "") |         self.assertEqual(orjson.loads(result.content)["msg"], "") | ||||||
| @@ -763,7 +762,7 @@ class TestSendTypingNotificationsSettings(ZulipTestCase): | |||||||
|         do_deactivate_stream(channel, acting_user=sender) |         do_deactivate_stream(channel, acting_user=sender) | ||||||
|         # No events should be sent if stream is deactivated. |         # No events should be sent if stream is deactivated. | ||||||
|         with self.capture_send_event_calls(expected_num_events=0) as events: |         with self.capture_send_event_calls(expected_num_events=0) as events: | ||||||
|             result = self.api_post(sender, "/api/v1/message_edit_typing", params) |             result = self.api_post(sender, f"/api/v1/messages/{msg_id}/typing", params) | ||||||
|         self.assert_json_error(result, "Invalid message(s)") |         self.assert_json_error(result, "Invalid message(s)") | ||||||
|         self.assertEqual(events, []) |         self.assertEqual(events, []) | ||||||
|         do_unarchive_stream(channel, channel_name, acting_user=sender) |         do_unarchive_stream(channel, channel_name, acting_user=sender) | ||||||
| @@ -773,7 +772,7 @@ class TestSendTypingNotificationsSettings(ZulipTestCase): | |||||||
|  |  | ||||||
|         # No events should be sent now |         # No events should be sent now | ||||||
|         with self.capture_send_event_calls(expected_num_events=0) as events: |         with self.capture_send_event_calls(expected_num_events=0) as events: | ||||||
|             result = self.api_post(sender, "/api/v1/message_edit_typing", params) |             result = self.api_post(sender, f"/api/v1/messages/{msg_id}/typing", params) | ||||||
|         self.assert_json_error( |         self.assert_json_error( | ||||||
|             result, "User has disabled typing notifications for channel messages" |             result, "User has disabled typing notifications for channel messages" | ||||||
|         ) |         ) | ||||||
| @@ -786,7 +785,7 @@ class TestSendTypingNotificationsSettings(ZulipTestCase): | |||||||
|         aaron.save() |         aaron.save() | ||||||
|  |  | ||||||
|         with self.capture_send_event_calls(expected_num_events=1) as events: |         with self.capture_send_event_calls(expected_num_events=1) as events: | ||||||
|             result = self.api_post(sender, "/api/v1/message_edit_typing", params) |             result = self.api_post(sender, f"/api/v1/messages/{msg_id}/typing", params) | ||||||
|         self.assert_json_success(result) |         self.assert_json_success(result) | ||||||
|         self.assert_length(events, 1) |         self.assert_length(events, 1) | ||||||
|  |  | ||||||
| @@ -805,14 +804,13 @@ class TestSendTypingNotificationsSettings(ZulipTestCase): | |||||||
|  |  | ||||||
|         params = dict( |         params = dict( | ||||||
|             op="start", |             op="start", | ||||||
|             message_id=msg_id, |  | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         # Test typing events sent when `send_private_typing_notifications` set to `True`. |         # Test typing events sent when `send_private_typing_notifications` set to `True`. | ||||||
|         self.assertTrue(sender.send_private_typing_notifications) |         self.assertTrue(sender.send_private_typing_notifications) | ||||||
|  |  | ||||||
|         with self.capture_send_event_calls(expected_num_events=1) as events: |         with self.capture_send_event_calls(expected_num_events=1) as events: | ||||||
|             result = self.api_post(sender, "/api/v1/message_edit_typing", params) |             result = self.api_post(sender, f"/api/v1/messages/{msg_id}/typing", params) | ||||||
|  |  | ||||||
|         self.assert_json_success(result) |         self.assert_json_success(result) | ||||||
|         self.assert_length(events, 1) |         self.assert_length(events, 1) | ||||||
| @@ -825,7 +823,7 @@ class TestSendTypingNotificationsSettings(ZulipTestCase): | |||||||
|  |  | ||||||
|         # No events should be sent now |         # No events should be sent now | ||||||
|         with self.capture_send_event_calls(expected_num_events=0) as events: |         with self.capture_send_event_calls(expected_num_events=0) as events: | ||||||
|             result = self.api_post(sender, "/api/v1/message_edit_typing", params) |             result = self.api_post(sender, f"/api/v1/messages/{msg_id}/typing", params) | ||||||
|  |  | ||||||
|         self.assert_json_error(result, "User has disabled typing notifications for direct messages") |         self.assert_json_error(result, "User has disabled typing notifications for direct messages") | ||||||
|         self.assertEqual(events, []) |         self.assertEqual(events, []) | ||||||
| @@ -837,7 +835,7 @@ class TestSendTypingNotificationsSettings(ZulipTestCase): | |||||||
|         recipient_user.save() |         recipient_user.save() | ||||||
|  |  | ||||||
|         with self.capture_send_event_calls(expected_num_events=1) as events: |         with self.capture_send_event_calls(expected_num_events=1) as events: | ||||||
|             result = self.api_post(sender, "/api/v1/message_edit_typing", params) |             result = self.api_post(sender, f"/api/v1/messages/{msg_id}/typing", params) | ||||||
|         self.assert_json_success(result) |         self.assert_json_success(result) | ||||||
|         self.assert_length(events, 1) |         self.assert_length(events, 1) | ||||||
|  |  | ||||||
| @@ -858,12 +856,11 @@ class TestSendTypingNotificationsSettings(ZulipTestCase): | |||||||
|  |  | ||||||
|         params = dict( |         params = dict( | ||||||
|             op="start", |             op="start", | ||||||
|             message_id=str(msg_id), |  | ||||||
|         ) |         ) | ||||||
|         # Test typing events sent when `send_private_typing_notifications` set to `True`. |         # Test typing events sent when `send_private_typing_notifications` set to `True`. | ||||||
|         self.assertTrue(sender.send_private_typing_notifications) |         self.assertTrue(sender.send_private_typing_notifications) | ||||||
|         with self.capture_send_event_calls(expected_num_events=1) as events: |         with self.capture_send_event_calls(expected_num_events=1) as events: | ||||||
|             result = self.api_post(sender, "/api/v1/message_edit_typing", params) |             result = self.api_post(sender, f"/api/v1/messages/{msg_id}/typing", params) | ||||||
|  |  | ||||||
|         self.assert_json_success(result) |         self.assert_json_success(result) | ||||||
|         self.assert_length(events, 1) |         self.assert_length(events, 1) | ||||||
| @@ -876,7 +873,7 @@ class TestSendTypingNotificationsSettings(ZulipTestCase): | |||||||
|  |  | ||||||
|         # No events should be sent now |         # No events should be sent now | ||||||
|         with self.capture_send_event_calls(expected_num_events=0) as events: |         with self.capture_send_event_calls(expected_num_events=0) as events: | ||||||
|             result = self.api_post(sender, "/api/v1/message_edit_typing", params) |             result = self.api_post(sender, f"/api/v1/messages/{msg_id}/typing", params) | ||||||
|  |  | ||||||
|         self.assert_json_error(result, "User has disabled typing notifications for direct messages") |         self.assert_json_error(result, "User has disabled typing notifications for direct messages") | ||||||
|         self.assertEqual(events, []) |         self.assertEqual(events, []) | ||||||
| @@ -891,7 +888,7 @@ class TestSendTypingNotificationsSettings(ZulipTestCase): | |||||||
|         expected_recipient_ids = {hamlet.id, cordelia.id} |         expected_recipient_ids = {hamlet.id, cordelia.id} | ||||||
|  |  | ||||||
|         with self.capture_send_event_calls(expected_num_events=1) as events: |         with self.capture_send_event_calls(expected_num_events=1) as events: | ||||||
|             result = self.api_post(sender, "/api/v1/message_edit_typing", params) |             result = self.api_post(sender, f"/api/v1/messages/{msg_id}/typing", params) | ||||||
|         self.assert_json_success(result) |         self.assert_json_success(result) | ||||||
|         self.assert_length(events, 1) |         self.assert_length(events, 1) | ||||||
|         event_user_ids = set(events[0]["users"]) |         event_user_ids = set(events[0]["users"]) | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ from typing import Annotated, Literal | |||||||
|  |  | ||||||
| from django.http import HttpRequest, HttpResponse | from django.http import HttpRequest, HttpResponse | ||||||
| from django.utils.translation import gettext as _ | from django.utils.translation import gettext as _ | ||||||
| from pydantic import Json | from pydantic import Json, NonNegativeInt | ||||||
|  |  | ||||||
| from zerver.actions.message_edit import validate_user_can_edit_message | from zerver.actions.message_edit import validate_user_can_edit_message | ||||||
| from zerver.actions.typing import ( | from zerver.actions.typing import ( | ||||||
| @@ -16,7 +16,7 @@ from zerver.lib.message import access_message | |||||||
| from zerver.lib.response import json_success | from zerver.lib.response import json_success | ||||||
| from zerver.lib.streams import access_stream_by_id_for_message, access_stream_for_send_message | from zerver.lib.streams import access_stream_by_id_for_message, access_stream_for_send_message | ||||||
| from zerver.lib.topic import maybe_rename_general_chat_to_empty_topic | from zerver.lib.topic import maybe_rename_general_chat_to_empty_topic | ||||||
| from zerver.lib.typed_endpoint import ApiParamConfig, OptionalTopic, typed_endpoint | from zerver.lib.typed_endpoint import ApiParamConfig, OptionalTopic, PathOnly, typed_endpoint | ||||||
| from zerver.models import Recipient, UserProfile | from zerver.models import Recipient, UserProfile | ||||||
| from zerver.models.recipients import get_direct_message_group_user_ids | from zerver.models.recipients import get_direct_message_group_user_ids | ||||||
|  |  | ||||||
| @@ -77,8 +77,8 @@ def send_message_edit_notification_backend( | |||||||
|     request: HttpRequest, |     request: HttpRequest, | ||||||
|     user_profile: UserProfile, |     user_profile: UserProfile, | ||||||
|     *, |     *, | ||||||
|  |     message_id: PathOnly[NonNegativeInt], | ||||||
|     operator: Annotated[Literal["start", "stop"], ApiParamConfig("op")], |     operator: Annotated[Literal["start", "stop"], ApiParamConfig("op")], | ||||||
|     message_id: Json[int], |  | ||||||
| ) -> HttpResponse: | ) -> HttpResponse: | ||||||
|     # Technically, this endpoint doesn't modify the message, but we're |     # Technically, this endpoint doesn't modify the message, but we're | ||||||
|     # attempting to send a typing notification that we're editing the |     # attempting to send a typing notification that we're editing the | ||||||
|   | |||||||
| @@ -399,7 +399,7 @@ v1_api_and_json_patterns = [ | |||||||
|     # POST sends a typing notification event to recipients |     # POST sends a typing notification event to recipients | ||||||
|     rest_path("typing", POST=send_notification_backend), |     rest_path("typing", POST=send_notification_backend), | ||||||
|     # POST sends a message edit typing notification |     # POST sends a message edit typing notification | ||||||
|     rest_path("message_edit_typing", POST=send_message_edit_notification_backend), |     rest_path("messages/<int:message_id>/typing", POST=send_message_edit_notification_backend), | ||||||
|     # user_uploads -> zerver.views.upload |     # user_uploads -> zerver.views.upload | ||||||
|     rest_path("user_uploads", POST=upload_file_backend), |     rest_path("user_uploads", POST=upload_file_backend), | ||||||
|     rest_path( |     rest_path( | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user