mirror of https://github.com/zulip/zulip.git
integrations: Update Slack webhook to use check_send_webhook_message.
Due to the channel_map_to_topics URL parameter in the Slack webhook, it was not migrated to use the check_send_webhook_message. By using check_send_webhook_message, any topic parameter in the webhook URL will be prioritized over mapping Slack channels to topics, e.g. when channel_map_to_topics is true. This is because the default behaviour for incoming webhooks is to send a default topic as a parameter to check_send_webhook_message in case there is no topic specified in the URL. In contrast, we can override the stream passed in the URL when channel_map_to_topics is false by passing the Slack channel name to check_send_webhook_message. The default behaviour for incoming webhooks is to send a direct message if there is no specified stream in the URL, so a default stream is not generally passed to check_send_webhook_message. Fixes #27601.
This commit is contained in:
parent
069680a7d1
commit
3a03e14938
|
@ -7,20 +7,20 @@ See also the [Slack-compatible webhook](/integrations/doc/slack_incoming).
|
||||||
|
|
||||||
1. {!create-an-incoming-webhook.md!}
|
1. {!create-an-incoming-webhook.md!}
|
||||||
|
|
||||||
Construct the URL for the {{ integration_display_name }}
|
1. {!generate-integration-url.md!}
|
||||||
bot using the bot's API key:
|
|
||||||
|
|
||||||
`{{ api_url }}{{ integration_url }}?api_key=abcdefgh`
|
If you'd like to map Slack channels to different topics within the same
|
||||||
|
stream, add `&channels_map_to_topics=1` to the end of the URL. Note that
|
||||||
If you'd like to map Slack channels to different topics within the
|
this should be used instead of specifying a topic in the URL. If a topic
|
||||||
same stream, add `&channels_map_to_topics=1` to the end of the URL.
|
is specified in the URL, then it will be prioritized over the channel to
|
||||||
This is the default behavior of the integration.
|
topic mapping.
|
||||||
|
|
||||||
If you'd like to map Slack channels to different streams, add
|
If you'd like to map Slack channels to different streams, add
|
||||||
`&channels_map_to_topics=0` to the end of the URL. Make sure you
|
`&channels_map_to_topics=0` to the end of the URL. Make sure you create
|
||||||
create streams for all your public Slack channels, and that the name
|
streams for all your public Slack channels *(see step 1)*, and that the
|
||||||
of each stream is the same as the name of the Slack channel it maps
|
name of each stream is the same as the name of the Slack channel it maps
|
||||||
to.
|
to. Note that in this case, the channel to stream mapping will be
|
||||||
|
prioritized over the stream specified in the URL.
|
||||||
|
|
||||||
1. Go to <https://my.slack.com/services/new/outgoing-webhook>
|
1. Go to <https://my.slack.com/services/new/outgoing-webhook>
|
||||||
and click **Add Outgoing WebHooks integration**.
|
and click **Add Outgoing WebHooks integration**.
|
||||||
|
|
|
@ -2,31 +2,71 @@ from typing_extensions import override
|
||||||
|
|
||||||
from zerver.lib.test_classes import WebhookTestCase
|
from zerver.lib.test_classes import WebhookTestCase
|
||||||
|
|
||||||
|
EXPECTED_TOPIC = "Message from Slack"
|
||||||
|
EXPECTED_MESSAGE = "**slack_user**: test"
|
||||||
|
|
||||||
|
|
||||||
class SlackWebhookTests(WebhookTestCase):
|
class SlackWebhookTests(WebhookTestCase):
|
||||||
STREAM_NAME = "slack"
|
STREAM_NAME = "slack"
|
||||||
URL_TEMPLATE = "/api/v1/external/slack?stream={stream}&api_key={api_key}"
|
URL_TEMPLATE = "/api/v1/external/slack?stream={stream}&api_key={api_key}"
|
||||||
WEBHOOK_DIR_NAME = "slack"
|
WEBHOOK_DIR_NAME = "slack"
|
||||||
|
|
||||||
def test_slack_channel_to_topic(self) -> None:
|
def test_slack_only_stream_parameter(self) -> None:
|
||||||
expected_topic_name = "channel: general"
|
|
||||||
expected_message = "**slack_user**: test"
|
|
||||||
self.check_webhook(
|
self.check_webhook(
|
||||||
"message_info",
|
"message_info",
|
||||||
expected_topic_name,
|
EXPECTED_TOPIC,
|
||||||
expected_message,
|
EXPECTED_MESSAGE,
|
||||||
content_type="application/x-www-form-urlencoded",
|
content_type="application/x-www-form-urlencoded",
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_slack_channel_to_stream(self) -> None:
|
def test_slack_with_user_specified_topic(self) -> None:
|
||||||
self.STREAM_NAME = "general"
|
self.url = self.build_webhook_url(topic="test")
|
||||||
self.url = "{}{}".format(self.url, "&channels_map_to_topics=0")
|
expected_topic_name = "test"
|
||||||
expected_topic_name = "Message from Slack"
|
|
||||||
expected_message = "**slack_user**: test"
|
|
||||||
self.check_webhook(
|
self.check_webhook(
|
||||||
"message_info",
|
"message_info",
|
||||||
expected_topic_name,
|
expected_topic_name,
|
||||||
expected_message,
|
EXPECTED_MESSAGE,
|
||||||
|
content_type="application/x-www-form-urlencoded",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_slack_channels_map_to_topics_true(self) -> None:
|
||||||
|
self.url = self.build_webhook_url(channels_map_to_topics="1")
|
||||||
|
expected_topic_name = "channel: general"
|
||||||
|
self.check_webhook(
|
||||||
|
"message_info",
|
||||||
|
expected_topic_name,
|
||||||
|
EXPECTED_MESSAGE,
|
||||||
|
content_type="application/x-www-form-urlencoded",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_slack_channels_map_to_topics_true_and_user_specified_topic(self) -> None:
|
||||||
|
self.url = self.build_webhook_url(topic="test", channels_map_to_topics="1")
|
||||||
|
expected_topic_name = "test"
|
||||||
|
self.check_webhook(
|
||||||
|
"message_info",
|
||||||
|
expected_topic_name,
|
||||||
|
EXPECTED_MESSAGE,
|
||||||
|
content_type="application/x-www-form-urlencoded",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_slack_channels_map_to_topics_false(self) -> None:
|
||||||
|
self.STREAM_NAME = "general"
|
||||||
|
self.url = self.build_webhook_url(channels_map_to_topics="0")
|
||||||
|
self.check_webhook(
|
||||||
|
"message_info",
|
||||||
|
EXPECTED_TOPIC,
|
||||||
|
EXPECTED_MESSAGE,
|
||||||
|
content_type="application/x-www-form-urlencoded",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_slack_channels_map_to_topics_false_and_user_specified_topic(self) -> None:
|
||||||
|
self.STREAM_NAME = "general"
|
||||||
|
self.url = self.build_webhook_url(topic="test", channels_map_to_topics="0")
|
||||||
|
expected_topic_name = "test"
|
||||||
|
self.check_webhook(
|
||||||
|
"message_info",
|
||||||
|
expected_topic_name,
|
||||||
|
EXPECTED_MESSAGE,
|
||||||
content_type="application/x-www-form-urlencoded",
|
content_type="application/x-www-form-urlencoded",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -50,7 +90,7 @@ class SlackWebhookTests(WebhookTestCase):
|
||||||
|
|
||||||
def test_invalid_channels_map_to_topics(self) -> None:
|
def test_invalid_channels_map_to_topics(self) -> None:
|
||||||
payload = self.get_body("message_info")
|
payload = self.get_body("message_info")
|
||||||
url = "{}{}".format(self.url, "&channels_map_to_topics=abc")
|
url = self.build_webhook_url(channels_map_to_topics="abc")
|
||||||
result = self.client_post(url, payload, content_type="application/x-www-form-urlencoded")
|
result = self.client_post(url, payload, content_type="application/x-www-form-urlencoded")
|
||||||
self.assert_json_error(result, "Error: channels_map_to_topics parameter other than 0 or 1")
|
self.assert_json_error(result, "Error: channels_map_to_topics parameter other than 0 or 1")
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from django.http.response import HttpResponse
|
from django.http.response import HttpResponse
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from zerver.actions.message_send import check_send_stream_message
|
|
||||||
from zerver.decorator import webhook_view
|
from zerver.decorator import webhook_view
|
||||||
from zerver.lib.exceptions import JsonableError
|
from zerver.lib.exceptions import JsonableError
|
||||||
from zerver.lib.request import RequestNotes
|
|
||||||
from zerver.lib.response import json_success
|
from zerver.lib.response import json_success
|
||||||
from zerver.lib.typed_endpoint import typed_endpoint
|
from zerver.lib.typed_endpoint import typed_endpoint
|
||||||
|
from zerver.lib.webhooks.common import check_send_webhook_message
|
||||||
from zerver.models import UserProfile
|
from zerver.models import UserProfile
|
||||||
|
|
||||||
ZULIP_MESSAGE_TEMPLATE = "**{message_sender}**: {text}"
|
ZULIP_MESSAGE_TEMPLATE = "**{message_sender}**: {text}"
|
||||||
|
@ -23,20 +24,39 @@ def api_slack_webhook(
|
||||||
user_name: str,
|
user_name: str,
|
||||||
text: str,
|
text: str,
|
||||||
channel_name: str,
|
channel_name: str,
|
||||||
stream: str = "slack",
|
channels_map_to_topics: Optional[str] = None,
|
||||||
channels_map_to_topics: str = "1",
|
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
if channels_map_to_topics not in VALID_OPTIONS.values():
|
content = ZULIP_MESSAGE_TEMPLATE.format(message_sender=user_name, text=text)
|
||||||
|
topic_name = "Message from Slack"
|
||||||
|
|
||||||
|
if channels_map_to_topics is None:
|
||||||
|
check_send_webhook_message(
|
||||||
|
request,
|
||||||
|
user_profile,
|
||||||
|
topic_name,
|
||||||
|
content,
|
||||||
|
)
|
||||||
|
elif channels_map_to_topics == VALID_OPTIONS["SHOULD_BE_MAPPED"]:
|
||||||
|
# If the webhook URL has a user_specified_topic,
|
||||||
|
# then this topic-channel mapping will not be used.
|
||||||
|
topic_name = f"channel: {channel_name}"
|
||||||
|
check_send_webhook_message(
|
||||||
|
request,
|
||||||
|
user_profile,
|
||||||
|
topic_name,
|
||||||
|
content,
|
||||||
|
)
|
||||||
|
elif channels_map_to_topics == VALID_OPTIONS["SHOULD_NOT_BE_MAPPED"]:
|
||||||
|
# This stream-channel mapping will be used even if
|
||||||
|
# there is a stream specified in the webhook URL.
|
||||||
|
check_send_webhook_message(
|
||||||
|
request,
|
||||||
|
user_profile,
|
||||||
|
topic_name,
|
||||||
|
content,
|
||||||
|
stream=channel_name,
|
||||||
|
)
|
||||||
|
else:
|
||||||
raise JsonableError(_("Error: channels_map_to_topics parameter other than 0 or 1"))
|
raise JsonableError(_("Error: channels_map_to_topics parameter other than 0 or 1"))
|
||||||
|
|
||||||
if channels_map_to_topics == VALID_OPTIONS["SHOULD_BE_MAPPED"]:
|
|
||||||
topic_name = f"channel: {channel_name}"
|
|
||||||
else:
|
|
||||||
stream = channel_name
|
|
||||||
topic_name = _("Message from Slack")
|
|
||||||
|
|
||||||
content = ZULIP_MESSAGE_TEMPLATE.format(message_sender=user_name, text=text)
|
|
||||||
client = RequestNotes.get_notes(request).client
|
|
||||||
assert client is not None
|
|
||||||
check_send_stream_message(user_profile, client, stream, topic_name, content)
|
|
||||||
return json_success(request)
|
return json_success(request)
|
||||||
|
|
Loading…
Reference in New Issue