Skip to content

Commit

Permalink
message and message-thread
Browse files Browse the repository at this point in the history
  • Loading branch information
maorfr committed May 8, 2024
1 parent 7bffdc9 commit 57c46ec
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 12 deletions.
37 changes: 27 additions & 10 deletions reconcile/utils/slack_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
Protocol,
Union,
)
from urllib.parse import urlparse

from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
Expand Down Expand Up @@ -224,7 +225,7 @@ def _configure_client_retry(self) -> None:
self._sc.retry_handlers.append(rate_limit_handler)
self._sc.retry_handlers.append(server_error_handler)

def chat_post_message(self, text: str) -> None:
def chat_post_message(self, text: str, channel_override: Optional[str] = None, thread_ts: Optional[str] = None) -> None:
"""
Try to send a chat message into a channel. If the bot is not in the
channel it will join the channel and send the message again.
Expand All @@ -234,22 +235,23 @@ def chat_post_message(self, text: str) -> None:
:raises slack_sdk.errors.SlackApiError: if unsuccessful response
from Slack API, except for not_in_channel
"""
if not self.channel:
channel = channel_override or self.channel
if not channel:
raise ValueError(
"Slack channel name must be provided when posting messages."
)

def do_send(c: str, t: str) -> None:
slack_request.labels("chat.postMessage", "POST").inc()
self._sc.chat_postMessage(channel=c, text=t, **self.chat_kwargs)
self._sc.chat_postMessage(channel=c, text=t, **self.chat_kwargs, thread_ts=thread_ts)

try:
do_send(self.channel, text)
do_send(channel, text)
except SlackApiError as e:
match e.response["error"]:
case "not_in_channel":
self.join_channel()
do_send(self.channel, text)
self.join_channel(channel_override=channel_override)
do_send(channel, text)
# When a message is sent to #someChannel and the Slack API can't find
# it, the message it provides in the exception doesn't include the
# channel name. We handle that here in case the consumer has many such
Expand All @@ -260,6 +262,20 @@ def do_send(c: str, t: str) -> None:
case _:
raise

def chat_post_message_to_thread(self, text: str, thread_url: str) -> None:
"""
Send a message to a thread
"""
# example parent message url
# https://example.slack.com/archives/C017E996GPP/p1715146351427019
parsed_thread_url = urlparse(thread_url)
if parsed_thread_url.netloc != f"{self.workspace_name}.slack.com":
raise ValueError("Slack workspace must match thread URL.")
_, _, channel_id, p_timstamp = parsed_thread_url.path.split("/")
timstamp = p_timstamp.replace("p", "")
thread_ts = f"{timstamp[:10]}.{timstamp[10:]}"
self.chat_post_message(text, channel_override=channel_id, thread_ts=thread_ts)

def describe_usergroup(
self, handle: str
) -> tuple[dict[str, str], dict[str, str], str]:
Expand All @@ -274,21 +290,22 @@ def describe_usergroup(

return users, channels, description

def join_channel(self) -> None:
def join_channel(self, channel_override: Optional[str] = None) -> None:
"""
Join a given channel if not already a member, will join self.channel
:raises slack_sdk.errors.SlackApiError: if unsuccessful response from
Slack API
:raises ValueError: if self.channel is not set
"""
if not self.channel:
channel = channel_override or self.channel
if channel:
raise ValueError(
"Slack channel name must be provided when joining a channel."
)

channels_found = self.get_channels_by_names(self.channel)
[channel_id] = [k for k in channels_found if channels_found[k] == self.channel]
channels_found = self.get_channels_by_names(channel)
[channel_id] = [k for k in channels_found if channels_found[k] == channel]
slack_request.labels("conversations.info", "GET").inc()

info = self._sc.conversations_info(channel=channel_id)
Expand Down
22 changes: 20 additions & 2 deletions tools/qontract_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2605,17 +2605,35 @@ def slack_usergroup(ctx, workspace, usergroup, username):
slack.update_usergroup_users(ugid, users)


@root.command()
@root.group(name="slack")
@output
@click.pass_context
def slack(ctx, output):
ctx.obj["output"] = output

@slack.command()
@click.argument("message")
@click.pass_context
def slack_message(ctx, message):
def message(ctx, message: str):
"""
Send a Slack message.
"""
slack = slackapi_from_queries("qontract-cli", init_usergroups=False)
slack.chat_post_message(message)


@slack.command()
@click.argument("message")
@click.argument("thread_url")
@click.pass_context
def message_thread(ctx, message: str, thread_url: str):
"""
Send a Slack message to a thread.
"""
slack = slackapi_from_queries("qontract-cli", init_usergroups=False)
slack.chat_post_message_to_thread(message, thread_url)


@set_command.command()
@click.argument("org_name")
@click.argument("cluster_name")
Expand Down

0 comments on commit 57c46ec

Please sign in to comment.