チームへの問い合わせをGoogle Formに集約することで保守の仕事を少し楽にした話

# はじめに
私の所属するチームでは、他チーム/他部署からの問い合わせを専用のチャンネルを設け、Slackで受けています。
ここには顧客トラブル発生時のサポート依頼から機能の仕様確認まで、様々な文章が投稿されています。

チャンネルを作成し、1年が経過した頃…
必要な情報の揃っていない依頼が多く投稿されていることに、モヤモヤがたまっていたある日、チーム内で
「Google Form作ってそこからSlackに投稿できたら良さそう」
という話になり、
「それだ！！！」
と思ったので即行動に移すことにしました。
難しくないけど、あったら便利だけど、でもやれていない、そんな仕事を率先して行うことを得意としている私にはピッタリの内容でした。

この記事では、主にGoogle Formに投稿された内容をSlackに自動投稿する方法について記載します。

# 困っていたこと
* Slackの投稿文書に統一性がない。
* トラブル調査に必要な情報が書かれていない。
* いつまでに解決すれば良いか分からない。
* Slack内にしか情報が残らない。

# 解決のために利用したツール
* Google Form
* Google Apps Script(GAS)
* Slack API(Incoming Webhooks)

# Google Formの利用で意識したこと
Google Formは、私のチームに問い合わせをしたい色々な所属の人が利用するので、以下のことに配慮しました。

* 問い合わせの種別で設問分け
* 可能な限り回答は選択式の内容に
* 自由記述欄のタイトルには例や説明を記載

また、せっかくGoogle Formを利用しても、必要な情報を集められなければ意味がないので、

* ほぼすべての項目を入力/選択必須項目

としました。

# Google Formの投稿をSlackに投稿するには？
無知の私は「Google Form Slack」などといったワードで検索をしたところ、Google Apps Script(以下GAS)を利用する、という検索結果が得られたので、これを採用しました。

[GAS ビギナーが GAS を使いこなすために知るべきこと 10 選](https://qiita.com/tanabee/items/2c51681396fe12b6a0e4)

また、Slackへの自動投稿はIncoming Webhooksでやれる、ということも分かりました。

[Slack Botの種類と大まかな作り方](https://qiita.com/namutaka/items/233a83100c94af033575)

つまり、Google Formへの投稿内容をGASを利用してJSON形式にして、そのJSONをIncoming Webhooksを利用してSlackに投稿すれば良い。参考にできそうな記事がたくさん出てくるので、触ったことのない私でもできそう、と思えました。

# GASを使ってみる
Google Formの編集画面の右上の三点ボタンから「スクリプト エディタ」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167538/2d3e702f-a9ff-f834-067c-b105b1416b69.png)
コードを書く場所が出現します。初期表示は以下の画像の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167538/d55afea3-82c5-309d-6710-6de649904775.png)
ここに、今回やりたいこと
「Google Formへの投稿内容をGASを利用してJSON形式にして」
「そのJSONをIncoming Webhooksを利用してSlackに投稿」
の2つの内容を書いていきます。

**Google Formの投稿内容を配列に詰める**

```
  // すべての質問と回答を取得する
  let itemResponses = e.response.getItemResponses();

  // 個々の質問と回答を格納するための空配列を宣言する
  let questionAndAnswers = [];

  // for文で変数itemResponsesから個々の質問と回答を取得する
  for(let i = 0; i < itemResponses.length; i++) {
    // 質問のタイトルを取得する
    let questionTitle = itemResponses[i].getItem().getTitle();

    // 回答を取得する
    let answer = itemResponses[i].getResponse();
    
    // 未回答の質問は表示しない
    if(answer) {
      questionAndAnswers.push("*≪" + questionTitle + "≫*\n" + answer + "\n");
    }
  }
```

今回、投稿内容と一緒に、投稿を送信した人のメールアドレスからSlackアカウントを取得し、Slackの投稿文書に誰から送信されたものかを分かるようにしたかったので、以下のように取得しました。(Google Formではメールアドレスを収集するをONにしておきます)

**投稿を送信した人の情報を取得**

```
  // 回答者のemail取得
  let email = e.response.getRespondentEmail();

  let splitEmail = email.split("@");
  var slackAccount = "<@" + splitEmail[0] + ">";
```

最初の配列と合わせて1つの関数にしました。投稿されたときに呼び出される関数ということで、名前はonFormSubmitです。

```
function onFormSubmit(e){
  // 回答者のemail取得
  let email = e.response.getRespondentEmail();

  let splitEmail = email.split("@");
  var slackAccount = "<@" + splitEmail[0] + ">";

  // すべての質問と回答を取得する
  let itemResponses = e.response.getItemResponses();

  // 個々の質問と回答を格納するための空配列を宣言する
  let questionAndAnswers = [];

  // for文で変数itemResponsesから個々の質問と回答を取得する
  for(let i = 0; i < itemResponses.length; i++) {
    // 質問のタイトルを取得する
    let questionTitle = itemResponses[i].getItem().getTitle();

    // 回答を取得する
    let answer = itemResponses[i].getResponse();
    
    // 未回答の質問は表示しない
    if(answer) {
      questionAndAnswers.push("*≪" + questionTitle + "≫*\n" + answer + "\n");
    }
  }

  let preTex = "<!here> " + slackAccount + " から投稿がありました。\n";
  let body = questionAndAnswers.join("\n");

  sendToSlack(preTex, body);
}
```

onFormSubmitの最後にsendToSlackとありますが、この名前でSlack送信用の中身を書きました。

**配列をJSON形式にしてSlackに送信する**

``` 
function sendToSlack(preTex, body) {
  var url = "後述のWebhook URL";

  // onFormSubmitで作成した配列をJSONにする
  let data = {
    'attachments': [
      {
        pretext: preTex,
        text: body,
        color: "good"
      }
    ]
  }

  // Incoming WebhooksはPOSTでSlackに投稿ができる
  let options = {
    "method" : "post",
    "contentType": "application/json",
    "payload" : JSON.stringify(data)
  };

   UrlFetchApp.fetch(url, options);
}
```

これでスクリプトの記載は完了です。
onFormSubmitをフォーム投稿時に実行してほしいので、トリガーを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167538/cbb9a4c9-6ffe-94fe-59ac-6bb49075483d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167538/a2014bab-f5f6-b07e-bfc0-4bebbbca9717.png)
最後に(もちろん先に準備をしてもOK)、Incoming Webhooksが利用できるようにSlackにBotを作成します。

# Slack APIを使ってみる

[Slack API]("https://api.slack.com/")

Slackにログインした状態で上記ページにアクセスし、Appの作成を行います。
Appに対して機能を追加します。

今回のメイン、Incoming WebhooksをONに。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167538/6b5dd613-f081-b728-02ad-b3b3c0b4bdcd.png)
Incoming Webhooksの画面下部に任意のチャンネルのWebhook URLを取得できる場所があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167538/48732ff8-80c2-3e27-843b-23b0d57eef93.png)
これでSlack側の準備は完了です。

最後に、GASに戻り、Slackで取得したWebhook URLをsendToSlackのurlに埋め込みます。

```
var url = "https://hooks.slack.com/services/~~~~~~~~~";
```

# 実際にSlackに投稿されている内容

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167538/54606d62-3eb0-0b01-fd12-7b293622ddce.png)

# やってみた感想

記事冒頭にも記載した通り、とにかく情報がたくさん転がっているので、やってみようと思ってから実際に投稿を始めるまでにほぼ時間はかかりませんでした。
私がここで紹介しているスクリプトも他への流用が容易なので、すでに他の開発チームでも真似してくれています。
やったことは全然難しくないのに、困っていたことを解決する手立てになったので、やってよかったです。
Google Formは回答結果をグラフで表示できるので、選択式にできる設問は自由記述でなく選択式を選ぶと、後の分析に活用できると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167538/ec86b764-2b07-43c0-1533-a26afc704382.png)

また、Slackチャンネルは自由投稿禁止とし、Google Formからの投稿のみに制限したため、全ての文書が統一されたフォーマットになりました。
「フォーマットはこれを利用してください」とするよりも、はるかにお互いにメリットがあると感じています。

# おわりに

今回紹介した内容は開発者でなくても、簡単に実現できる内容です。
Google/Slackを利用しているのであれば、すぐに真似できます。
使ったことのある人にとっては何の新しさもない記事ですが、これを受けて自分のもってるモヤモヤを便利ツールで解決してみようかなと思える方が一人でも現れたら幸いです。

# 参考にしたサイト
[Slack ボットの作成手順]("https://qiita.com/odm_knpr0122/items/04c342ec8d9fe85e0fe9")
[【保存版！】Googleフォームの質問と回答をGASで自在に取り出す方法まとめ]("https://www.yukibnb.com/entry/form_responses")
[【コピペでOK！】GASでGoogleフォームの回答をSlackに自動通知する方法]("https://www.yukibnb.com/entry/gas_form_auto_slack_to_channel")