LoginSignup
1

More than 3 years have passed since last update.

Organization

ふりかえりのための備忘にSlackを活用する

原題「Cloud FunctionsをバックエンドにSlackのアクションを作る」

:book: あらまし

チームでの開発に定期的なふりかえりは不可欠です。

私が所属するチームでは主にKPT方式でふりかえりを行っています。
しかし加齢のためか、ふりかえりを実施するタイミングでは
既にイテレーション内で起こったことを忘れ去っているという大きなProblemがあります。

そこでSlackのActions(アクション)機能を使って
思いついたその場でKeepやProblemを登録できるフォームを作成します。

:gear: 仕組み

Slackの アクション は、メッセージに対して任意の操作を定義する機能です。

例えば、チャット上でサイトの不具合の報告を受けたときに
その場でJIRAのチケットやGitHubのIssueを作成するような活用例があります。

公式の記事の ダイアグラム にあるように
Slackアプリから送信されるペイロードを自前のアプリケーションで処理することにより
メッセージに紐づく各種データの処理を行うことができます。

本記事では コチラ の記事を参考にインタラクティブなフォームを実装します。
運用コストを下げる為にバックエンドにはGCPのCloudFunctionsを利用します。

:computer: 作業

Slackアプリの作成

参考記事 の「アプリの作成と設定」に従います。

Request URL には自前のアプリケーションの受け口となるURLを記載します。
今回はトリガータイプをHTTPに設定したCloudFunctionsのURLを指定します。
(作成方法は後述のため、一旦仮のURLを設定して後で変更します)

作成が完了すると、メッセージ右上の「その他」メニューからアクションを選択できるようになります。
Slack___test-for-slack-actions___mockmock.png

アプリケーションの実装

関数の作成

GCPのコンソールからCloudFunctionsの関数を作成します。
ペイロードを受け取るため、トリガーはHTTPで設定します。
Cloud_Functions_-_nature_-_Google_Cloud_Platform.png

(AWSのLambdaと比べて、単体でもHTTPリクエストを受け付けられるのが嬉しい)

なお、記事に書く都合上ソースコードをインラインエディタで記載しますが
運用上はCloud Source Repositoriesなどを活用した方が圧倒的に楽です。
動作はNode.js 10(ベータ版)で確認しています。

モジュールの準備

package.json に最低限必要なモジュールを記載しておきます。
CloudFunctions自体が機能を持っていることにより、 参考記事 の内容より少なめです。

{
  "name": " slack-actions-kp",
  "version": "0.0.1",
  "dependencies": {
    "axios": "^0.19.0",
    "qs": "^6.9.1"
  }
}

主な処理

アプリケーションの受け口として複数のURLを設定することはできないため
ペイロードから取得する type によって処理を分ける必要があります。

今回のアプリケーションが受け付けるリクエストは2通りあります。

  1. アクションを選択されたときのリクエスト
  2. フォームが送信されたときのリクエスト
/**
 * Responds to any HTTP request.
 *
 * @param {!express:Request} req HTTP request context.
 * @param {!express:Response} res HTTP response context.
 */
exports.slackActionsKP = (req, res) => {
  const payload = JSON.parse(req.body.payload);
  const {type, submission} = payload;

  if (type === 'message_action') {
    // アクションが選択されたときの処理: Slack上でフォーム(ダイアログ)を開く
  } else if (type === 'dialog_submission') {
    // フォームが送信されたときの処理: 送信された内容をどこかに記録する
  }
}

リクエストの前者では、Slack上でフォーム(ダイアログ)を開く処理を行います。
ダイアログ上の項目の設定については コチラ が詳しいです。

if (type === 'message_action') {
  const dialogData = {
    token: SLACK_ACCESS_TOKEN,  // 環境変数から読み込んで事前に復号する
    trigger_id: payload.trigger_id,
    dialog: JSON.stringify({
      title: 'KとPを忘れない',
      callback_id: 'do_not_forget_kp',
      submit_label: '登録する',
      elements: [
        {
          label: '種別(K/P)',
          type: 'select',
          name: 'type',
          value: 'Keep',
          options: [
            { label: 'Keep', value: 'Keep' },
            { label: 'Problem', value: 'Problem' }
          ],
        },
        {
          label: '内容',
          type: 'textarea',
          name: 'message',
          value: payload.message.text
        },
      ]
    })
  };

  // SlackのAPIでフォーム(ダイアログ)を開く
  // https://api.slack.com/methods/dialog.open
  axios.post('https://slack.com/api/dialog.open', qs.stringify(dialogData))
    .then((result) => {
      if(result.data.error) {
        res.sendStatus(500);
      } else {
        res.sendStatus(200);
      }
    })
    .catch((err) => {
      res.sendStatus(500);
    });
} ...

リクエストの後者では、送信された内容を記録する処理を行います。
今回はIncomingWebhook経由で、専用のチャンネルに内容を投稿します。

} else if (type === 'dialog_submission') {
  // 結果だけ先に返す
  res.send('');

  // Slackにメッセージを投稿する
  const emoji = submission.type === 'Keep' ? ':ok_woman:' : ':no_good:'
  const data = {
    text: `${emoji} ${submission.type} ${submission.message}`
  };

  // WebhookのURLは環境変数から読み込んで事前に復号する
  axios.post(SLACK_WEBHOOK_URL, data)
    .then((result) => {
      console.log(result.data);
    })
    .catch((err) => {
      console.log(err);
    });
}

成果物

Slack上のフォームを通してK/Pを記録することができるようになりました。
メッセージ右上の「その他」からアクションを選択するとフォームが表示されます。
sl.png

「登録する」を実行すると、それぞれこのように投稿されました。
kp.png

長ったらしい投稿でも、ソースコード込みでも、数ポチで記録できます。
また、payload.message には投稿者のIDも含まれるため
他のメンバーの投稿をそっと取り上げることもできます。※コードには未反映

:warning: 注意書き

動くようにはなりましたが、運用の前にいくつか注意があります。

アクセス元の認証

メイン処理の前段で、Slackからの正しいアクセスであることを確認する必要があります。
参考記事 の「リクエスト情報の認証」の箇所を参考に実装を加えます。

各種設定の暗号化

CloudFunctionsの環境変数にアクセストークンやシークレットを埋めますが
事前に KMS で暗号化を行い、使用前に復号して利用するようにします。

:checkered_flag: むすび

メッセージをKeep/Problemとして記録するアクションを作成しました。

今回は他のチャンネルに投稿しただけですので
「コピペで良いのでは?」とか「ピン留めしたら?」という声が聞こえてきそうですが
スプレッドシートやDBにデータを保存すればもっと活用の幅は広がりそうです。

(私は付箋が好きです。備忘しても声を出して書き出すべきだと思います:relaxed:


明日以降もLIFULLアドベントカレンダーは続きます。引き続きお楽しみに!
https://qiita.com/advent-calendar/2019/lifull

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
What you can do with signing up
1