LoginSignup
5
7

More than 3 years have passed since last update.

【GAS × LINE WORKS】Bot で受け取ったファイルを Google Drive に保存する

Last updated at Posted at 2020-12-17

Google Apps Script Advent Calendar 2020 の 18日目!
どうぞよろしくお願いします。

はじめに

リモートワークでチャットの利用が増えてきた昨今。
仕事も効率よく自動化するために Bot の利用も増えてきました。

報告用 Bot とか経費精算 Bot とかで、メンバーがファイルを送信したら Google Drive に保存して管理者に通知してくれたら管理しやすいですよね。

ってなわけで作ってみました!(*'▽')

実際の画面

ユーザ画面
1608014275.png

管理者画面
1608014243.png

Google Drive
1608014346.png

GoogleAppsScript で LINE WORKS BOT を作る

以下の記事を参考に Bot を作成してあります。
【GAS × LINE WORKS】BOT で PDF ファイルを送受信!

この記事で作った Bot にコードを書き加えていきます♪

コードを書き加える

ファイルデータを受信するプログラムは実装されているので、追加で実装する機能は以下の2つです。

  1. 受信したファイルをダウンロードする
  2. ダウンロードしたファイルを Google Drive に保存する

ではでは、ひとつずつ実装していきまっす!ヾ(´∀`)ノ

1. 受信したファイルをダウンロードする

Bot がファイルを受信すると resourceId というものを取得します。
実際のファイルデータを手に入れるには、この resourceId を使って API を Request します。
使用する API はトーク Bot のコンテンツダウンロード API です。

では、この API を呼び出す関数を作っていきます。

fileDownload
function fileDownload(resourceId) {
  const headers = {
    'consumerKey': CONSTS.consumerKey,
    'Authorization': 'Bearer ' + LINEWORKS.getToken(CONSTS),
    'x-works-apiid': CONSTS.apiId,
    'x-works-resource-id': resourceId
  }  
  const options = {
    'method': 'get',
    'headers': headers
  }
  const uri = 'http://storage.worksmobile.com/openapi/message/download.api'
  return UrlFetchApp.fetch(uri, options)
}

headers には認証情報が入ります。
CONSTS への認証情報のセットについてはコチラをご参考ください。
ダウンロードするファイルの resourceIdheaders に記載します。

ダウンロードしたファイルは HTTPResponse オブジェクトで取得されます。
公式 Reference - Class HTTPResponse

あっという間ですね!( ゚Д゚)

では、HTTPResponse オブジェクトを Google Drive に保存していきましょう。

2. ダウンロードしたファイルを Google Drive に保存する

HTTPResponse オブジェクトの操作は簡単。
.getBlob() で作成した Blob オブジェクトを DriveApp で書き込むだけ・・・

と、思いきや意外な落とし穴がありました。
保存したファイルの名前がなぜかすべて download.api になってしまうのです!
呪いか?( ゚Д゚)

1608015703.png

何故だかはわかりませんが、ファイル名が正常に取れない模様。
仕方がないので HTTPResponse のヘッダー情報からファイル名を取得することにしました。

createFile
function createFile(response){
  const resHeaders = response.getAllHeaders()
  const refererUri = resHeaders['x-hlink-org-referer'].split('/')
  const filename = refererUri[refererUri.length - 2]
  const resBlob = response.getBlob()
  resBlob.setName(filename)
  const drive = DriveApp.getFolderById(folderId)
  drive.createFile(resBlob)
}

filename が一発で取れれば良かったのですが、無理なので split() しました。
ちなみにヘッダー情報の中身はこんな構成でした。ご参考までに。

{x-resource-type=resource, Date=Tue, 15 Dec 2020 05:52:01 GMT, Last-Modified=Tue, 15 Dec 2020 05:25:28 GMT, x-hlink-org-referer=https://jp1-storage.worksmobile.com/k/oneapp/r/jp1.xxxxxxxx/xxxxxxxx/v2-xxxxxxxx-443220668.190531528/TEST_PDF.pdf/, ETag=1608009928, Server=FileCloud, Connection=keep-alive, Content-Disposition=attachment; filename="TEST_PDF.pdf"; charset=utf-8; filename*=UTF-8''TEST_PDF.pdf, Content-Length=28315, Content-Type=application/pdf}

無事に実行され、ファイルが Google Drive に保存されましたとさー(*‘∀‘)

1608014346.png

おしまい♪

全体のコード

全体のコードはここに折りたたんで貼り付けておきます。
main.gs
// LINE WORKS API 認証情報
const CONSTS = {
    'apiId': 'API ID',
    'consumerKey': 'Server API Consumer Key',
    'serverId': 'Server List(ID登録タイプ) の ID',
    'privateKey': 'Server List(ID登録タイプ) の認証キー',
    'botNo': 'botNo',
    'botMaster': 'BOT 管理者のアカウント ID'
}
// ファイルを保存するフォルダの ID
const folderId = 'xxxxxxxxxxxxxxxxxxxxxxxxx'

// BOT 
function doPost(e) {
  if(e === null || e.postData === null || e.postData.contents === null) return
  const requestJSON = e.postData.contents
  const requestObj = JSON.parse(requestJSON)
  const user = requestObj.source.accountId
  switch(requestObj.content.type){
    case 'file':
      const resourceId = requestObj.content.resourceId
      LINEWORKS.sendMsg(CONSTS, CONSTS.botMaster, `${user}さんからファイルが届きました。`)
      LINEWORKS.sendFile(CONSTS, CONSTS.botMaster, resourceId)
      LINEWORKS.sendMsg(CONSTS, user, '管理者に File を転送しました。')
      const file = fileDownload(resourceId)
      createFile(file)
      LINEWORKS.sendMsg(CONSTS, CONSTS.botMaster, 'Google Drive に File を保存しました。')
      break
    default:
      LINEWORKS.sendMsg(CONSTS, user, '管理者に File を送信するにはファイルをトークに添付してください。')
  }
}
/**
 * コンテンツダウンロード API を使用してファイルを取得する
 * @param {string} resourceId LINE WORKS からダウンロードするファイルの resourceId
 * @return {HTTPResponse object} ダウンロードしたファイルデータ
 */
function fileDownload(resourceId) {
  const headers = {
    'consumerKey': CONSTS.consumerKey,
    'Authorization': 'Bearer ' + LINEWORKS.getToken(CONSTS),
    'x-works-apiid': CONSTS.apiId,
    'x-works-resource-id': resourceId
  }  
  const options = {
    'method': 'get',
    'headers': headers
  }
  const uri = 'http://storage.worksmobile.com/openapi/message/download.api'
  return UrlFetchApp.fetch(uri, options)
}

/**
 * ダウンロードしたファイルデータを folderId のフォルダに保存する
 * @param {HTTPResponse object} ダウンロードしたファイルデータ
 */
function createFile(response){
  const resHeaders = response.getAllHeaders()
  const refererUri = resHeaders['x-hlink-org-referer'].split('/')
  const filename = refererUri[refererUri.length - 2]
  const resBlob = response.getBlob()
  resBlob.setName(filename)
  const drive = DriveApp.getFolderById(folderId)
  drive.createFile(resBlob)
}

おわりに

ここまでお付き合いいただきありがとうございました。

前回の宣言通り、Google Drive に保存してやったぜ!(*‘∀‘)メズラシイ
UrlFetchApp.fetch() からのファイル保存は意外と簡単にできるんですね。
やっぱり GoogleAppsScript は扱いやすいなー。
連携もしやすいし、LINE WORKS API との相性いいかも?

あと、Advent Calender の記事を色々と見ていたら @taketakekaho さんの記事で Google Drive の OCR 機能が無料で使えることを知りました( ゚Д゚)
GASとGoogleDriveのOCR機能で文字起こしボットを作ってみた時のTips

次はさらに OCR 機能追加してみるのも楽しいかも!

ではまた!(^^)/

参考にさせていただきましたm(_ _)m

LINEWORKS Developers
公式 Reference - Class HTTPResponse

5
7
1

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
  3. You can use dark theme
What you can do with signing up
5
7