Garoonに登録した予定情報をkintoneにPOSTしてみた

## はじめに

前回の記事
[**kintoneに登録した予定情報をGaroonにPOSTしてみた**](https://qiita.com/RyBB/items/ff8bfa9cb94423280bc1)

の逆バージョン、

**Garoon → kintone**

になります。こっちの方が需要がありそうな気がします。

## 動作イメージ

イメージはつきやすいとは思いますが、こんな感じです。
![grkin.png](https://qiita-image-store.s3.amazonaws.com/0/153051/390cd4d8-0fef-0c50-722a-cca22af33543.png)

kintoneへ登録することで、
 「来訪」の割合を出したり「勉強会」の開催回数を出したり
が簡単にできる！kintoneのグラフ集計機能も使えるので便利！

## 事前知識

今回はGaroon側でカスタマイズするわけですが、Garoonのカスタマイズはkintoneと比べるとちょっとつらかったです (単に慣れてないだけかもですが ^^;)。

- カスタマイズファイルのアップロード先がわかりくい
- Garoon JavaScript API はそこまで充実しているわけではない

### ファイルのアップロード先

Garoonはアプリケーションごとに管理が別れています。
スケジュールの場合は、
**『Garoonシステム管理 > 各アプリケーションの管理(タブ) > スケジュール > JS/CSSによるカスタマイズ』**
の順にいきます。うん。覚えられない。

で、カスタマイズグループを作成してJSファイルをアップロードします。

:pencil2: **豆知識**
このカスタマイズグループでカスタマイズの適用ユーザーを指定することができる!
(Garoonは影響範囲が広いのでぜひ確認を)

### Garoon JavaScript API

devnetの [このページ](https://developer.cybozu.io/hc/ja/articles/115002115386) に一覧があるのですが、そこまで多くはないのがわかると思います。
特にイベントは **表示系** しかないです。困った。

## やりたいこと

やりたいことをシンプルに1行で表すと、
**Garoonで予定を登録すると、その内容がkintoneの特定アプリにレコードとして保存される**

です。もう少し技術的に表すと、

「Garoonの予定登録で保存ボタンが押されたら」
「Garoon側で記述した内容(日時、タイトル、参加者 等)を取得して」
「kintoneの適切なフィールドに値が入るようにレコードを新規追加する」

てな感じです。うん。わかりやすい

## ポイント

今回も前回同様、なかなかスムーズにはいかなかったです(´；ω；｀)
ざっと洗い出すと、以下がポイントかなと。

* Garoonのイベント
* ユーザー情報
* 施設情報
* 予定の公開方法

### イベント

先ほども触れましたが、Garoon側には **表示**イベント しか用意されていません。
kintoneでいう**submit**イベントがないんですよね・・・

まぁ、ないものをねだっても仕方がないので、
今回は `addEventListener()`で保存ボタンにイベントを追加することにしました

そのため非推奨のDOM操作です つД`)ｸﾞｽﾝ

### ユーザー情報

これは前回もありましたが、Garoonとkintoneではユーザー情報の内容が異なるので、kintone用に合せる必要があります。詳しくは[前回](https://qiita.com/RyBB/items/ff8bfa9cb94423280bc1)の記事を！

### 施設情報

Garoonではユーザー情報と似た感じで施設（会議室など）の情報を保持しています。
が、kintone側にはそんなものないので、うまいこと保存できるようにする必要があります。

### 予定の公開方法

これはコードを作り終わって動作確認しているときに 「はっ！やべっ！」 と思った部分でした^^;
Garoon側で**「非公開」**としても、kintone側で公開されたらたまったもんじゃないです

ってことで、Garoon同様、参加者しか見れないようにします

## kintoneアプリ

保存先のkintone側のアプリは以下のように作りました

### フィールド

| フィールドタイプ | フィールドコード | 用途 |
|:-:|:-:|:-:|:-:|
| 日時 | start | 開始日時 |
| 日時 | end | 終了日時 |
| 文字列 (1行) | eventMenu | メニュー |
| 文字列 (1行) | subject | タイトル |
| ユーザー選択 | attendees | 参加者 |
| 文字列 (1行) | facilities | 施設 |
| 文字列 (複数行) | notes | メモ |
|ラジオボタン| visibilityType | 公開方法|

↓ 配置するとこんなかんじ
<img width="500" alt="スクリーンショット 2019-02-26 21.35.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/153051/9795dbff-58d0-22a3-1352-f2c8e198690e.png">

### アクセス権

レコードの公開・非公開をラジオボタンで設定しています
<img width="600" alt="スクリーンショット 2019-02-26 21.55.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/153051/4e1c79b4-4ed1-01c9-8231-9f1eb07c77f1.png">

これで非公開の~~デート予定~~ **飲み会** がバレずに済みますｗ


## コード

全体は [GitHub](https://github.com/RyBB/kintoneCustomize/blob/master/GrKin_Schedule/copySchedule.js) で公開しています。

### イベント処理

Garoonのイベントと保存ボタンのonclickイベント
`addEventListener('click', handler(), true)` この最後に **true** を指定することで、ボタンを押したら最初に動くようになりました。

が、詳しくは知りません。キャプチャとバブリングがどうたらとネットに書いてありましたｗ


```javascript
  // Garoonのイベント
  garoon.events.on('schedule.event.create.show', () => {
    // 保存ボタンの取得 (※DOM操作)
    const submit = document.getElementById('schedule_submit_button');
    if (!submit) {
      return;
    }
    // 保存ボタンのクリックイベントに下記処理を追加
    submit.addEventListener('click', () => {
```

### 処理

kintoneに合わせてごにょごにょします

```javascript
      // ユーザーのidとtypeを削除 (kintoneでは必要ないため)
      e.attendees.forEach((ele, i) => {
        delete e.attendees[i].id;
        delete e.attendees[i].type;
      });

      // スケジュールの公開方法
      const visibilityType = e.visibilityType === 'PUBLIC' ? '公開' : '非公開';

      // 施設情報 (テキスト1行で表現)
      let facilities = e.facilities.map(ele => {
        return ele.name;
      });
      facilities = facilities.join(', ');
```

### 認証

> 2019/04/03 修正＆追記
> APIトークン認証からセッション認証に変更

Garoonとkintoneが同じ環境の場合セッション認証が使えるので、APIトークン認証ではなくセッション認証を利用する方法にします。

POST(とPUTとDELETE)を利用する場合、**CSRFトークン** を取得する必要があります。
(詳しくは [こちら](https://developer.cybozu.io/hc/ja/articles/115005294843))

Garoon上でkintoneのCSRFトークンを取得する関数 `garoon.connect.kintone.getRequestToken()` を利用します。

```javascript
garoon.connect.kintone.getRequestToken()
.then(token => {
  // POST処理
});
```

そして、取得したCSRFトークンを`?__REQUEST_TOKEN__=〇〇`としてURLに載せてPOSTします。
(今回はGaroonにもともとあるjQueryのajaxを利用します)

```javascript
garoon.connect.kintone.getRequestToken()
.then(token => {
  $.ajax({
    url: kin.url + '?__REQUEST_TOKEN__=' + token,
    type: 'POST',
    headers: {
      'Content-Type': 'application/json',
    }
  ・・・
});
```

> 2019/05/13 追記
> fetch API によるリクエスト方法を追記

fetch API の場合、ヘッダーに ```'X-Requested-With': 'XMLHttpRequest'``` を載せる必要があります。

```javascript
garoon.connect.kintone.getRequestToken()
.then(token => {
  return fetch(kin.url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Requested-With': 'XMLHttpRequest'
    },
    body: JSON.stringify({...params, __REQUEST_TOKEN__: token})
  }).then(res => {
    console.log(res.json());
・・・
});
```

### 注意点 :warning: 

`addEventListener('click', handler(), true)` でイベントを登録すると、
**Garoonのエラーチェックの前に** レコードを登録してしまいます。
-> 施設が重複でエラーとなっても、kintone側には登録されてしまいます

でも他に良い方法が思いつかず今回は断念・・・
-> submitイベントさえつけば、、、(どうせなら submit.success もつくと良いな〜)

## おわりに

なかなか思い通りにはいかないガルキン連携です。
Garoon側がエラーでもkintoneへ保存されるのはどうにかしたい。。Promise対応できないかね〜

ただ、前回よりは今回のほうが需要があると信じてます！！
それでは！≧(+･` ཀ･´)≦