【Garoon REST API】kintoneにレコード追加されたらGaroonに通知を送信する

目次

はじめに

今回は 通知を登録する API を用いて、kintone レコードが新規登録された際、Garoon にレコード内容を通知するカスタマイズを紹介します。

いままで、Garoon と kintone を両方使用していたユーザーの方は、双方通知を確認する必要がありましたが、今回のカスタマイズで通知を Garoon に一元管理できます。

前提条件と注意事項

  • この機能は、以下の環境で動作します。
    • クラウド版 Garoon
    • パッケージ版 Garoon(ver 5.0.0 以降)
  • 製品のアップデートにより、通知アイコンを正常に表示できなくなる場合があります。

完成イメージ

kintoneアプリ

Garoon通知

Garoonシステム管理設定

システム管理(各アプリケーション)> 通知一覧 > 外部通知の設定 > 外部通知の追加から外部通知を設定する必要があります。
Garoon ヘルプ - API の外部通知の設定 クラウド版 (External link) パッケージ版 (External link) を参照してください。

下図を参考に外部通知を追加してください。

  1. ステータスは「有効」を選択します。
  2. 許可する外部通知は「API」にチェックしてください。
  3. 外部通知コードは「kintonedailyreport」に設定します。
  4. 許可する URL は下記 2 つを設定します。sample の部分はご自身の環境に合わせて設定してください。
    • https://sample.cybozu.com/*
      kintone(sample.cybozu.com/k...)から Garoon REST API を実行するために設定します。
    • https://static.cybozu.com/*
      今回は通知アイコンに製品内の画像を使用しているので上記 URL を含める必要があります。

kintoneアプリ作成

下表を参考に 4 つのフィールドをアプリに設定し、簡単な日報アプリを作成します。

フィールドタイプ フィールドコード 備考
文字列 (1行) title 必須項目にする
文字列 (複数行) body 必須項目にする
日付 date レコード登録時の日付を初期値にする
作成者 作成者

JavaScript / CSSカスタマイズ設定

サンプルコード

次のサンプルコードを「dailyReport.js」という名前で保存します。文字コードは「UTF-8」を使用してください。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/*
* Notify Garoon Sample Program
* Copyright (c) 2018 Cybozu
*
* Licensed under the MIT License
* https://opensource.org/license/mit/
*/

(function($) {
  'use strict';
  // Garoon で設定した外部通知コード
  const grnNoticeCode = 'kintonedailyreport';
  // 通知を送信するユーザーのログイン名
  const grnNoticeUser = ['{Target User Login Name}'];
  // kintone のアプリの URL
  const kntAppURL = 'https://sample.cybozu.com/k/xx/';

  // SOAP の XML のヘッダー部分を作成する
  const makeXMLHeader = function(service, action) {

    let xmlns;
    if (service === 'schedule') {
      xmlns = 'schedule_services="http://wsdl.cybozu.co.jp/schedule/2008"';
    } else {
      return null;
    }
    return '<?xml version="1.0" encoding="UTF-8"?>' +
                '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" ' +
                    'xmlns:xsd="http://www.w3.org/2001/XMLSchema" ' +
                    'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
                    'xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" ' +
                    'xmlns:' + xmlns + '>' +
                '<SOAP-ENV:Header>' +
                    '<Action SOAP-ENV:mustUnderstand="1" ' +
                        'xmlns="http://schemas.xmlsoap.org/ws/2003/03/addressing">' + action + '</Action>' +
                    '<Timestamp SOAP-ENV:mustUnderstand="1" Id="id" ' +
                        'xmlns="http://schemas.xmlsoap.org/ws/2002/07/utility">' +
                        '<Created>2037-08-12T14:45:00Z</Created>' +
                        '<Expires>2037-08-12T14:45:00Z</Expires>' +
                    '</Timestamp>' +
                    '<Locale>jp</Locale>' +
                '</SOAP-ENV:Header>';
  };

  // ajax を実行する
  const runajax = function(url, method, dtype, sendobj, callback) {

    const objajax = {type: method, url: url};
    const headers = {'X-Requested-With': 'XMLHttpRequest'};

    // データを xml 形式で送信する場合
    if (dtype === 'xml') {

      headers['Content-Type'] = 'text/xml; charset=UTF-8';
      objajax.data = sendobj;

      // データを json 形式で送信する場合
    } else if (dtype === 'json') {

      headers['Content-Type'] = 'application/json';
      objajax.contentType = 'application/json';
      objajax.data = JSON.stringify(sendobj);
      objajax.dataType = 'json';

    }

    objajax.headers = headers;

    // ajax を実行
    return $.ajax(
      objajax
    );

  };

  // Garoon に通知を送信
  const sendNotice = function(rec, token) {

    const arydest = [];

    // 通知の送信先を配列にまとめる
    for (let i = 0; i < grnNoticeUser.length; i += 1) {
      arydest.push({type: 'USER', code: grnNoticeUser[i]});
    }

    // 送信する通知の情報
    const sendobj = {
      // リクエストトークン
      __REQUEST_TOKEN__: token,
      // Garoon で設定した外部通知コード
      app: grnNoticeCode,
      // 通知のキー(他のレコードと重複しないこと)
      notificationKey: kntAppURL + rec.$id.value,
      // kintone のレコードの URL
      url: kntAppURL + 'show#record=' + rec.$id.value,
      // 通知のモード 「add: 追加, modify: 変更, remove: 削除」
      operation: 'add',
      // 通知のタイトル ※レコードのタイトルを出力
      title: rec.title.value,
      // 通知の本文 ※レコードの本文を出力
      body: rec.body.value,
      // 通知のアイコン
      icon: 'https://static.cybozu.com/g/F19.11_379/grn/image/cybozu/image-common/kintone.svg',
      // 通知の送信先
      destinations: arydest
    };

    // 通知を送信
    return runajax('/g/api/v1/notification/items', 'POST', 'json', sendobj).then((resp) => {
      return resp;
    }).catch((err) => {
      return err;
    });

  };

  // Garoon のリクエストトークンを取得する
  const getRequestToken = function() {

    const xml = makeXMLHeader('schedule', 'UtilGetRequestToken') +
                  '<SOAP-ENV:Body>' +
                    '<UtilGetRequestToken></UtilGetRequestToken>' +
                  '</SOAP-ENV:Body>' +
                  '</SOAP-ENV:Envelope>';

    // Garoon のリクエストトークンを取得
    return runajax('/g/util_api/util/api.csp', 'POST', 'xml', xml).then((resp) => {
      const $resp = $(resp);
      // リクエストトークンの文字列部分を抽出して返す
      const token = $resp.find('request_token').text();
      return token;
    }).catch((err) => {
      return err;
    });

  };

  // レコードの保存に成功したとき
  kintone.events.on(['app.record.create.submit.success'], (ev) => {

    const rec = ev.record;

    // Garoon のリクエストトークンを取得する
    return getRequestToken().then((token) => {
      // 通知を送信する
      return sendNotice(rec, token);
      // 成功時
    }).then((resp) => {
      return ev;
      // 失敗時
    }).catch((err) => {
      alert(err.responseText);
      return ev;
    });

  });

  // イベント:新規画面を開いたとき
  kintone.events.on(['app.record.create.show'], (ev) => {
    const rec = ev.record;
    // 「タイトル」フィールドにユーザー名と日付を表示する
    rec.title.value = '日報: ' + kintone.getLoginUser().name + ' (' + rec.date.value + ')';
    // 「本文」フィールドに日報の初期フォーマットを表示する
    rec.body.value = '■本日の業務\n\n\n■本日の学び・感想\n\n\n■相談・連絡';
    return ev;
  });

})(jQuery.noConflict(true));

14・16 行目をご自身の環境に合わせて編集してください。

13
14
15
16
// 通知を送信するユーザーのログイン名
const grnNoticeUser = ['{Target User Login Name}'];
// kintone のアプリの URL
const kntAppURL = 'https://sample.cybozu.com/k/xx/';

アプリ画面の右上の歯車マークから、アプリの設定 > 設定タブ > JavaScript / CSS でカスタマイズの順番に遷移し、下図のように設定します。

本カスタマイズでは、 Cybozu CDN の以下のライブラリーを使用します。

  • jQuery
    https://js.cybozu.com/jquery/3.3.1/jquery.min.js

jQuery は dailyReport.js より上位に登録してください。

以上ですべての設定は完了です。

サンプルコード解説

サンプルコード「dailyReport.js」について解説していきます。

makeXMLHeader

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  // SOAP の XML のヘッダー部分を作成する
  const makeXMLHeader = function(service, action) {

    let xmlns;
    if (service === 'schedule') {
      xmlns = 'schedule_services="http://wsdl.cybozu.co.jp/schedule/2008"';
    } else {
      return null;
    }
    return '<?xml version="1.0" encoding="UTF-8"?>' +
                '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" ' +
                    'xmlns:xsd="http://www.w3.org/2001/XMLSchema" ' +
                    'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
                    'xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" ' +
                    'xmlns:' + xmlns + '>' +
                '<SOAP-ENV:Header>' +
                    '<Action SOAP-ENV:mustUnderstand="1" ' +
                        'xmlns="http://schemas.xmlsoap.org/ws/2003/03/addressing">' + action + '</Action>' +
                    '<Timestamp SOAP-ENV:mustUnderstand="1" Id="id" ' +
                        'xmlns="http://schemas.xmlsoap.org/ws/2002/07/utility">' +
                        '<Created>2037-08-12T14:45:00Z</Created>' +
                        '<Expires>2037-08-12T14:45:00Z</Expires>' +
                    '</Timestamp>' +
                    '<Locale>jp</Locale>' +
                '</SOAP-ENV:Header>';
  };

Garoon SOAP API のヘッダー部分を作成する関数です。
今回はリクエストトークンを取得するために一度だけ SOAP API を実行します。

runajax

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  // ajax を実行する
  const runajax = function(url, method, dtype, sendobj, callback) {

    const objajax = {type: method, url: url};
    const headers = {'X-Requested-With': 'XMLHttpRequest'};

    // データを xml 形式で送信する場合
    if (dtype === 'xml') {

      headers['Content-Type'] = 'text/xml; charset=UTF-8';
      objajax.data = sendobj;

      // データを json 形式で送信する場合
    } else if (dtype === 'json') {

      headers['Content-Type'] = 'application/json';
      objajax.contentType = 'application/json';
      objajax.data = JSON.stringify(sendobj);
      objajax.dataType = 'json';

    }

    objajax.headers = headers;

    // ajax を実行
    return $.ajax(
      objajax
    );

  };

jQuery の ajax を使用して HTTP リクエストを実行する関数です。
リクエストトークン取得と、通知登録でそれぞれ SOAP API、REST API を実行する必要があります。
そのため、引数の「dtype」により、処理を分岐させています。

sendNoticesendNotice

 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
  // Garoon に通知を送信
  const sendNotice = function(rec, token) {

    const arydest = [];

    // 通知の送信先を配列にまとめる
    for (let i = 0; i < grnNoticeUser.length; i += 1) {
      arydest.push({type: 'USER', code: grnNoticeUser[i]});
    }

    // 送信する通知の情報
    const sendobj = {
      // リクエストトークン
      __REQUEST_TOKEN__: token,
      // Garoon で設定した外部通知コード
      app: grnNoticeCode,
      // 通知のキー(他のレコードと重複しないこと)
      notificationKey: kntAppURL + rec.$id.value,
      // kintone のレコードの URL
      url: kntAppURL + 'show#record=' + rec.$id.value,
      // 通知のモード 「add: 追加, modify: 変更, remove: 削除」
      operation: 'add',
      // 通知のタイトル ※レコードのタイトルを出力
      title: rec.title.value,
      // 通知の本文 ※レコードの本文を出力
      body: rec.body.value,
      // 通知のアイコン
      icon: 'https://static.cybozu.com/g/F19.11_379/grn/image/cybozu/image-common/kintone.svg',
      // 通知の送信先
      destinations: arydest
    };

    // 通知を送信
    return runajax('/g/api/v1/notification/items', 'POST', 'json', sendobj).then((resp) => {
      return resp;
    }).catch((err) => {
      return err;
    });

  };

Garoon 通知 API を実行する関数です。sendobj がリクエストボディです。
API の詳細は 通知を登録する を確認してください。

104 行目の icon オプションに kintone 製品内の画像を設定しています。
前提条件と注意事項にもあるように、今後製品のアップデートにより正常に表示されなくなる可能性があるので注意してください。

getRequestToken

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
  // Garoon のリクエストトークンを取得する
  const getRequestToken = function() {

    const xml = makeXMLHeader('schedule', 'UtilGetRequestToken') +
                  '<SOAP-ENV:Body>' +
                    '<UtilGetRequestToken></UtilGetRequestToken>' +
                  '</SOAP-ENV:Body>' +
                  '</SOAP-ENV:Envelope>';
    let $resp, token;

    // Garoon のリクエストトークンを取得
    return runajax('/g/util_api/util/api.csp', 'POST', 'xml', xml).then((resp) => {
      $resp = $(resp);
      // リクエストトークンの文字列部分を抽出して返す
      token = $resp.find('request_token').text();
      return token;
    }).catch((err) => {
      return err;
    });

  };

リクエストトークンを取得する 関数を実行します。
makeXMLHeader 関数で設定した SOAP API 用のヘッダーと、この関数内で成型したボディを使用し、SOAP API を実行しています。

おわりに

今回のアップデートにより、Garoon 以外の製品から Garoon へ通知を登録することが可能になりました。
本 Tips では kintone から通知を登録してみましたが、他の製品からも Garoon へ通知を登録できそうですね。

ぜひ Garoon REST API を触ってみてください。

information

この Tips は、2018 年 11 月版 Garoon で動作を確認しています。