defmodule Slack.Sends do
@moduledoc """
Utility functions for sending slack messages.
"""
alias Slack.Lookups
@doc """
Sends `text` to `channel` for the given `slack` connection. `channel` can be
a string in the format of `"#CHANNEL_NAME"`, `"@USER_NAME"`, or any ID that
Slack understands.
NOTE: Referencing `"@USER_NAME"` is deprecated, and should not be used.
For more information see https://api.slack.com/changelog/2017-09-the-one-about-usernames
"""
def send_message(text, channel = "#" <> channel_name, slack) do
channel_id = Lookups.lookup_channel_id(channel, slack)
if channel_id do
send_message(text, channel_id, slack)
else
raise ArgumentError, "channel ##{channel_name} not found"
end
end
def send_message(text, user_id = "U" <> _user_id, slack) do
send_message_to_user(text, user_id, slack)
end
def send_message(text, user_id = "W" <> _user_id, slack) do
send_message_to_user(text, user_id, slack)
end
def send_message(text, user = "@" <> _user_name, slack) do
user_id = Lookups.lookup_user_id(user, slack)
send_message(text, user_id, slack)
end
def send_message(text, channel, slack) do
%{
type: "message",
text: text,
channel: channel
}
|> Jason.encode!()
|> send_raw(slack)
end
def send_message(text, channel = "#" <> channel_name, slack, thread) do
channel_id = Lookups.lookup_channel_id(channel, slack)
if channel_id do
send_message(text, channel_id, slack, thread)
else
raise ArgumentError, "channel ##{channel_name} not found"
end
end
def send_message(text, channel, slack, thread) do
%{
type: "message",
text: text,
channel: channel,
thread_ts: thread
}
|> Jason.encode!()
|> send_raw(slack)
end
@doc """
Notifies Slack that the current user is typing in `channel`.
"""
def indicate_typing(channel, slack) do
%{
type: "typing",
channel: channel
}
|> Jason.encode!()
|> send_raw(slack)
end
@doc """
Notifies slack that the current `slack` user is typing in `channel`.
"""
def send_ping(data \\ %{}, slack) do
%{
type: "ping"
}
|> Map.merge(Map.new(data))
|> Jason.encode!()
|> send_raw(slack)
end
@doc """
Subscribe to presence notifications for the user IDs in `ids`.
"""
def subscribe_presence(ids \\ [], slack) do
%{
type: "presence_sub",
ids: ids
}
|> Jason.encode!()
|> send_raw(slack)
end
@doc """
Sends raw JSON to a given socket.
"""
def send_raw(json, %{process: pid, client: client}) do
client.cast(pid, {:text, json})
end
defp send_message_to_user(text, user_id, slack) do
direct_message_id = Lookups.lookup_direct_message_id(user_id, slack)
if direct_message_id do
send_message(text, direct_message_id, slack)
else
open_im_channel(
slack.token,
user_id,
fn id -> send_message(text, id, slack) end,
fn reason -> reason end
)
end
end
defp open_im_channel(token, user_id, on_success, on_error) do
im_open =
with url <- Application.get_env(:slack, :url, "https://slack.com") <> "/api/im.open",
headers <- {:form, [token: token, user: user_id]},
options <-
Application.get_env(:slack, :web_http_client_opts, [{"Content-Type", "utf-8"}]) do
HTTPoison.post(url, headers, options)
end
case im_open do
{:ok, response} ->
case Jason.decode!(response.body, keys: :atoms) do
%{ok: true, channel: %{id: id}} -> on_success.(id)
e = %{error: _error_message} -> on_error.(e)
end
{:error, reason} ->
on_error.(reason)
end
end
end