# Slack


This is for creating Slack applications or bots in Elixir.

To listen for subscribed events, it uses **Socket Mode** to connect to Slack, which has some restrictions, so
please read up on that.

It's a relatively thin wrapper, which keeps it flexible and easy to maintain, but
it does mean there are less conveniences than a full bot/app framework/SDK.

## Installation

Add `slack_elixir` to your list of dependencies in `mix.exs`:

def deps do
    {:slack_elixir, "~> 1.0.0"}

## Setup

You will need to:

  - Create a Slack app for your workspace
  - Add permissions (scopes)
  - Connect it to your workspace
  - Get an OAuth Bot Token (will have the scopes you defined)
  - Enable Socket Mode
  - Get an app-level token with `connections:write` scope
  - Add Event Subscriptions

See below for some minimum required scopes and event subscriptions. You will
need to add more scopes and subscriptions depending on what you want to do.

#### Required Bot Token scopes:
 - `channels:history`
 - `channels:read`
 - `groups:read`
 - `mpim:read`
 - `im:read`

#### Required Bot Event Subscriptions
 - `message.channels`
 - `member_joined_channel`
 - `channel_left`

Write the Bot module:
defmodule MyApp.Slackbot do
  use Slack.Bot

  require Logger

  @impl true
  # A silly example of old-school style bot commands.
  def handle_event("message", %{"text" => "!" <> command, "channel" => channel, "user" => user}) do
    case command do
      "roll" ->
        send_message(channel, "<@#{user}> rolled a #{Enum.random(1..6)}")

      "echo " <> text ->
        send_message(channel, text)

      _ ->
        send_message(channel, "Unknown command: #{command}")

  def handle_event("message", %{"channel" => channel, "text" => text, "user" => user}) do
    if String.match?(text, ~r/hello/i) do
      send_message(channel, "Hello! <@#{user}>")

  def handle_event(type, payload) do
    Logger.debug("Unhandled #{type} event: #{inspect(payload)}")

Then you start the Slack Supervisor in your application's supervision tree.

For example:

  def start(_type, _args) do
    # Often, you'd fetch this from application env,
    # set in `config/runtime.exs`, instead of like this.
    config = [
      app_token: "MY_SLACK_APP_TOKEN",
      bot_token: "MY_SLACK_BOT_TOKEN",
      bot: MyApp.SlackBot

    children = [
      # ...
      {Slack.Supervisor, config}

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)

## Journey to v1.0 (Things that may or may not be added)

PRs welcome!

- [x] **Socket Mode** for events
- [x] Web API POST requests
- [x] Web API GET requests
- [x] Message Server per channel (rate-limited to 1 message per second per channel).