slackでbotがgoogleドキュメントの新規ファイルを作ってくれる仕組み（ノンプログラマー向け）

googleドキュメントの新規ファイルをいちいち作るのかったるいなー、ということありませんか？
私はあります。

というのも前職では議事録をgoogleドキュメントで残しておくようにしていたのですが。
議事録をつくるたびに

- googleドライブを開く
- 作るフォルダを探す
- ドキュメントを新規作成する
- 定型のファイル名をつける
- 定型文を冒頭に差し込む

といった手間が発生するので、ぶっちゃけまあまあ面倒です。
なのでこの辺を解消したくて、ノンプログラマーががんばって仕組みを作ってみたという話を書き残します。


# どんなものか
・slackの特定のチャンネルで
<img width="527" alt="スクリーンショット 2019-12-17 16.04.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621062/c915f77c-02b7-cb82-967e-d07033c80c29.png">


と叫ぶと

<img width="535" alt="スクリーンショット 2019-12-17 16.05.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621062/8746afee-ca7f-c65d-16ef-39d95571c23c.png">



このように議事録神が降臨し、議事録を授けてくれます。

##仕様
- slackの特定のチャンネルでのみ作動します。
- 「出でよ議事録！」または「出でよ議事録！○○○」（○○○にミーティングの名前を入れる）と入力するとbotが現れ、議事録のgoogleドキュメントを授けてくれます。
- 議事録は自動で作新規成されたものです。
- ファイルは指定したgoogle driveのフォルダに置かれます。
- 議事録のファイル名は「議事録：<当日の日付の8桁>_<MTG名（ない場合は空き）>」になります。
- ドキュメントには以下が最初から入っています。

> 宣言したMTG名
> 日にち：XXXX年XX月XX日（作成した日付）
> 出席者：

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621062/d7341937-5a38-4c20-f2b5-3fb30db39ae7.png)


# ざっくりした作り方
slackのプラットフォームにあるシステムを流用しつつ、Google Apps Script（GAS）という、googleドライブから扱えるスクリプトを利用します。

以前「slackで動くボットをつくってみたいんですけどどうやるんですか？」と、エンジニアの方に聞いてみたところ

エ「まずはボットを動かすサーバを…」
僕「（ぼくにはむずかしい）」

と即座に諦めた経緯があるのですが。
GASならどうもサーバ云々は気にせずにできそうなので、やってみた、という経緯があります。

いろいろ調べてみましたが、基本はこの記事を参考にしました。
ここでも説明はこの記事から~~パクッて~~引用して進めていきます。
https://qiita.com/pistaman/items/a542119ea28871960477

# 進め方

- GASの設定
- Slack APIの設定
- outgoing webhookの設定
- コードの入力など

## GASの設定

GASを立ち上げたうえで、ライブラリという、誰か親切な人がつくってくれた既存のプログラムみたいなもの？を使えるように設定します。

### ①Google Apps Scriptを立ち上げる

googleドライブを開き、「新規作成」＞「その他」＞「Google Apps Script」で新規スクリプトのエディタを立ち上げます。
「その他」を開いても出て来ない場合は「アプリを追加」から検索して探します。


### ②ライブラリにslackAppを追加する
エディタで「リソース」＞「ライブラリ」を開き「Add a library」に次のプロジェクトキーを入れます。
`M3W5Ut3Q39AaIwLquryEPMwV62A3znfOO`
追加されたら「バージョン」から最大の数字を選び、保存します。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621062/6bb94c08-f2c7-2071-bc1f-d109b59d8577.png)



## Slack APIの設定
次に、slackのボットの設定をします。

### ③slack apiでappを作成する

[slack api](https://api.slack.com/apps)を開き「Create New App」をクリック。
<img width="1055" alt="4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621062/cc7c43e1-2bf2-d12b-f2c7-6263b4ee0c15.png">


アプリ名を自由に決めて、動作させるワークスペースを選びます。

###④OAuth & Permissionsの設定をする
次に左側のメニュー「Features」の「OAuth & Permissions」を開き「Scopes」の「Bot Token Scopes」にある「Add an OAuth Scope」をクリック。
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621062/04e2da01-4071-ec9d-d505-3c22a667c6f9.png)

「chat:write」を選択します。


###⑤Botの設定をする
左側のメニュー「Settings」の「Basic Information」を開き、下のほうにある「Display Information」を設定します。
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621062/445bfced-65f4-489d-2b74-8412ef077c3b.png)

設定後、画面下のほうに表示される「Save Changes」をクリックして保存します。

次に「Features」の「App Home」にて「Your App’s Presence in Slack」の「App Display Name」の「edit」ボタンをクリックし、Display NameとDefault usernameを設定します。
![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621062/96ca29cf-0f37-d107-6483-64e7e38ec5ed.png)




###⑥ワークスペースにインストールする

「Features」の「OAuth & Permissions」に戻り、「Install App to Workspace」をクリックし、許可します。
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621062/cfed0283-44cd-c1a7-58ce-23a23f655d78.png)

そうすると、同じ場所に「Bot User OAuth Access Token」という文字列が表示されます。
この文字列（token）はあとで使うので、コピーしておいてください。


## outgoing webhookの設定
slackからGASに情報を送る設定をします。

###⑦slack App ディレクトリでアプリを探す
https://slack.com/intl/ja-jp/apps
にアクセスし、「Outgoing Webhook」という、slackからデータを拾ってきて送ることができるアプリを検索します。

###⑧slackにインテグレーションを追加する
「slackに追加」をクリックし、次のページで「Outgoing Webhookインテグレーションの追加」をクリック
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621062/59be8935-3f7d-e3f2-ea48-5a36365e04ef.png)



###⑧インテグレーションの設定をする
下のほうにスクロールすると「インテグレーションの設定」とあるので、ここで設定。
設定が完了すると、該当のチャンネルに「このチャンネルに次のインテグレーションを追加しました」という投稿がされます。


【チャンネル】
動作させたいチャンネルを設定します。
「全チャンネル」とすればどのチャンネルでも動作します。

【引き金となる言葉】
「この言葉が発せられたら動作する」という、トリガーキーワードを設定します。今回の場合は「出でよ議事録！」としました。
ちなみに、キーワードは投稿の冒頭でなければなりません。
なので「最近めっきり寒くなりましたねえ。ところで、出でよ議事録！」と入力しても動作しないので注意してください。

なお、「,」で区切れば複数設定できるようです。

【URL】
ここはあとで入力します。

【トークン】
ここは後で使うのでコピーしておきます。

【その他の設定】
今回は気にせずそのままでOKです。

## コードの入力など

GASのエディターでの入力・設定に戻ります。

###⑨コードを書く

詳細は後ほど説明しますが、今回は以下のようなコードを書きました。

```javascript
function doPost(e) {

  //ドキュメントのタイトル
  var triggerWord = "出でよ議事録！"; //トリガーにする言葉
  var gijirokuHeader = "議事録：" //議事録ファイル名のヘッダー

  var newFileTheme = e.parameter.text.replace(triggerWord, "");
  var todayTitle = Utilities.formatDate(new Date(), "JST", "yyyyMMdd");
  var newFileName = gijirokuHeader + todayTitle + "_" + newFileTheme;

  //ドキュメントの内容
  var todayContents = Utilities.formatDate(new Date(), "JST", "yyyy年MM月dd日");
  var contents = newFileTheme +"\n\n" +
      "日にち：" + todayContents + "\n" +
      "出席者：";

  // ドキュメント作成、contentsを書き込む
  var newFile = DocumentApp.create(newFileName);
  newFile.getBody().setText(contents);

  //作成したドキュメントURLを取得
  var newFileUrl = newFile.getUrl();

  //ドキュメントを格納するフォルダを取得
  var newFileFolderId = "★新しいファイルを置くフォルダのID"; 
  var targetFolder = DriveApp.getFolderById(newFileFolderId);

  //指定したフォルダに移動させる（そしてマイドライブから消す）
  var docFile = DriveApp.getFileById(newFile.getId());
  targetFolder.addFile(docFile);
  DriveApp.getRootFolder().removeFile(docFile);


  //slackに投稿
  var message = "容易いことだ。願いを叶えよう…！\n"; //議事録URLを出すときの文言後半

  var token = "★Bot User OAuth Access Tokenのトークン";
  var verify_token = "★Outgoing Webhookのトークン"; 

  if (verify_token != e.parameter.token) {
    throw new Error("invalid token.");
  }
  var slackApp = SlackApp.create(token); 
  if (newFileTheme == "") {
       slackApp.chatPostMessage(e.parameter.channel_id, "新しい議事録か。" + message + newFileUrl)
    }
    else {
      slackApp.chatPostMessage(e.parameter.channel_id, "「" + newFileTheme + "」の議事録か。" + message + newFileUrl)
    }  
}
```

コードが書けたらフロッピーマークで保存します。

###⑩アプリとして公開する
「公開」＞「ウェブアプリケーションとして導入」をクリック。
【Current web app URL:】
この内容はコピーしておきます。

【Project version:】
「New」を選びます。

なお、更新すると自動でバージョンの番号が振られます。
コードを更新する際は必ずProject version:を改めて「New」にします。
（そうしないと更新されない）

【Execute the app as:】
特に変えなくて大丈夫です。

【Who has access to the app:】
「Anyone, even anonymous」にします。


###⑪Outgoing webhookに紐づける
最後に、⑩でコピーした「Current web app URL:」を、Outgoing webhookの「URL」に入力し、設定を保存します。

これで動作するはずです。

###⑫動作させたいチャンネルにアプリを追加する
slackで、動作させたいチャンネルを開き、「i」マークでチャンネル詳細を開きます。
「その他」から「アプリを追加する」を選びます。
アプリ選択画面が表示されるので、④で作成したbotを追加します。
![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621062/3381ddbc-9d07-30fd-0614-885dcaee7100.png)


※以前はわざわざアプリを追加する必要はなかったのですが、slack apiに仕様変更があったようです。

###（場合によっては）ファイルを置くフォルダのリンク共有設定をオンにしておく
ドキュメントをマイドライブではないフォルダに置く場合は、改めてオンにしておかないと、うまく動かなかったような気がします。
うまくファイルが移動してくれないときは試してみてください。


#コード
わかる範囲で、自分なりの解釈を書いてみます。

###関数宣言

```javascript

function doPost(e) {
```

今回の場合は、この関数名じゃないとダメっぽい気がします。

###ドキュメントのファイルを作成する

```javascript

  //ドキュメントのタイトル
  var triggerWord = "出でよ議事録！"; //トリガーにする言葉
  var gijirokuHeader = "議事録：" //議事録ファイル名のヘッダー
  var newFileTheme = e.parameter.text.replace(triggerWord, "");
  var todayTitle = Utilities.formatDate(new Date(), "JST", "yyyyMMdd");
  var newFileName = gijirokuHeader + todayTitle + "_" + newFileTheme;

  //ドキュメントの内容
  var todayContents = Utilities.formatDate(new Date(), "JST", "yyyy年MM月dd日");
  var contents = newFileTheme +"\n\n" +
      "日にち：" + todayContents + "\n" +
      "出席者：";
```

このへんで、ドキュメントのタイトルや内容に関する設定をあらかじめしておきます。
前半がタイトルに関する設定、後半が内容に関する設定です。

```javascript
  // ドキュメント作成、contentsを書き込む
  var newFile = DocumentApp.create(newFileName);
  newFile.getBody().setText(contents);
```
いよいよファイルを作成します。
まずは、さきほど設定したファイル名でドキュメントファイルを作成し、そのファイルにさきほどの内容を書き込みます。

```javascript
  //作成したドキュメントURLを取得
  var newFileUrl = newFile.getUrl();
```
そしてここでURLを取得しておきます。

###ファイルを移動する
ただファイルをつくるだけだと、ファイルはマイドライブに作成されています。
なので、任意の場所にファイルをコピーし、マイドライブからはファイルを削除します。

まず、置きたいフォルダのIDを取得します。
フォルダを開いたとき、アドレスバーに表示される「folder/」以下の文字列がIDなので、コピペしてここで使います。

```javascript
  //ドキュメントを格納するフォルダを取得
  var newFileFolderId = "★新しいファイルを置くフォルダのID"; 
  var targetFolder = DriveApp.getFolderById(newFileFolderId);

  //指定したフォルダに移動させる（そしてマイドライブから消す）
  var docFile = DriveApp.getFileById(newFile.getId());
  targetFolder.addFile(docFile);
  DriveApp.getRootFolder().removeFile(docFile);
```

###slackに投稿する

今回は、「出でよ議事録！」というトリガーワードの後ろに議事録名を書き入れることで、ファイル名や内容に反映され、URLが表示されるようにしました。

せっかくなので、slackに投稿される際に、議事録神にその内容を復唱させると、議事録神の実在が感じられてありがたみが増しそうな気がします。

しかし、議事録名を入れないこともあるでしょうから、議事録名のあるバージョンとないバージョンの分岐をさせる必要がありました。


```javascript
  //slackに投稿
  var message = "容易いことだ。願いを叶えよう…！\n"; //議事録URLを出すときの文言後半

  var token = "★Bot User OAuth Access Tokenのトークン";
  var verify_token = "★Outgoing Webhookのトークン"; 

  if (verify_token != e.parameter.token) {
    throw new Error("invalid token.");
  }
  var slackApp = SlackApp.create(token); 

  if (newFileTheme == "") {
       slackApp.chatPostMessage(e.parameter.channel_id, "新しい議事録か。" + message + newFileUrl)
    }
    else {
      slackApp.chatPostMessage(e.parameter.channel_id, "「" + newFileTheme + "」の議事録か。" + message + newFileUrl)
    }  
}
```
なお、ここで⑧でコピーしたoutgoing webhookのトークンを使っています。

（中ほどのエラーコードのところの意味は参考文献からのコピペで、正直よくわかっていません。）

以上です。
何かの参考になれば幸いです。