LoginSignup
7
1

More than 5 years have passed since last update.

CTOに対抗してGoでSlack slash command作りました

Last updated at Posted at 2018-12-17

LOB Advent Calendar Advent Calendar 2018 - Qiitaカレンダー18日の記事です。

我が社のCTOことmojibkoさんが、TypeScript で書いた Slack Slash Command を Firebase で動かしたらめちゃくちゃ簡単だった件について でTypeScriptでslash commandを作っていたので、対抗して私はGoでslash commandを作ってみました。(firebaseだとめっちゃ簡単だよ的な所はご紹介できないのですが、すみません。)

何作ったんや

/big :custom絵文字:を打つとmigawari(slack bot)が画像として大きく表示してくれる
slash command2.mov.gif

どうやって作ったの

  1. slash commandの設定をする

  2. Goの実装

実装はこんな感じになります。

func main() {
    logger.Infof("Start big-stamp server.")
    http.HandleFunc("/", handle)
    log.Fatal(http.ListenAndServe(":" + os.Getenv("PORT"), nil))
}

func handle(w http.ResponseWriter, r *http.Request) {
    token := os.Getenv("SLASHCOMMAND")
    if err := r.ParseForm(); err != nil {
        http.Error(w, "Error parsing form.", http.StatusBadRequest)
        return
    }
    channelID := r.Form.Get("channel_id")
    texts := strings.Split(r.Form.Get("text"), " ")
    stampMap := map[string]bool{}
    for _, text := range texts {
        stampMap[text] = false
    }
    sendMsgUrl := "https://slack.com/api/chat.postMessage"

    emojiMsg := emojiList(w, token)
    for k, imgUrl := range emojiMsg {
        ek := fmt.Sprintf(":%s:", k)
        if _, ok := stampMap[ek]; ok {
            sendMsgUrlOption := url.Values{}
            sendMsgUrlOption.Add("token", token)
            sendMsgUrlOption.Add("channel", channelID)
            sendMsgUrlOption.Add("attachments", "[{\"\": \"\", \"text\": \"\", \"image_url\": \""+imgUrl.(string)+"\"}]")
            _, err := http.Post(sendMsgUrl+"?"+sendMsgUrlOption.Encode(), "", nil)
            if err != nil {
                http.Error(w, "can't http post.", http.StatusBadRequest)
            }
        }
    }
}

func emojiList(w http.ResponseWriter, token string) (map[string]interface{}) {
    urlOption := url.Values{}
    urlOption.Add("token", token)

    url := "https://slack.com/api/emoji.list?" + urlOption.Encode()
    resp, err := http.Post(url, "", nil)
    if err != nil {
        http.Error(w, "can not get emoji list.", http.StatusBadRequest)
    }

    b, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        http.Error(w, "cnan not response read.", http.StatusBadRequest)
    }

    var result interface{}
    if err = json.Unmarshal(b, &result); err != nil {
        http.Error(w, "Error parse json.", http.StatusBadRequest)
    }
    msg := result.(map[string]interface{})

    var emoji interface{}
    eb, err := json.Marshal(msg["emoji"])
    if err != nil {
        logger.Errorf("can not emoji marshal err: %v", err)
        http.Error(w, "can not emoji.list.", http.StatusBadRequest)
    }

    if eb == nil {
        logger.Error("not set emoji.")
    }

    json.Unmarshal(eb, &emoji)
    emojiMsg := emoji.(map[string]interface{})

    return emojiMsg
}

3.サーバーにデプロイ
これは個人的に作ったものなので(*所属している団体、企業とは関係ありません)、AWSのec2インスタンスにデプロイして使用しています。

local環境での開発時は、Slack APIで薦められているngrokを使えば、localhostで動いているサーバーを、LANの外からアクセスできるようにできるようになるので、それをRequest URLに設定すれば、簡単に開発することができます。

まとめ

今回作ったslash commandはLineのスタンプ感覚で使いたい時などに活躍します。
これからも色々slash commandで遊んでいこうかな〜と思っています。

我が社では、サーバーサイドはGo, フロントエンドはReactとTypeScriptで開発を行なっています。
興味がある方はぜひ我が社へ〜〜〜💨

7
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1