Telegram Botで顧客情報をちゃちゃっと確認

Telegram, Node.jsを使ってkintoneのデータをちゃちゃっと閲覧/登録することにチャレンジしました。

# Telegramとは
インスタントメッセンジャーでセキュリティの高さが売りのようです。
個人的にはプラットフォームの多さ、APIの豊富さから連携にチャレンジしました。
[公式サイトはこちらです。](https://www.telegram.org/)
[APIの一覧はこちらです。音声や動画ファイルの取り扱いもできます。](https://core.telegram.org/bots/api#available-methods)

# kintoneとは
「kintoneとは、サイボウズ株式会社が開発しクラウドで提供するWebデータベース型業務アプリ構築サービス（作成したアプリケーションを連携したりシステム管理機能も活用できるよ）
[2015年のkintone Advent Calendarから引用](https://qiita.com/ryokdy/items/41bfa7a008a70ae863d1)しました。
[公式サイトはこちらです。](https://kintone.cybozu.co.jp/jp/)

# やったこと
- 会社名で顧客管理アプリに情報が登録されているか確認
- 登録されている場合は選択肢を表示
- 選択肢クリックで各種情報を表示
- 写真送信で写真を登録

こんな感じです。
<blockquote class="twitter-tweet" data-lang="ja"><p lang="und" dir="ltr"><a href="https://t.co/mJThxIV3TD">pic.twitter.com/mJThxIV3TD</a></p>&mdash; たけち (@cy_takeuchi) <a href="https://twitter.com/cy_takeuchi/status/1069115506660016129?ref_src=twsrc%5Etfw">2018年12月2日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

実際に試してみたい方は以下の手順をご確認ください。

# 準備1. Botの作成
[こちらの手順](https://core.telegram.org/bots#6-botfather)に従ってBotを作成します。
こんな感じでBotFatherに話しかけることでBotが作成できます。すごい。
<img width="375" alt="IMG_2027.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/102790/8d2e9f5b-5dd8-7ff0-37d1-ee4916894603.png">
Bot名（↑の場合はcy_take_bot）と入力するとAPIトークンが表示されるのでそれをメモします。
APIトークンは「xxxx:xxxxxxxxx」のような形式でコロンの前部分もトークンに含まれるので注意が必要です。

# 準備2. kintoneのアプリ作成
アプリストアから顧客サポートパックを追加します。
![app.png](https://qiita-image-store.s3.amazonaws.com/0/102790/dc1fe42b-b4d5-2a95-0d5a-6737b8ede121.png)

追加できたら顧客管理アプリを開き、添付ファイルフィールドを追加します。
フィールドコードは添付ファイルのままで大丈夫です。
次にURLから確認できるドメインとアプリIDをメモします。
https://xxxx.cybozu.com/k/100/の場合は「xxxx.cybozu.com」がドメインです。
「100」がアプリIDです。

顧客管理アプリにAPIトークンを追加します。アクセス権はレコード閲覧と編集をチェックします。

# 準備3. Node.jsにライブラリ追加
```shell
$ npm install --save node-telegram-bot-api kintone-nodejs-sdk axios
```

# 準備4. 実行ファイルの保存
以下のコードをbot.jsという名前で保存します。
冒頭のコメント箇所はメモした内容に変更してください。

```bot.js
'use strict';
process.env.NTBA_FIX_319 = 1;

const Path = require('path');
const Axios = require('axios');
const TelegramBot = require('node-telegram-bot-api');
const kintone = require('kintone-nodejs-sdk');
const FormData = require('form-data');

// 個別の設定
const botToken = 'xxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // BotのAPIトークン
const kintoneDomain = 'xxxx.cybozu.com'; // kintoneのドメイン
const kintoneAppId = xxxx; // kintoneのアプリID
const kintoneToken = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // kintoneのAPIトークン

const bot = new TelegramBot(botToken, {polling: true});
const kintoneAuthWithAPIToken = (new kintone.Auth()).setApiToken(kintoneToken);
const kintoneConnection = new kintone.Connection(kintoneDomain, kintoneAuthWithAPIToken);
const kintoneRecord = new kintone.Record(kintoneConnection);

const fileUpload = async (fileStream, fileName) => {
    const form = new FormData();
    form.append('file', fileStream, fileName);
    const options = {
        method: 'POST',
        url: `https://${kintoneDomain}/k/v1/file.json`,
        headers: {
            'X-Cybozu-API-Token': kintoneToken,
            'Content-Type': form.getHeaders()['content-type']
        },
        data: form
    };
    const res = await Axios(options);
    return res.data.fileKey;
}

const fileDownload = async (fileKey) => {
    const options = {
        method: 'GET',
        url: `https://${kintoneDomain}/k/v1/file.json?fileKey=${fileKey}`,
        headers: {
            'X-Cybozu-API-Token': kintoneToken
        },
        responseType: 'arraybuffer'
    };
    const res = await Axios(options);
    return res.data;
}

let record = {};

bot.onText(/[^(担当者名|連絡先|住所|添付ファイル)]/, (msg) => {
    const chatId = msg.chat.id;
    const customerName = msg.text;
    const query = `会社名 like "${customerName}"`;

    kintoneRecord.getRecords(kintoneAppId, query).then((res) => {
        record = res.records[0];
        
        let select_options = {};
        if (record['添付ファイル'].value[0] !== undefined) {
            select_options = {
                reply_markup: {
                    keyboard: [['担当者名'], ['連絡先'], ['住所'], ['添付ファイル']],
                    one_time_keyboard: true
                }
            };
        } else {
            select_options = {
                reply_markup: {
                    keyboard: [['担当者名'], ['連絡先'], ['住所']],
                    one_time_keyboard: true
                }
            };
        }
        
        bot.sendMessage(chatId, 'ヒットしました。何を確認しますか。', select_options);
    });
});

bot.onText(/担当者名|連絡先|住所|添付ファイル/, (msg, match) => {
    const chatId = msg.chat.id;
    const rid = record.$id.value;
    const file = record['添付ファイル'].value[0];

    let text = '';
    if (match[0] === '担当者名') {
        text = `${record['部署名'].value} ${record['担当者名'].value}`;
        bot.sendMessage(chatId, text);
    } else if (match[0] === '連絡先') {
        text = `${record['メールアドレス'].value} ${record['電話番号'].value}`;
        bot.sendMessage(chatId, text);
    } else if (match[0] === '住所') {
        text = `${record['住所'].value}`
        bot.sendMessage(chatId, text);
    } else if (match[0] === '添付ファイル') {
        fileDownload(file.fileKey).then((fileData) => {
            const fileOptions = {
                filename: file.name,
                contentType: file.contentType
            }
            bot.sendPhoto(chatId, fileData, {}, fileOptions);
        });
    }
});

bot.on('photo', (file) => {
    const rid = record.$id.value;
    const botFileId = file.photo[0].file_id;
    bot.getFileLink(botFileId).then((fileLink) => {
        const fileName = Path.basename(fileLink);
        fileUpload(bot.getFileStream(botFileId), fileName).then((fileKey) => {
            const params = {
                '添付ファイル': {
                    'value': [
                        {'fileKey': fileKey}
                    ]
                }
            };
            kintoneRecord.updateRecordById(kintoneAppId, rid, params);
        });
    });
});
```

# 実行！
以下のコマンドを入力して実行します。

```shell
$ node bot.js
```

実行できたらTelegramからメッセージを送信してみてください。

# まとめ
Bot楽しいですね！