Google ChatでBotに送った添付ファイルをDriveAppを使って保存するよ

こんにちは。:relaxed:だよ。
今日もChatの続きをやっていくよ。


###前回までの振り返り
【問合せBotを作成するまでの道】
1.BOTにDMを送ったら、チャットルームへの転送がされる。　*→完了*
2.チャットルーム内でのユーザーごとのthread名を保持し、同じユーザーからのDMは同じスレッドに書き込まれる。 
3.スレッドに:relaxed:から書き込みをしたら、対象のユーザーにDMが送られる。
4.（余力があれば）よくある質問集みたいな一覧を作ってBotが自動返答してくれる。




:relaxed: は説明下手だから画像キャプチャばかり送ってしまう悪癖があるんだけれど、
今の応答だと画像が転送されないことがわかったよ・・
こーまーるーよー・・・・

そこで、今回は、Botに送った画像をGoogleDriveに格納して、
転送されるようにするよ！


###画像つきのメッセージが送られる時のEventの内容を確認しよう。
まずはBotに対して画像を送ってみるよ。
<img width="500" alt="スクリーンショット 2020-08-08 19.43.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482103/13b86f95-be8b-b83d-82a6-9c5e06da0562.png">

onMessage()関数内で console.log(event)をした時の結果・・

<img width="1146" alt="スクリーンショット 2020-08-08 19.47.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482103/8f5d83b7-44ed-1905-53d8-5fdb5d80822d.png">



お・・:relaxed:
<img width="1173" alt="スクリーンショット 2020-08-08 19.47.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482103/75f99ea0-1190-1011-3289-2057dc9e3960.png">



attachmentという項目がMessageに載っているね！
そのダウンロードURIにアクセスしてみると、こんがらがっちゃって困っている男の人が見えたよ。
:relaxed:もよくなるから親近感！

（[いらすとや](https://www.irasutoya.com)さんの可愛い画像をお借りしたよ。）



URIわかったのでこんな感じのButtonをMessageに含めて、クリックで表示できるようにしたんだけれど、問題発生！

<img width="1014" alt="スクリーンショット 2020-08-10 11.13.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482103/27c710ec-0408-c7db-03de-fbec20c00d57.png">

送った本人は、ボタンクリックで画像の表示ができるんだけれど、他の人に開いてもらうと、403エラーが出ちゃったんだ。
URI見て分かる通り謎APIを叩いているっぽいんだけれど、このAPIはもとより、attachmentの情報が公式に全くなくて、公式命！公式大好きな:relaxed:は絶望したよね・・


でも悔しいので、調べに調べた結果、ここに辿りついた！！
>[IssueTracker:get attachment with the api](https://issuetracker.google.com/issues/77501248)

すごくタイムリーに問題が解決されていて、サンプルまで載っているよ！
```https://chat.googleapis.com/v1/media/" + resourceName + "?alt=media```
のAPIを使うと、添付をバイナリデータとして取得できるみたい。

詳細は上記リンク先を見てもらいたいんだけれど、
画像付きのメッセージを送る→Google Driveに保管→そのLINKをメッセージにつけて転送というフローにすることで画像問題を解決するよ。
*2020.09.13現在、公式にも使い方が記載されていることを確認。記事の最後にURL付けています。

###DriveAppを使って、GoogleDriveにファイルを保存するよ

[IssueTrackerのサンプル](https://doc-3vn0-0u4g-issuetracker.googleusercontent.com/attachments/d41ephgqq0k9jhchqg4eu644vteg9ois/g7hvokcp5vaq5alcd9ubtggptpomiue4/1596861000000/350158/107669769947508456575/77501248::30444833::350158?dat=AFNnbnntlMs7plsTCrDFqvzSYYwoT20GEai1coTG3xbMfbNlMBm4sTXW4ZfapArXLmKD4Gaqmvfd3-P6LNVtHLtdo25xox9NJrPpOuHDamk_nnKmE3q6XHfh8dPFR6Ku4Fa4zs_rRs84oJ5j677DNySsnVy16lxjW2odlAfG83hmBddxeh2m-h3KdFX6zsy7yJ60KVgUxU1h8DhEeq5STa-gYe4gFs5fK7XG7IUtWGNkZRwBtAqpsgDav0NStYs-Lo94WRebvMT1RZGQDJ0fw5zNwHjp_hOu6Jpqws-qLnquibgywLHE57aHNHxKU3WpSTvBVa0EA9HF2sSYlWu8RIRlPELAJoiq6xxstJlasf0CO6is6YZCg9dr2AitvKmB9Oy4cmjsGtbDGSPv66huK8V2hZ3mYzvfR3L0Lmjan96XFRFF8XeJXgyztsZNZyF7UR8owt2xmUbZh6P3eWErGhMo79eTb_mDXcwwXSqMep8Reyz8jss--t5IKrmDtLB_jtzT9_rjUvRReBrAHoOP-4Bfe3LhKGq6iX5hgqF-4bNVjKSfeu9VwaXIatRqA3FO_hCLwn_4uzRed9ZkUzb39a7yEaZU8Wt055wPrBhH2X3rvLWwoLmI33hoemyJMkN9btkAqLH2-cnqXmquRqcxxEt1gp55Z8YfTBtaca9OHSy3HGSbiOH799vEP3sR6g51diYlKjJ7YcOW4tDuXr6imt2UnyE3PwXviW6ne1PXqWLzmRgC1I4Y2Yo&u=0&s=1&download=false&nonce=lrpqa8s41ti10&user=107669769947508456575&hash=covf04volelp5abhllfp534iegji1fmp)のgetByteStream()をベースに、GoogleDrive上に保存する関数を作ったよ。

```
/**
 * Upload Attachment To GoogleDrive
 *
 * @param  {Object} attachement
 * @param  {Object} folderId
 * @param  {Object} fileName 
 * @return {string} GoogleDriveURL
 */
 
function uploadAttachmentToDrive(attachment, folderId, fileName){
  var resourceName = attachment[0].attachmentDataRef.resourceName;
  var blob     = "";
  var url      = "https://chat.googleapis.com/v1/media/" + resourceName + "?alt=media"
  var service  = getOAuth2Service(); 

　var response = UrlFetchApp.fetch(url, {
    headers: {
      'Authorization': 'Bearer ' + service.getAccessToken(),
    },
    'muteHttpExceptions': true,
  });

  if (response.getResponseCode() != 200) {
    return "Failed to get file content with error code: " + response.getResponseCode();
  }

  blob = response.getBlob();
  var folder = DriveApp.getFolderById(folderId);
  var uploadFile = folder.createFile(blob);
  
  uploadFile.setName(fileName);
  
  return uploadFile.getUrl();
}



// 以下、OAuth2の取得の仕方は参考まで。いろいろなやり方があるからね。

/**
 * Creates OAuth2 Service to use chat api
 *
 * @return {Object} contains OAuth2 token
 */

function getOAuth2Service() {
  
  var jsonKey                   = JSON.parse(PropertiesService.getScriptProperties().getProperty("jsonKey"));    
  var serviceAccountPriveKey    = jsonKey.private_key;
  var serviceAccountClientEmail = jsonKey.client_email; 
  var scope = 'https://www.googleapis.com/auth/chat.bot';
  var service = OAuth2.createService('chat')
      .setTokenUrl('https://accounts.google.com/o/oauth2/token')
      .setPrivateKey(serviceAccountPriveKey)
      .setClientId(serviceAccountClientEmail)
      .setPropertyStore(PropertiesService.getUserProperties())
      .setScope(scope);
  
  if (!service.hasAccess()) {
    console.log('Authentication error: %s', service.getLastError());
    return;
  }
  
  return service;
}
```


Google Driveの操作が必要になるので、このAPIも有効にしてあげようね。
<img width="1310" alt="スクリーンショット 2020-08-11 10.27.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482103/40117264-48fb-8eb2-ac03-26761ecaf761.png">

引数のattachment=event.message.attachmentで、存在するときだけこの関数を呼び出すよ。
戻り値のurlはwidgetsにボタン形式で持たせたよ。

```
"widgets": [
  { "buttons": [
    { "textButton": 
      {  "text": "添付を見る",
         "onClick": { "openLink": { "url": url}}
      }
    }
  }
]
```


で、いきなりこのサンプルにDriveAppが出てきてびっくりしたよね！
これについてちょっと説明するね。

>[GoogleAppsScript : DriveApp](https://developers.google.com/apps-script/reference/drive?hl=nb#driveapp)

DriveAppsはGoogleAppsScriptに用意されているGoogleDriveを簡単に扱うためのクラスだよ。
いろいろなメソッドがあるけれど、今回使ったのはこの四種類だよ。


**createFile(blob)**
Googleさんが作ってくれたサンプルではバイナリファイルを取ってこられるようになっていたね。
それを引数に与えると、このメソッドでファイルを作成することができるよ。

**getFolderById(folederId)**
特定の場所に添付ファイルを置きたかったので、このメソッドを使ってフィルダーの場所を指定したよ。
引数のfolderIdには、GoogleDriveでそのフォルダーを開いた時のおしりがつくよ。画像だとオレンジの部分だよ。
<img width="907" alt="スクリーンショット 2020-08-11 11.48.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482103/dcc5b810-68f8-8348-9307-f9fd0a2cfe5c.png">

**setName(fileName)**
ドライブにあげたファイルに管理がしやすいように名前をつけるのに使ったよ。

**getUrl()**
onClickでこのGoogleDriveの画像を開けるようにしたかったのでURLも取得するようにしたよ。





###実際の動きを見てみよう
実行するとこんな感じ。
【:relaxed: → systemBot】
<img width="541" alt="スクリーンショット 2020-08-11 11.26.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482103/c6bd1a44-7eff-9121-ba16-37b64017b08f.png">

【systemBot →　特定のワークスペース】

<img width="419" alt="スクリーンショット 2020-08-11 12.13.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482103/679e8e46-0b6d-76e9-ac80-d72f0bcd4560.png">


添付を見るをクリックすると画像が現れる&指定したフォルダに、画像ができているよ。
<img width="634" alt="スクリーンショット 2020-08-11 11.29.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482103/4c032ef6-5990-bce4-6931-bd86371a2613.png">



わーい、これで画像問題は解決だよーー！
ちなみに画像以外にも、EXCELなどのドキュメントも問題なくアップロードできることを確認したよ！

今日はここまで！
次回はここまでできた応答システムのコードを公開したいなぁ・・


##参考にさせていただいたもの
ふふふ、公式:relaxed:
[公式:GoogleAppsScript](https://developers.google.com/apps-script?hl=nb)

##2020.09.13現在
今日確認したら、attachmentsについてのAPIが公式サイトに追記されていたね。
[公式：ChatAPI Download](https://developers.google.com/hangouts/chat/reference/rest/v1/media/download)