mirror of https://github.com/zulip/zulip.git
message-type: Add support for "channel" as value for type parameter.
For endpoints with a type parameter to indicate whether a message is a direct or stream message, adds support for passing "channel" as a value for stream messages. Part of stream to channel rename project.
This commit is contained in:
parent
d24dadb52f
commit
01b59c5aa2
|
@ -20,6 +20,14 @@ format used by the Zulip server that they are interacting with.
|
||||||
|
|
||||||
## Changes in Zulip 9.0
|
## Changes in Zulip 9.0
|
||||||
|
|
||||||
|
**Feature level 248**
|
||||||
|
|
||||||
|
* [`POST /typing`](/api/set-typing-status), [`POST /messages`](/api/send-message),
|
||||||
|
[`POST /scheduled_messages`](/api/create-scheduled-message),
|
||||||
|
[`PATCH /scheduled_messages/<int:scheduled_message_id>`](/api/update-scheduled-message):
|
||||||
|
Added `"channel"` as an additional value for the `type` parameter to
|
||||||
|
indicate a stream message.
|
||||||
|
|
||||||
**Feature level 247**
|
**Feature level 247**
|
||||||
|
|
||||||
* [Markdown message formatting](/api/message-formatting#mentions):
|
* [Markdown message formatting](/api/message-formatting#mentions):
|
||||||
|
|
|
@ -33,7 +33,7 @@ DESKTOP_WARNING_VERSION = "5.9.3"
|
||||||
# Changes should be accompanied by documentation explaining what the
|
# Changes should be accompanied by documentation explaining what the
|
||||||
# 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 = 247
|
API_FEATURE_LEVEL = 248
|
||||||
|
|
||||||
# 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
|
||||||
|
|
|
@ -129,7 +129,7 @@ class Message(AbstractMessage):
|
||||||
# deprecating the original "private" and becoming the
|
# deprecating the original "private" and becoming the
|
||||||
# preferred way to indicate a personal or huddle
|
# preferred way to indicate a personal or huddle
|
||||||
# Recipient type via the API.
|
# Recipient type via the API.
|
||||||
API_RECIPIENT_TYPES = ["direct", "private", "stream"]
|
API_RECIPIENT_TYPES = ["direct", "private", "stream", "channel"]
|
||||||
|
|
||||||
search_tsvector = SearchVectorField(null=True)
|
search_tsvector = SearchVectorField(null=True)
|
||||||
|
|
||||||
|
|
|
@ -5677,17 +5677,20 @@ paths:
|
||||||
type:
|
type:
|
||||||
description: |
|
description: |
|
||||||
The type of scheduled message to be sent. `"direct"` for a direct
|
The type of scheduled message to be sent. `"direct"` for a direct
|
||||||
message and `"stream"` for a stream message.
|
message and `"stream"` or `"channel"` for a stream message.
|
||||||
|
|
||||||
In Zulip 7.0 (feature level 174), `"direct"` was added as the
|
Note that, while `"private"` is supported for scheduling direct
|
||||||
preferred way to indicate the type of a direct message, deprecating
|
messages, clients are encouraged to use to the modern convention of
|
||||||
the original `"private"`. While `"private"` is supported for
|
`"direct"` to indicate this message type, because support for
|
||||||
scheduling direct messages, clients are encouraged to use to the
|
`"private"` may eventually be removed.
|
||||||
modern convention because support for `"private"` may eventually
|
|
||||||
be removed.
|
**Changes**: In Zulip 9.0 (feature level 248), `"channel"` was added as
|
||||||
|
an additional value for this parameter to indicate the type of a stream
|
||||||
|
message.
|
||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
- direct
|
- direct
|
||||||
|
- channel
|
||||||
- stream
|
- stream
|
||||||
- private
|
- private
|
||||||
example: direct
|
example: direct
|
||||||
|
@ -5822,21 +5825,24 @@ paths:
|
||||||
type:
|
type:
|
||||||
description: |
|
description: |
|
||||||
The type of scheduled message to be sent. `"direct"` for a direct
|
The type of scheduled message to be sent. `"direct"` for a direct
|
||||||
message and `"stream"` for a stream message.
|
message and `"stream"` or `"channel"` for a stream message.
|
||||||
|
|
||||||
When updating the type of the scheduled message, the `to` parameter
|
When updating the type of the scheduled message, the `to` parameter
|
||||||
is required. And, if updating the type of the scheduled message to
|
is required. And, if updating the type of the scheduled message to
|
||||||
`"stream"`, then the `topic` parameter is also required.
|
`"stream"`/`"channel"`, then the `topic` parameter is also required.
|
||||||
|
|
||||||
In Zulip 7.0 (feature level 174), `"direct"` was added as the
|
Note that, while `"private"` is supported for scheduling direct
|
||||||
preferred way to indicate the type of a direct message, deprecating
|
messages, clients are encouraged to use to the modern convention of
|
||||||
the original `"private"`. While `"private"` is supported for
|
`"direct"` to indicate this message type, because support for
|
||||||
scheduling direct messages, clients are encouraged to use to the
|
`"private"` may eventually be removed.
|
||||||
modern convention because support for `"private"` may eventually
|
|
||||||
be removed.
|
**Changes**: In Zulip 9.0 (feature level 248), `"channel"` was added as
|
||||||
|
an additional value for this parameter to indicate the type of a stream
|
||||||
|
message.
|
||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
- direct
|
- direct
|
||||||
|
- channel
|
||||||
- stream
|
- stream
|
||||||
- private
|
- private
|
||||||
example: stream
|
example: stream
|
||||||
|
@ -6452,9 +6458,13 @@ paths:
|
||||||
description: |
|
description: |
|
||||||
The type of message to be sent.
|
The type of message to be sent.
|
||||||
|
|
||||||
`"direct"` for a direct message and `"stream"` for a stream message.
|
`"direct"` for a direct message and `"stream"` or `"channel"` for a
|
||||||
|
stream message.
|
||||||
|
|
||||||
**Changes**: In Zulip 7.0 (feature level 174), `"direct"` was added as
|
**Changes**: In Zulip 9.0 (feature level 248), `"channel"` was added as
|
||||||
|
an additional value for this parameter to request a stream message.
|
||||||
|
|
||||||
|
In Zulip 7.0 (feature level 174), `"direct"` was added as
|
||||||
the preferred way to request a direct message, deprecating the original
|
the preferred way to request a direct message, deprecating the original
|
||||||
`"private"`. While `"private"` is still supported for requesting direct
|
`"private"`. While `"private"` is still supported for requesting direct
|
||||||
messages, clients are encouraged to use to the modern convention with
|
messages, clients are encouraged to use to the modern convention with
|
||||||
|
@ -6463,6 +6473,7 @@ paths:
|
||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
- direct
|
- direct
|
||||||
|
- channel
|
||||||
- stream
|
- stream
|
||||||
- private
|
- private
|
||||||
example: direct
|
example: direct
|
||||||
|
@ -18069,7 +18080,11 @@ paths:
|
||||||
description: |
|
description: |
|
||||||
Type of the message being composed.
|
Type of the message being composed.
|
||||||
|
|
||||||
**Changes**: In Zulip 8.0 (feature level 215), stopped supporting
|
**Changes**: In Zulip 9.0 (feature level 248), `"channel"` was added as
|
||||||
|
an additional value for this parameter to indicate a stream message is
|
||||||
|
being composed.
|
||||||
|
|
||||||
|
In Zulip 8.0 (feature level 215), stopped supporting
|
||||||
`"private"` as a valid value for this parameter.
|
`"private"` as a valid value for this parameter.
|
||||||
|
|
||||||
In Zulip 7.0 (feature level 174), `"direct"` was added
|
In Zulip 7.0 (feature level 174), `"direct"` was added
|
||||||
|
@ -18083,6 +18098,7 @@ paths:
|
||||||
enum:
|
enum:
|
||||||
- direct
|
- direct
|
||||||
- stream
|
- stream
|
||||||
|
- channel
|
||||||
default: direct
|
default: direct
|
||||||
example: direct
|
example: direct
|
||||||
op:
|
op:
|
||||||
|
|
|
@ -84,34 +84,40 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
Sending a message to a stream to which you are subscribed is
|
Sending a message to a stream to which you are subscribed is
|
||||||
successful.
|
successful.
|
||||||
"""
|
"""
|
||||||
|
recipient_type_name = ["stream", "channel"]
|
||||||
self.login("hamlet")
|
self.login("hamlet")
|
||||||
result = self.client_post(
|
|
||||||
"/json/messages",
|
for recipient_type in recipient_type_name:
|
||||||
{
|
result = self.client_post(
|
||||||
"type": "stream",
|
"/json/messages",
|
||||||
"to": orjson.dumps("Verona").decode(),
|
{
|
||||||
"content": "Test message",
|
"type": recipient_type,
|
||||||
"topic": "Test topic",
|
"to": orjson.dumps("Verona").decode(),
|
||||||
},
|
"content": "Test message",
|
||||||
)
|
"topic": "Test topic",
|
||||||
self.assert_json_success(result)
|
},
|
||||||
|
)
|
||||||
|
self.assert_json_success(result)
|
||||||
|
|
||||||
def test_api_message_to_stream_by_name(self) -> None:
|
def test_api_message_to_stream_by_name(self) -> None:
|
||||||
"""
|
"""
|
||||||
Same as above, but for the API view
|
Same as above, but for the API view
|
||||||
"""
|
"""
|
||||||
|
recipient_type_name = ["stream", "channel"]
|
||||||
user = self.example_user("hamlet")
|
user = self.example_user("hamlet")
|
||||||
result = self.api_post(
|
|
||||||
user,
|
for recipient_type in recipient_type_name:
|
||||||
"/api/v1/messages",
|
result = self.api_post(
|
||||||
{
|
user,
|
||||||
"type": "stream",
|
"/api/v1/messages",
|
||||||
"to": orjson.dumps("Verona").decode(),
|
{
|
||||||
"content": "Test message",
|
"type": recipient_type,
|
||||||
"topic": "Test topic",
|
"to": orjson.dumps("Verona").decode(),
|
||||||
},
|
"content": "Test message",
|
||||||
)
|
"topic": "Test topic",
|
||||||
self.assert_json_success(result)
|
},
|
||||||
|
)
|
||||||
|
self.assert_json_success(result)
|
||||||
|
|
||||||
def test_message_to_stream_with_nonexistent_id(self) -> None:
|
def test_message_to_stream_with_nonexistent_id(self) -> None:
|
||||||
cordelia = self.example_user("cordelia")
|
cordelia = self.example_user("cordelia")
|
||||||
|
@ -123,7 +129,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
bot,
|
bot,
|
||||||
"/api/v1/messages",
|
"/api/v1/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": orjson.dumps([99999]).decode(),
|
"to": orjson.dumps([99999]).decode(),
|
||||||
"content": "Stream message by ID.",
|
"content": "Stream message by ID.",
|
||||||
"topic": "Test topic for stream ID message",
|
"topic": "Test topic for stream ID message",
|
||||||
|
@ -154,7 +160,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
bot,
|
bot,
|
||||||
"/api/v1/messages",
|
"/api/v1/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": orjson.dumps(stream.name).decode(),
|
"to": orjson.dumps(stream.name).decode(),
|
||||||
"content": "Stream message to an empty stream by name.",
|
"content": "Stream message to an empty stream by name.",
|
||||||
"topic": "Test topic for empty stream name message",
|
"topic": "Test topic for empty stream name message",
|
||||||
|
@ -189,7 +195,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
bot,
|
bot,
|
||||||
"/api/v1/messages",
|
"/api/v1/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": orjson.dumps([stream.id]).decode(),
|
"to": orjson.dumps([stream.id]).decode(),
|
||||||
"content": "Stream message to an empty stream by id.",
|
"content": "Stream message to an empty stream by id.",
|
||||||
"topic": "Test topic for empty stream id message",
|
"topic": "Test topic for empty stream id message",
|
||||||
|
@ -213,21 +219,25 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
Sending a message to a stream (by stream ID) to which you are
|
Sending a message to a stream (by stream ID) to which you are
|
||||||
subscribed is successful.
|
subscribed is successful.
|
||||||
"""
|
"""
|
||||||
|
recipient_type_name = ["stream", "channel"]
|
||||||
self.login("hamlet")
|
self.login("hamlet")
|
||||||
realm = get_realm("zulip")
|
realm = get_realm("zulip")
|
||||||
stream = get_stream("Verona", realm)
|
stream = get_stream("Verona", realm)
|
||||||
result = self.client_post(
|
|
||||||
"/json/messages",
|
for recipient_type in recipient_type_name:
|
||||||
{
|
content = f"Stream message by ID, type parameter: {recipient_type}."
|
||||||
"type": "stream",
|
result = self.client_post(
|
||||||
"to": orjson.dumps([stream.id]).decode(),
|
"/json/messages",
|
||||||
"content": "Stream message by ID.",
|
{
|
||||||
"topic": "Test topic for stream ID message",
|
"type": recipient_type,
|
||||||
},
|
"to": orjson.dumps([stream.id]).decode(),
|
||||||
)
|
"content": content,
|
||||||
self.assert_json_success(result)
|
"topic": "Test topic for stream ID message",
|
||||||
sent_message = self.get_last_message()
|
},
|
||||||
self.assertEqual(sent_message.content, "Stream message by ID.")
|
)
|
||||||
|
self.assert_json_success(result)
|
||||||
|
sent_message = self.get_last_message()
|
||||||
|
self.assertEqual(sent_message.content, content)
|
||||||
|
|
||||||
def test_sending_message_as_stream_post_policy_admins(self) -> None:
|
def test_sending_message_as_stream_post_policy_admins(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -522,7 +532,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
user,
|
user,
|
||||||
"/api/v1/messages",
|
"/api/v1/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"content": "Test message no to",
|
"content": "Test message no to",
|
||||||
"topic": "Test topic",
|
"topic": "Test topic",
|
||||||
},
|
},
|
||||||
|
@ -542,7 +552,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
result = self.client_post(
|
result = self.client_post(
|
||||||
"/json/messages",
|
"/json/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": "nonexistent_stream",
|
"to": "nonexistent_stream",
|
||||||
"content": "Test message",
|
"content": "Test message",
|
||||||
"topic": "Test topic",
|
"topic": "Test topic",
|
||||||
|
@ -559,7 +569,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
result = self.client_post(
|
result = self.client_post(
|
||||||
"/json/messages",
|
"/json/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": """&<"'><non-existent>""",
|
"to": """&<"'><non-existent>""",
|
||||||
"content": "Test message",
|
"content": "Test message",
|
||||||
"topic": "Test topic",
|
"topic": "Test topic",
|
||||||
|
@ -585,7 +595,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
user,
|
user,
|
||||||
"/api/v1/messages",
|
"/api/v1/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": orjson.dumps("Verona").decode(),
|
"to": orjson.dumps("Verona").decode(),
|
||||||
"content": "Test message",
|
"content": "Test message",
|
||||||
"topic": "Test topic",
|
"topic": "Test topic",
|
||||||
|
@ -601,7 +611,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
user,
|
user,
|
||||||
"/api/v1/messages",
|
"/api/v1/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": orjson.dumps("Verona").decode(),
|
"to": orjson.dumps("Verona").decode(),
|
||||||
"content": "Another Test message",
|
"content": "Another Test message",
|
||||||
"topic": "Test topic",
|
"topic": "Test topic",
|
||||||
|
@ -882,7 +892,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
result = self.client_post(
|
result = self.client_post(
|
||||||
"/json/messages",
|
"/json/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": "Verona",
|
"to": "Verona",
|
||||||
"content": "Test message",
|
"content": "Test message",
|
||||||
"topic": "",
|
"topic": "",
|
||||||
|
@ -897,7 +907,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
self.login("hamlet")
|
self.login("hamlet")
|
||||||
result = self.client_post(
|
result = self.client_post(
|
||||||
"/json/messages",
|
"/json/messages",
|
||||||
{"type": "stream", "to": "Verona", "content": "Test message"},
|
{"type": "channel", "to": "Verona", "content": "Test message"},
|
||||||
)
|
)
|
||||||
self.assert_json_error(result, "Missing topic")
|
self.assert_json_error(result, "Missing topic")
|
||||||
|
|
||||||
|
@ -910,7 +920,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
result = self.client_post(
|
result = self.client_post(
|
||||||
"/json/messages",
|
"/json/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": "Verona",
|
"to": "Verona",
|
||||||
"topic": "Test\n\rTopic",
|
"topic": "Test\n\rTopic",
|
||||||
"content": "Test message",
|
"content": "Test message",
|
||||||
|
@ -922,7 +932,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
result = self.client_post(
|
result = self.client_post(
|
||||||
"/json/messages",
|
"/json/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": "Verona",
|
"to": "Verona",
|
||||||
"topic": "Test\ufffeTopic",
|
"topic": "Test\ufffeTopic",
|
||||||
"content": "Test message",
|
"content": "Test message",
|
||||||
|
@ -932,7 +942,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
|
|
||||||
def test_invalid_recipient_type(self) -> None:
|
def test_invalid_recipient_type(self) -> None:
|
||||||
"""
|
"""
|
||||||
Messages other than the type of "direct", "private" or "stream" are invalid.
|
Messages other than the type of "direct", "private", "channel" or "stream" are invalid.
|
||||||
"""
|
"""
|
||||||
self.login("hamlet")
|
self.login("hamlet")
|
||||||
result = self.client_post(
|
result = self.client_post(
|
||||||
|
@ -1072,7 +1082,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
"""
|
"""
|
||||||
self.login("hamlet")
|
self.login("hamlet")
|
||||||
post_data = {
|
post_data = {
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": "Verona",
|
"to": "Verona",
|
||||||
"content": " I like null bytes \x00 in my content",
|
"content": " I like null bytes \x00 in my content",
|
||||||
"topic": "Test topic",
|
"topic": "Test topic",
|
||||||
|
@ -1086,7 +1096,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
"""
|
"""
|
||||||
self.login("hamlet")
|
self.login("hamlet")
|
||||||
post_data = {
|
post_data = {
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": orjson.dumps("Verona").decode(),
|
"to": orjson.dumps("Verona").decode(),
|
||||||
"content": " I like whitespace at the end! \n\n \n",
|
"content": " I like whitespace at the end! \n\n \n",
|
||||||
"topic": "Test topic",
|
"topic": "Test topic",
|
||||||
|
@ -1098,7 +1108,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
|
|
||||||
# Test if it removes the new line from the beginning of the message.
|
# Test if it removes the new line from the beginning of the message.
|
||||||
post_data = {
|
post_data = {
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": orjson.dumps("Verona").decode(),
|
"to": orjson.dumps("Verona").decode(),
|
||||||
"content": "\nAvoid the new line at the beginning of the message.",
|
"content": "\nAvoid the new line at the beginning of the message.",
|
||||||
"topic": "Test topic",
|
"topic": "Test topic",
|
||||||
|
@ -1120,7 +1130,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
MAX_MESSAGE_LENGTH = settings.MAX_MESSAGE_LENGTH
|
MAX_MESSAGE_LENGTH = settings.MAX_MESSAGE_LENGTH
|
||||||
long_message = "A" * (MAX_MESSAGE_LENGTH + 1)
|
long_message = "A" * (MAX_MESSAGE_LENGTH + 1)
|
||||||
post_data = {
|
post_data = {
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": orjson.dumps("Verona").decode(),
|
"to": orjson.dumps("Verona").decode(),
|
||||||
"content": long_message,
|
"content": long_message,
|
||||||
"topic": "Test topic",
|
"topic": "Test topic",
|
||||||
|
@ -1141,7 +1151,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
self.login("hamlet")
|
self.login("hamlet")
|
||||||
long_topic_name = "A" * (MAX_TOPIC_NAME_LENGTH + 1)
|
long_topic_name = "A" * (MAX_TOPIC_NAME_LENGTH + 1)
|
||||||
post_data = {
|
post_data = {
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": orjson.dumps("Verona").decode(),
|
"to": orjson.dumps("Verona").decode(),
|
||||||
"content": "test content",
|
"content": "test content",
|
||||||
"topic": long_topic_name,
|
"topic": long_topic_name,
|
||||||
|
@ -1157,7 +1167,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
result = self.client_post(
|
result = self.client_post(
|
||||||
"/json/messages",
|
"/json/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": "Verona",
|
"to": "Verona",
|
||||||
"content": "Test message",
|
"content": "Test message",
|
||||||
"topic": "Test topic",
|
"topic": "Test topic",
|
||||||
|
@ -1185,7 +1195,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
self.mit_user("starnine"),
|
self.mit_user("starnine"),
|
||||||
"/api/v1/messages",
|
"/api/v1/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"sender": self.mit_email("sipbtest"),
|
"sender": self.mit_email("sipbtest"),
|
||||||
"content": "Test message",
|
"content": "Test message",
|
||||||
"client": "zephyr_mirror",
|
"client": "zephyr_mirror",
|
||||||
|
@ -1282,7 +1292,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
user,
|
user,
|
||||||
"/api/v1/messages",
|
"/api/v1/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"forged": "true",
|
"forged": "true",
|
||||||
"time": fake_timestamp,
|
"time": fake_timestamp,
|
||||||
"sender": "irc-user@irc.zulip.com",
|
"sender": "irc-user@irc.zulip.com",
|
||||||
|
@ -1305,7 +1315,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
user,
|
user,
|
||||||
"/api/v1/messages",
|
"/api/v1/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"forged": "yes",
|
"forged": "yes",
|
||||||
"time": fake_timestamp,
|
"time": fake_timestamp,
|
||||||
"sender": "irc-user@irc.zulip.com",
|
"sender": "irc-user@irc.zulip.com",
|
||||||
|
@ -1335,7 +1345,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
|
|
||||||
def test_with(sender_email: str, client: str, forged: bool) -> None:
|
def test_with(sender_email: str, client: str, forged: bool) -> None:
|
||||||
payload = dict(
|
payload = dict(
|
||||||
type="stream",
|
type="channel",
|
||||||
to=orjson.dumps(stream_name).decode(),
|
to=orjson.dumps(stream_name).decode(),
|
||||||
client=client,
|
client=client,
|
||||||
topic="whatever",
|
topic="whatever",
|
||||||
|
@ -1382,7 +1392,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
self.make_stream(stream_name, invite_only=True)
|
self.make_stream(stream_name, invite_only=True)
|
||||||
|
|
||||||
payload = dict(
|
payload = dict(
|
||||||
type="stream",
|
type="channel",
|
||||||
to=orjson.dumps(stream_name).decode(),
|
to=orjson.dumps(stream_name).decode(),
|
||||||
topic="whatever",
|
topic="whatever",
|
||||||
content="whatever",
|
content="whatever",
|
||||||
|
@ -1408,7 +1418,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
notification_bot,
|
notification_bot,
|
||||||
"/api/v1/messages",
|
"/api/v1/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": orjson.dumps("notify_channel").decode(),
|
"to": orjson.dumps("notify_channel").decode(),
|
||||||
"content": "Test message",
|
"content": "Test message",
|
||||||
"topic": "Test topic",
|
"topic": "Test topic",
|
||||||
|
@ -1429,7 +1439,7 @@ class MessagePOSTTest(ZulipTestCase):
|
||||||
stream_name = "public stream"
|
stream_name = "public stream"
|
||||||
self.make_stream(stream_name, invite_only=False)
|
self.make_stream(stream_name, invite_only=False)
|
||||||
payload = dict(
|
payload = dict(
|
||||||
type="stream",
|
type="channel",
|
||||||
to=orjson.dumps(stream_name).decode(),
|
to=orjson.dumps(stream_name).decode(),
|
||||||
topic="whatever",
|
topic="whatever",
|
||||||
content="whatever",
|
content="whatever",
|
||||||
|
@ -2211,7 +2221,7 @@ class StreamMessagesTest(ZulipTestCase):
|
||||||
user,
|
user,
|
||||||
"/api/v1/messages",
|
"/api/v1/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": orjson.dumps("Verona").decode(),
|
"to": orjson.dumps("Verona").decode(),
|
||||||
"sender": self.mit_email("sipbtest"),
|
"sender": self.mit_email("sipbtest"),
|
||||||
"client": "zephyr_mirror",
|
"client": "zephyr_mirror",
|
||||||
|
@ -2228,7 +2238,7 @@ class StreamMessagesTest(ZulipTestCase):
|
||||||
user,
|
user,
|
||||||
"/api/v1/messages",
|
"/api/v1/messages",
|
||||||
{
|
{
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": "Verona",
|
"to": "Verona",
|
||||||
"sender": self.mit_email("sipbtest"),
|
"sender": self.mit_email("sipbtest"),
|
||||||
"client": "zephyr_mirror",
|
"client": "zephyr_mirror",
|
||||||
|
|
|
@ -40,7 +40,7 @@ class ScheduledMessageTest(ZulipTestCase):
|
||||||
self.login("hamlet")
|
self.login("hamlet")
|
||||||
|
|
||||||
topic_name = ""
|
topic_name = ""
|
||||||
if msg_type == "stream":
|
if msg_type in ["stream", "channel"]:
|
||||||
topic_name = "Test topic"
|
topic_name = "Test topic"
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
|
@ -61,7 +61,7 @@ class ScheduledMessageTest(ZulipTestCase):
|
||||||
|
|
||||||
# Scheduling a message to a stream you are subscribed is successful.
|
# Scheduling a message to a stream you are subscribed is successful.
|
||||||
result = self.do_schedule_message(
|
result = self.do_schedule_message(
|
||||||
"stream", verona_stream_id, content + " 1", scheduled_delivery_timestamp
|
"channel", verona_stream_id, content + " 1", scheduled_delivery_timestamp
|
||||||
)
|
)
|
||||||
scheduled_message = self.last_scheduled_message()
|
scheduled_message = self.last_scheduled_message()
|
||||||
self.assert_json_success(result)
|
self.assert_json_success(result)
|
||||||
|
@ -99,7 +99,7 @@ class ScheduledMessageTest(ZulipTestCase):
|
||||||
scheduled_delivery_timestamp = int(scheduled_delivery_datetime.timestamp())
|
scheduled_delivery_timestamp = int(scheduled_delivery_datetime.timestamp())
|
||||||
verona_stream_id = self.get_stream_id("Verona")
|
verona_stream_id = self.get_stream_id("Verona")
|
||||||
result = self.do_schedule_message(
|
result = self.do_schedule_message(
|
||||||
"stream", verona_stream_id, content + " 1", scheduled_delivery_timestamp
|
"channel", verona_stream_id, content + " 1", scheduled_delivery_timestamp
|
||||||
)
|
)
|
||||||
self.assert_json_success(result)
|
self.assert_json_success(result)
|
||||||
|
|
||||||
|
@ -420,7 +420,7 @@ class ScheduledMessageTest(ZulipTestCase):
|
||||||
scheduled_delivery_timestamp = int(time.time() - 86400)
|
scheduled_delivery_timestamp = int(time.time() - 86400)
|
||||||
|
|
||||||
result = self.do_schedule_message(
|
result = self.do_schedule_message(
|
||||||
"stream", verona_stream_id, content + " 1", scheduled_delivery_timestamp
|
"channel", verona_stream_id, content + " 1", scheduled_delivery_timestamp
|
||||||
)
|
)
|
||||||
self.assert_json_error(result, "Scheduled delivery time must be in the future.")
|
self.assert_json_error(result, "Scheduled delivery time must be in the future.")
|
||||||
|
|
||||||
|
@ -431,7 +431,7 @@ class ScheduledMessageTest(ZulipTestCase):
|
||||||
|
|
||||||
# Scheduling a message to a stream you are subscribed is successful.
|
# Scheduling a message to a stream you are subscribed is successful.
|
||||||
result = self.do_schedule_message(
|
result = self.do_schedule_message(
|
||||||
"stream", verona_stream_id, content, scheduled_delivery_timestamp
|
"channel", verona_stream_id, content, scheduled_delivery_timestamp
|
||||||
)
|
)
|
||||||
scheduled_message = self.last_scheduled_message()
|
scheduled_message = self.last_scheduled_message()
|
||||||
self.assert_json_success(result)
|
self.assert_json_success(result)
|
||||||
|
@ -445,6 +445,26 @@ class ScheduledMessageTest(ZulipTestCase):
|
||||||
scheduled_message_id = scheduled_message.id
|
scheduled_message_id = scheduled_message.id
|
||||||
payload: Dict[str, Any]
|
payload: Dict[str, Any]
|
||||||
|
|
||||||
|
# Edit message with other stream message type ("stream") and no other changes
|
||||||
|
# results in no changes to the scheduled message.
|
||||||
|
payload = {
|
||||||
|
"type": "stream",
|
||||||
|
"to": orjson.dumps(verona_stream_id).decode(),
|
||||||
|
"topic": "Test topic",
|
||||||
|
}
|
||||||
|
result = self.client_patch(f"/json/scheduled_messages/{scheduled_message_id}", payload)
|
||||||
|
self.assert_json_success(result)
|
||||||
|
|
||||||
|
scheduled_message = self.get_scheduled_message(str(scheduled_message_id))
|
||||||
|
self.assertEqual(scheduled_message.recipient.type, Recipient.STREAM)
|
||||||
|
self.assertEqual(scheduled_message.stream_id, verona_stream_id)
|
||||||
|
self.assertEqual(scheduled_message.content, "Original test message")
|
||||||
|
self.assertEqual(scheduled_message.topic_name(), "Test topic")
|
||||||
|
self.assertEqual(
|
||||||
|
scheduled_message.scheduled_timestamp,
|
||||||
|
timestamp_to_datetime(scheduled_delivery_timestamp),
|
||||||
|
)
|
||||||
|
|
||||||
# Sending request with only scheduled message ID returns an error
|
# Sending request with only scheduled message ID returns an error
|
||||||
result = self.client_patch(f"/json/scheduled_messages/{scheduled_message_id}")
|
result = self.client_patch(f"/json/scheduled_messages/{scheduled_message_id}")
|
||||||
self.assert_json_error(result, "Nothing to change")
|
self.assert_json_error(result, "Nothing to change")
|
||||||
|
@ -480,7 +500,7 @@ class ScheduledMessageTest(ZulipTestCase):
|
||||||
|
|
||||||
# Trying to edit `type` to stream message type without a `topic` returns an error
|
# Trying to edit `type` to stream message type without a `topic` returns an error
|
||||||
payload = {
|
payload = {
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": orjson.dumps(verona_stream_id).decode(),
|
"to": orjson.dumps(verona_stream_id).decode(),
|
||||||
}
|
}
|
||||||
result = self.client_patch(f"/json/scheduled_messages/{scheduled_message_id}", payload)
|
result = self.client_patch(f"/json/scheduled_messages/{scheduled_message_id}", payload)
|
||||||
|
@ -490,7 +510,7 @@ class ScheduledMessageTest(ZulipTestCase):
|
||||||
|
|
||||||
# Edit message `type` to stream with valid `to` and `topic` succeeds
|
# Edit message `type` to stream with valid `to` and `topic` succeeds
|
||||||
payload = {
|
payload = {
|
||||||
"type": "stream",
|
"type": "channel",
|
||||||
"to": orjson.dumps(verona_stream_id).decode(),
|
"to": orjson.dumps(verona_stream_id).decode(),
|
||||||
"topic": "New test topic",
|
"topic": "New test topic",
|
||||||
}
|
}
|
||||||
|
@ -568,7 +588,7 @@ class ScheduledMessageTest(ZulipTestCase):
|
||||||
verona_stream_id = self.get_stream_id("Verona")
|
verona_stream_id = self.get_stream_id("Verona")
|
||||||
content = "Test message"
|
content = "Test message"
|
||||||
scheduled_delivery_timestamp = int(time.time() + 86400)
|
scheduled_delivery_timestamp = int(time.time() + 86400)
|
||||||
self.do_schedule_message("stream", verona_stream_id, content, scheduled_delivery_timestamp)
|
self.do_schedule_message("channel", verona_stream_id, content, scheduled_delivery_timestamp)
|
||||||
|
|
||||||
# Single scheduled message
|
# Single scheduled message
|
||||||
result = self.client_get("/json/scheduled_messages")
|
result = self.client_get("/json/scheduled_messages")
|
||||||
|
@ -611,7 +631,7 @@ class ScheduledMessageTest(ZulipTestCase):
|
||||||
verona_stream_id = self.get_stream_id("Verona")
|
verona_stream_id = self.get_stream_id("Verona")
|
||||||
scheduled_delivery_timestamp = int(time.time() + 86400)
|
scheduled_delivery_timestamp = int(time.time() + 86400)
|
||||||
|
|
||||||
self.do_schedule_message("stream", verona_stream_id, content, scheduled_delivery_timestamp)
|
self.do_schedule_message("channel", verona_stream_id, content, scheduled_delivery_timestamp)
|
||||||
scheduled_message = self.last_scheduled_message()
|
scheduled_message = self.last_scheduled_message()
|
||||||
self.logout()
|
self.logout()
|
||||||
|
|
||||||
|
@ -649,7 +669,7 @@ class ScheduledMessageTest(ZulipTestCase):
|
||||||
scheduled_delivery_timestamp = int(time.time() + 86400)
|
scheduled_delivery_timestamp = int(time.time() + 86400)
|
||||||
|
|
||||||
# Test sending with attachment
|
# Test sending with attachment
|
||||||
self.do_schedule_message("stream", verona_stream_id, content, scheduled_delivery_timestamp)
|
self.do_schedule_message("channel", verona_stream_id, content, scheduled_delivery_timestamp)
|
||||||
scheduled_message = self.last_scheduled_message()
|
scheduled_message = self.last_scheduled_message()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
list(attachment_object1.scheduled_messages.all().values_list("id", flat=True)),
|
list(attachment_object1.scheduled_messages.all().values_list("id", flat=True)),
|
||||||
|
|
|
@ -367,6 +367,26 @@ class TypingHappyPathTestDirectMessages(ZulipTestCase):
|
||||||
|
|
||||||
|
|
||||||
class TypingHappyPathTestStreams(ZulipTestCase):
|
class TypingHappyPathTestStreams(ZulipTestCase):
|
||||||
|
def test_valid_type_and_op_parameters(self) -> None:
|
||||||
|
recipient_type_name = ["channel", "stream"]
|
||||||
|
operator_type = ["start", "stop"]
|
||||||
|
sender = self.example_user("hamlet")
|
||||||
|
stream_name = self.get_streams(sender)[0]
|
||||||
|
stream_id = self.get_stream_id(stream_name)
|
||||||
|
topic_name = "Some topic"
|
||||||
|
|
||||||
|
for recipient_type in recipient_type_name:
|
||||||
|
for operator in operator_type:
|
||||||
|
params = dict(
|
||||||
|
type=recipient_type,
|
||||||
|
op=operator,
|
||||||
|
stream_id=str(stream_id),
|
||||||
|
topic=topic_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
result = self.api_post(sender, "/api/v1/typing", params)
|
||||||
|
self.assert_json_success(result)
|
||||||
|
|
||||||
def test_start(self) -> None:
|
def test_start(self) -> None:
|
||||||
sender = self.example_user("hamlet")
|
sender = self.example_user("hamlet")
|
||||||
stream_name = self.get_streams(sender)[0]
|
stream_name = self.get_streams(sender)[0]
|
||||||
|
|
|
@ -145,6 +145,11 @@ def send_message_backend(
|
||||||
# TODO: Use "direct" here, as well as in events and
|
# TODO: Use "direct" here, as well as in events and
|
||||||
# message (created, schdeduled, drafts) objects/dicts.
|
# message (created, schdeduled, drafts) objects/dicts.
|
||||||
recipient_type_name = "private"
|
recipient_type_name = "private"
|
||||||
|
elif recipient_type_name == "channel":
|
||||||
|
# For now, use "stream" from Message.API_RECIPIENT_TYPES.
|
||||||
|
# TODO: Use "channel" here, as well as in events and
|
||||||
|
# message (created, schdeduled, drafts) objects/dicts.
|
||||||
|
recipient_type_name = "stream"
|
||||||
|
|
||||||
# If req_to is None, then we default to an
|
# If req_to is None, then we default to an
|
||||||
# empty list of recipients.
|
# empty list of recipients.
|
||||||
|
|
|
@ -66,6 +66,12 @@ def update_scheduled_message_backend(
|
||||||
else:
|
else:
|
||||||
recipient_type_name = req_type
|
recipient_type_name = req_type
|
||||||
|
|
||||||
|
if recipient_type_name is not None and recipient_type_name == "channel":
|
||||||
|
# For now, use "stream" from Message.API_RECIPIENT_TYPES.
|
||||||
|
# TODO: Use "channel" here, as well as in events and
|
||||||
|
# message (created, schdeduled, drafts) objects/dicts.
|
||||||
|
recipient_type_name = "stream"
|
||||||
|
|
||||||
if recipient_type_name is not None and recipient_type_name == "stream" and topic_name is None:
|
if recipient_type_name is not None and recipient_type_name == "stream" and topic_name is None:
|
||||||
raise JsonableError(_("Topic required when updating scheduled message type to stream."))
|
raise JsonableError(_("Topic required when updating scheduled message type to stream."))
|
||||||
|
|
||||||
|
@ -123,6 +129,11 @@ def create_scheduled_message_backend(
|
||||||
# TODO: Use "direct" here, as well as in events and
|
# TODO: Use "direct" here, as well as in events and
|
||||||
# scheduled message objects/dicts.
|
# scheduled message objects/dicts.
|
||||||
recipient_type_name = "private"
|
recipient_type_name = "private"
|
||||||
|
elif recipient_type_name == "channel":
|
||||||
|
# For now, use "stream" from Message.API_RECIPIENT_TYPES.
|
||||||
|
# TODO: Use "channel" here, as well as in events and
|
||||||
|
# message (created, schdeduled, drafts) objects/dicts.
|
||||||
|
recipient_type_name = "stream"
|
||||||
|
|
||||||
deliver_at = timestamp_to_datetime(scheduled_delivery_timestamp)
|
deliver_at = timestamp_to_datetime(scheduled_delivery_timestamp)
|
||||||
if deliver_at <= timezone_now():
|
if deliver_at <= timezone_now():
|
||||||
|
|
|
@ -12,7 +12,7 @@ from zerver.lib.validator import check_int, check_list, check_string_in
|
||||||
from zerver.models import UserProfile
|
from zerver.models import UserProfile
|
||||||
|
|
||||||
VALID_OPERATOR_TYPES = ["start", "stop"]
|
VALID_OPERATOR_TYPES = ["start", "stop"]
|
||||||
VALID_RECIPIENT_TYPES = ["direct", "stream"]
|
VALID_RECIPIENT_TYPES = ["direct", "stream", "channel"]
|
||||||
|
|
||||||
|
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
|
@ -30,6 +30,12 @@ def send_notification_backend(
|
||||||
topic: Optional[str] = REQ("topic", default=None),
|
topic: Optional[str] = REQ("topic", default=None),
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
recipient_type_name = req_type
|
recipient_type_name = req_type
|
||||||
|
if recipient_type_name == "channel":
|
||||||
|
# For now, use "stream" from Message.API_RECIPIENT_TYPES.
|
||||||
|
# TODO: Use "channel" here, as well as in events and
|
||||||
|
# message (created, schdeduled, drafts) objects/dicts.
|
||||||
|
recipient_type_name = "stream"
|
||||||
|
|
||||||
if recipient_type_name == "stream":
|
if recipient_type_name == "stream":
|
||||||
if stream_id is None:
|
if stream_id is None:
|
||||||
raise JsonableError(_("Missing stream_id"))
|
raise JsonableError(_("Missing stream_id"))
|
||||||
|
|
Loading…
Reference in New Issue