【Google Apps Script】LINE WORKS からの通知を Slack で受け取れるように

できなかった話です＿|￣|○

```html
（2021/2/4 追記）
何故か後述のエラーが解消されていました。
アップデートでもあったのかな？
後日、完成記事を書きます。m(_　_)m
```

理由は定かではないですが、おそらく Google Apps Script のサーバがアメリカにあることが原因（何を当たり前なことを）ではないかと思われます。確証はないですが。

詳細については後ほど説明します。

# なぜこんなことをしようと思ったのか

知人が「エンジニア同士では Slack 使ってるんだけど、会社で LINE WORKS 導入したからチャットツールが２つになってしんどい。。。」と言っておりました。

営業さんや事務さんには LINE と同じインターフェイスで好評の LINE WORKS ですが、エンジニア界隈ではやっぱり Slack が根強い人気。
先駆けてチャット文化だったし、いいね！ボタンがいじれるとか遊び心あるし。
気持ちはとてもよくわかります( ﾟДﾟ)

なので、どうにか共存できないものかと考えました。

# どうやって共存するか

普段はエンジニア同士でチャットしてるので Slack 開いておきたい。
LINE WORKS に通知がきたときは・・・全部見てたらめんどい。
全体向けのやつもあるし、自分が会話に関係ない場合もあるし・・・。

そうだ。メンションつけられたやつだけ見ればいいんじゃね？(ﾟДﾟ)
メンション付きのメッセージをトリガーに、Slack に通知してもらえばいいんだ！ヾ(*´∀｀*)ﾉ

# 実現の流れ

と、言うわけで以下のような流れで Slack に通知できるようにしようと考えました。

1. LINE WORKS の[監査データのダウンロード API](https://developers.worksmobile.com/jp/document/30014002?lang=ja) で LINE WORKS でトークログ（csv）を取得
2. csv データを解析して自分宛のメンションがあったらトーク内容を取得
3. [LINE WORKS の URL スキーム](https://developers.worksmobile.com/jp/document/10017001?lang=ja)を利用してトークルームへのリンクを作成
4. Slack にトーク内容とリンクを通知

Slack にきたリンクをクリックすれば LINE WORKS が起動してトークルームが開く。
そうしたらあとは返事を返すだけですね！

# LINE WORKS の監査データのダウンロード API でトークログ（csv）を取得

そして、１つ目で躓きました。

取り合えずこんなコードを書きました。
ここには書いてませんが、認証情報は変数 `CONSTS` にまとめてあります。

```js:main.gs
function getTalkLogs() {
  const apiUri = 'https://audit.worksmobile.com/r/'
  const apiId = CONSTS.apiId
  const feature = 'log'
  const service = 'message'
  const serviceId = 'audit'
  const endDate = getUnixTime()
  const startDate = Number(endDate) - 600 // 10分前から現在時刻までのログを取得
  const tenantId = CONSTS.tenantId
  const domainId = CONSTS.domainId
  const rangeName = 'tenant'
  const uri = `${apiUri}${apiId}/audit/v2/${feature}/${service}/logs.csv?apiId=downCsvLog&serviceId=${serviceId}&startDate=${startDate}&endDate=${endDate}&tenantId=${tenantId}&domainId=${domainId}&rangeName=${rangeName}`
  const headers = {
    'consumerKey': CONSTS.consumerKey,
    'Authorization': `Bearer ${LINEWORKS.getToken(CONSTS)}`
  }
  const options = {
    'method': 'get',
    'headers': headers,
    "muteHttpExceptions" : true,
    "validateHttpsCertificates" : false,
    "followRedirects" : true
  }
  try {
    const res = UrlFetchApp.fetch(uri, options).getBlob()
    Logger.log(`Success:\n${res.getDataAsString()}`)
  } catch(e) { Logger.log(`Error:\n${e}`) }
}
```

こいつを実行するとエラーが出ました。
どんなエラーかと言うと『ページが見つかりません』( ﾟДﾟ)

<details><summary>詳細なエラー内容はここに折りたたんで貼り付けておきます</summary><div>

```html
Success:
<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title>Admin</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?2" />
    <link href="/assets/dist/styles/domain_register.css?20201119101838" rel="stylesheet" type="text/css"/>
    <link href="/assets/dist/styles/domain_admin.css?20201119101838" rel="stylesheet" type="text/css"/>
</head>
<body class="">
<a href="#content" class="skip"></a>
<div id="wrap" class="error_layout">
    <!-- header -->
    <div id="header">
        <h1><a href="https://jp1-admin-v1.worksmobile.com" class="logo"><strong>LINE WORKS</strong><span>Admin</span></a></h1>
    </div>
    <!-- //header -->
    <!-- container -->
    <div id="container" class="error wide">
        <!-- content -->
        <div id="content">
            <div class="error_box">
                <h3 class="h_tit notfound"><span>Page not found.</span></h3>
                <p class="desc">Please contact <a href="https://help.worksmobile.com">Customer Center</a> for related questions and we will respond to your inquiries as soon as possible.</p>
                <div class="btn">
                    <button class="point" type="button" onclick="window.history.back();"><strong>Previous page</strong></button>
                </div>
            </div><span class="align"></span>
        </div>
        <!-- //content -->
    </div>
    <!-- //container -->
    <!-- footer -->
    <div id="footer">
        <address>&copy; <a href="https://line.worksmobile.com">Works Mobile Corp.</a></address>
    </div>
    <!-- //footer -->
</div>
<div class="pop_error" >
    <div id="container" class="error" style="display:none;">
        <div class="error_box">
            <h3 class="h_tit notfound"><span>Page not found.</span></h3>
            <p class="desc">Please contact <a href="https://help.worksmobile.com">Customer Center</a> for related questions and we will respond to your inquiries as soon as possible.</p>
            <div class="btn">
                <button class="point" type="button" onclick="window.close();"><strong>Previous page</strong></button>
            </div>
        </div><span class="align"></span>
    </div>
</div>
</body>
</html>
```
</div></details>

### そんなこと言って、どっか間違ってんじゃないの？？

まずは自分を疑いました。コードミスないかな。
ドキュメント読み間違えてないかな。認証情報間違ってないかな。
でも、Http Response は Success になってるんだよね・・・？( ﾟДﾟ)ｹﾞｾﾇ

そこで、[Postman](https://www.postman.com/) を使ってエラーになるかどうかを試してみました。
幸いなことに、この API の Method は GET なので、uri と Access Token さえ抜き出せばほぼ同じ Request が可能です。

すると・・・

![1611557791.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/bb28bd9d-7651-4154-9680-bd9631faacc7.png)

できた。。。
え、どゆこと？？( ﾟДﾟ)

## LINE WORKS サービスは海外サーバからの利用を保証するものではない

何か根本的なものを見落としている・・・そう思った私はドキュメントやらコミュニティの投稿やらを読み漁りました。

すると、ヘルプセンターにこんな文章が。

『LINE WORKS サービスは、現在日本市場でのみ提供されています。基本的には LINE WORKS のサーバーと正常な通信ができるインターネット環境下であれば海外でも利用できますが、日本国内での利用を想定しており、海外での利用を保証するものではありません。

海外でご使用になられる際には、輸出管理規制等、法令により必要とされている手続きなど、お客様ご自身の責任において行なっていただきますようお願いいたします。』
[LINE WORKS ヘルプセンター - 海外でも利用できますか？](https://help.worksmobile.com/jp/topic/common/support-environment/use-line-works-overseas/)

海外からの利用は保証されていない・・・？
そう言えば、Google Apps Script ってサーバを Google さんが用意してくれているので、アメリカからのアクセスになるのでは・・・？(._.)

## FetchApp で利用されている IP

Google Apps Script での API Request には FetchApp を使用します。
そこで、FetchApp で利用されている IP を調べればどこの国からの Request かがわかります。

すでに調べている方がいたので、[こちら](https://admin-it.xyz/gas/gas-ippool-listandget/)の情報を参考にさせていただきました。

<details><summary>fetchAPP で利用される IP pool Lists（50 IP）</summary><div>

```
8.34.208.0/20
8.35.192.0/21
8.35.200.0/23
23.236.48.0/20
23.251.128.0/19
34.64.0.0/11
34.96.0.0/14 
34.100.0.0/16 
34.102.0.0/15 
34.104.0.0/14 
34.124.0.0/18 
34.124.64.0/20 
34.124.80.0/23 
34.124.84.0/22 
34.124.88.0/23
34.124.92.0/22 
34.125.0.0/16 
35.184.0.0/14 
35.188.0.0/15 
35.190.0.0/17 
35.190.128.0/18 
35.190.192.0/19 
35.190.224.0/20 
35.190.240.0/22 
35.192.0.0/14 
35.196.0.0/15 
35.198.0.0/16 
35.199.0.0/17 
35.199.128.0/18 
35.200.0.0/13 
35.208.0.0/13 
35.216.0.0/15 
35.219.192.0/24 
35.220.0.0/14 
35.224.0.0/13 
35.232.0.0/15 
35.234.0.0/16 
35.235.0.0/17 
35.235.192.0/20 
35.235.216.0/21 
35.235.224.0/20 
35.236.0.0/14 
35.240.0.0/13 
104.154.0.0/15 
104.196.0.0/14 
107.167.160.0/19 
107.178.192.0/18 
108.59.80.0/20 
108.170.192.0/20 
108.170.208.0/21 
108.170.216.0/22 
108.170.220.0/23 
108.170.222.0/24 
130.211.4.0/22 
130.211.8.0/21 
130.211.16.0/20 
130.211.32.0/19
```
</div></details>

このリストにある IP アドレスをすべて調べてみましたが、当たり前かもしれませんがどれもアメリカのサーバですね。

![1611558707.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/0614c44c-4368-c581-b2a3-05437d3e4510.png)

と、言うことはこれが原因かな・・・？
Postman で成功したのは、ローカルからの Request になるので、日本からの Request になったから、と言えるでしょうし。
ただ、**確証は持てません**。
Google Apps Script で Region が選べれば比較して検証できたのですけどね。
あくまで、可能性の１つですね。

と、言うわけで調べられたのはここまででした。

# おわりに

ここまでお付き合いいただきありがとうございました。
結局完成してないので、とても悔しいです。

まぁ、国内サーバ借りて開発すればいいだけのことなんですけどね。
もしくは Region が指定できる AWS とか Heroku とか使えばいいんでしょうけど。

GAS でやりたかったんですよ。
もし、どなたか成功事例がありましたら共有いただけると嬉しいです。

ではまた！(^^)/

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

[fetchAPPで利用されるIP poolを調べたメモ 2020/03/03時点](https://admin-it.xyz/gas/gas-ippool-listandget/)
[IPアドレス住所検索](https://rakko.tools/tools/11/)
[【Slack】SlackでBotを開発する【GAS】](https://qiita.com/SyogoSuganoya/items/bb6a4f5256c0e944a0f5)
[【GAS】UNIX time を取得する方法](https://qiita.com/kunihiros/items/3878e951e726358a3258)