優柔不断なのでお昼ご飯を決めてくれるbotをGASで作る

# はじめに

:::note info
[TLB Enjoy Developers Advent Calendar 2022](https://qiita.com/advent-calendar/2022/tlb-enjoy) の14日目の記事です。
:::

**ある日のお昼**  
職場の人「今日の昼ごはん何食べます？」  
自分「うーん、、、 **なんでもいい** です」  

**次の日のお昼**  
職場の人「今日の昼ごはん何食べます？」  
自分「うーん、、、 **なんでもいい** です」  

こんな不毛な会話をほぼ毎日している気がします。  

優柔不断な自分はお昼ご飯を決めることができません。  
お昼ご飯すら決めることのできない人間にプログラムの変数名を決めることはできませんし、実装期日を決めることもできません。  
そしてSlackの返信は後回しにして溜まり続け、スケジュール管理もできないんです。きっとそう。  

そういえば人間には1日に判断できる回数が決められているみたいな話をどこかで聞きました。  
決断の度に脳みそに負担がかかって決断力の精度が落ちるみたいな話だった気がします。  
そんな貴重な1回の決断をお昼ごはんの決定に使って良いのか？  

ちょっと勿体無い気がするので、お昼ご飯の決定はbotに決めてもらいましょう。  

**botで決めれば公平だし、きっと誰も文句を言いません。**  

# 結果的にできるもの

Googleスプレッドシートに入力された**お昼ご飯情報**の中からランダムで1つお昼ご飯を抽出して平日の12時にslackに投稿します。  

Slackの通知の例

![スクリーンショット 2022-12-14 1.19.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506401/665ab7bc-5874-d8d8-74b1-e9932aebe4eb.png)

# 手順

## スプレッドシートの準備

複数人で入力することを前提にして「名前」「お昼ご飯」「お店のURL」「コメント」の項目を設けました。  
最低限「お昼ご飯」の項目だけあれば成立しますが、そっけないので項目を増やしました。  

![スクリーンショット 2022-12-14 1.15.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506401/bbc25c6e-676a-aeb9-53d5-ebbb9f755094.png)

## スプレッドシートとSlackの連携

GoogleAppScriptとSlackの連携は[IncomingWebhook](https://slack.com/intl/ja-jp/help/articles/115005265063-Slack-%E3%81%A7%E3%81%AE-Incoming-Webhook-%E3%81%AE%E5%88%A9%E7%94%A8)を利用します。  

まずは通知を送りたいslackのチャンネルにIncomingWebhookを追加します。  
今回は例としてgas-slack-testというチャンネルに追加してみます。  
インテグレーションのAppから「アプリを追加する」を選択。  
![](https://storage.googleapis.com/zenn-user-upload/af2f25381e6d-20220717.png)

検索窓に「Incoming Webhook」を入力し、Incoming Webhookをインストール。
![](https://storage.googleapis.com/zenn-user-upload/dccc9f2f4dd2-20220717.png)
![](https://storage.googleapis.com/zenn-user-upload/1d0ef365ec26-20220717.png)

「Slackに追加」を選択
![](https://storage.googleapis.com/zenn-user-upload/ac471a6c76e6-20220717.png)

チャンネルを選択のセレクトボックスで追加するチャンネル(今回はgas-slack-test)を選択して「Incoming Webhookインテグレーションの追加」を選択。
![](https://storage.googleapis.com/zenn-user-upload/f97867f4bfdc-20220717.png)

WebhookURLは後で使用するのでコピーしておきます
![](https://storage.googleapis.com/zenn-user-upload/b8dbf66253c3-20220717.png)

## AppScriptを記述する
スプレッドシートのツールバーから `拡張機能 -> Apps Script` を選択
![スクリーンショット 2022-12-14 2.34.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506401/338f316b-c3ec-7ac6-9f98-d5c97e9d87f7.png)

`コード.gs` が表示されるのでここにスクリプトを書いていきます。
![スクリーンショット 2022-12-14 2.35.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506401/35d7d627-e68a-9acb-c20e-fa7c87251819.png)

以下GoogleAppsScript全文

```js
const POST_URL = "ここにIncomingWebhookで生成したURLを貼り付け"

function myFunction() {
  // ①シート情報取得
  const sheetData = getSheetData()

  // ②お昼ご飯情報取得
  const lunchData = getLunchData(sheetData)

  // ③slackに投稿するメッセージを生成
  const lunchMessage = generateLunchMessage(lunchData)

  // ④slackへの通知
  notificationToSlack(lunchMessage)
}
  
const getSheetData = () => {
  const book = SpreadsheetApp.getActiveSpreadsheet()
  const sheet = book.getSheetByName("お昼ご飯記入シート")
  const sheetDate = sheet.getDataRange().getValues()

  return sheetDate
}

const getLunchData = (sheetData) => {
    const header = sheetData[0]
    // お昼ご飯未記入のデータを除外
    const filterSheetData = sheetData.filter((lunchData)=> lunchData[header.indexOf('お昼ご飯')] !== '')
    const num = Math.floor(Math.random()*(filterSheetData.length-1))+1;

    return filterSheetData[num]
}

const generateLunchMessage = (lunchData) => {
  // お昼ご飯情報が取得できていない場合は早期リターン
  if(!lunchData){
    return  '*お昼ご飯情報が取得できなかったので今日はお昼抜きです。*'
  }

  const message = []
  const name = lunchData[0]
  const lunch = lunchData[1]
  const url = lunchData[2]
  const comment = lunchData[3]

  message.push(`:fork_and_knife::clock12:今日のお昼ご飯は *${lunch}* です！:clock12::fork_and_knife:`)
  message.push(` *${name ? name : "名無し"}* が選びました！`)
  message.push(`お店のURLは ${url ? url : "*ない*"} です！`)
  message.push(`コメント:point_down: \n ${comment ? comment : "*コメントはありません*"}`)

  return message.join('\n')
}

const notificationToSlack = (message) => {
  const jsonData = { "text": message }
  const payload = JSON.stringify(jsonData)
  const options =
  {
    "method" : "post",
    "contentType" : "application/json",
    "payload" : payload
  }
  UrlFetchApp.fetch(POST_URL, options)
}
```

## コードの簡単な説明

myFunction関数内部の処理を大きく4つに分けました。  

### ①シート情報取得
シートの情報を取得しています。

### ②お昼ご飯情報取得
今回のメインの部分です。  
シートの情報から「お昼ご飯」の項目が未入力の情報を除外しています。  
また、ランダム関数を用いてランダムにお昼ご飯情報を取得しています。  

ここではシートから「お昼ご飯」情報を取得するだけの関数なので、仮にシートに何も記入されていなくても早期リターンせずにundefinedを返します。  

### ③slackに投稿するメッセージを生成
②で取得した情報をもとにSlackに送るメッセージを作成します。  
シートに何も記入されていない場合、 **もちろんお昼ご飯は抜き** です。
「お昼ご飯情報が取得できなかったので今日はお昼抜きです。」とSlackに通知します。  

あとは「名前」が未入力の場合は「名無し」に変換したり、Slackに送るためのメッセージをよしなに生成しています。  
ここの記述を変えることでもっとシンプルに出力することもできれば、より凝ったメッセージにすることもできます。  

### ④slackへの通知
SlackでPOSTする処理です。

## 実行してみる
**▶︎実行** を押して実行すればSlackのチャンネルに通知が届きます。  

## 毎日12時に実行する設定

あとは定期的に実行させればbotの完成です。  

AppsScriptでトリガーを選択し、画像のように定期的に実行させる設定を行えば完了です。
![スクリーンショット 2022-12-14 2.41.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506401/1673ac94-724b-53af-28bb-74c2946de080.png)


# おわりに
お昼ご飯botにお昼ご飯を決めてもらえるようになりました。  
これでお昼ご飯を決めるのに使っていた時間を変数名の命名に当てることができますね。  

どうしても食べたいものがある時はスプレッドシートの項目をたくさん埋めて確率を上げましょう  

 **botで決めれば公平だし、きっと誰も文句を言いません。**
![スクリーンショット 2022-12-14 3.08.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506401/b296f937-c01b-e4cc-acf6-b65ef239c624.png)

明日は @mohaya-hone さんの記事です！
お楽しみに！！




# 参考記事
https://zenn.dev/offers/articles/20220630-google-app-script-slack  

https://zenn.dev/ymmt1089/articles/20220717_gas_slack