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