connpass のイベントを記録&統計をとってみる

著者名:後迫 孝(サイボウズ株式会社)

目次

サイボウズが主催している kintone の勉強会『 kintone devCamp (External link) 』では、オープンな IT 勉強会・イベント支援サイト『 connpass (External link) 』を利用しています。
connpass には数多くのイベントが作成されており、とても便利に活用させていただいています。(詳細は後述)

今回は、 connpass API (External link) を利用して検索時点の申し込み数や定員を kintone に記録し、統計をとってみたいと思います。

利用した kintone API

connpass

connpass (External link) は、人をつなぐ IT 勉強会・イベント支援サイトというコンセプトで、IT 系の勉強会向けに活用されています。
こちら画像は、私たちが運営する『 kintone devCamp (External link) 』です。

こちらが、connpass の特徴です。

  • 勉強会の申し込みページが無料で作れる。
  • X(旧 Twitter)や Facebook で連携して新着を確認できる。
  • Slideshare やホームページの発表資料をまとめられる。
  • 日単位のイベント統計ができる。
  • 参加者のための iPhone アプリがある。
  • Paypal を使った有料(前払い)イベントができる。

ほか、たくさんの魅力あるサービスです。

kintone でアプリを作る

アプリのフィールド

フィールド名とフィールドコードは同じ名称にしています。

フィールドの種類 フィールド名/フィールドコード 注意事項 説明
文字列(1行) Keyword 必須項目 入力されたキーワードを元に検索する。
日付 Date 省略可 入力された日を開催日として検索する。
テーブル Table connpassイベントを格納するテーブル。
日時 StartDateTime テーブル内のフィールド connpass イベントの開始日時。
日時 EndDateTime テーブル内のフィールド connpass イベントの終了日時。
リッチテキスト Title テーブル内のフィールド connpass イベントのタイトル。
イベントのタイトルをリンク化しているため、リッチテキストにする。
数値 Accepted テーブル内のフィールド connpass イベントの参加者数。
数値 Limit テーブル内のフィールド connpass イベントの定員。
文字列(1行) SubTitle テーブル内のフィールド connpass イベントのタイトル。
イベントごとのグラフを作成したいため追加。
リッチテキストはグラフでグルーピングできない。
計算 SumAccepted 計算式:SUM(Accepted) 参加者数の合計。
計算 SumLimit 計算式:SUM(Limit) 定員の合計。
計算 AcceptedRate 計算式:SumAccepted/SumLimit*100 参加率。
数値 EventCount connpass イベント検索結果の件数。

フォームのイメージ

グラフのイメージ

たまったデータを kintone のグラフで集計します。

プログラムと解説

プログラム

  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
/*
 * connpass to kintone sample program
 * Copyright (c) 2016 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
 */

(function() {
  'use strict';

  // フィールドに値を設定
  const createFieldValue = function(fieldtype, value) {
    let valText = value;
    if ((fieldtype === 'NUMBER') && (value === null)) {
      valText = 0;
    }
    return {
      type: fieldtype,
      value: valText
    };
  };

  // アンカーを生成
  const createAnchorTtile = function(url, value, target) {
    const anchor = document.createElement('a');
    anchor.setAttribute('href', url);
    anchor.setAttribute('target', target);
    anchor.innerText = value;
    return anchor.outerHTML;
  };

  // イベントデータをテーブルに設定
  const setEventsData = function(event) {
    const record = event.record;
    const keyword = record.Keyword.value;
    const date = record.Date.value;
    if (!keyword) {
      return null;
    }

    // キーワード値はエンコードしておく(connpass仕様)
    let palam = 'keyword=' + encodeURIComponent(keyword);
    if (date) {
      // 検索対象の日付の変換(connpass仕様)
      palam += '&ymd=' + encodeURIComponent(date.replace(/-/g, ''));
    }

    // 外部APIの結果を待ってテーブル書き込むため、Promiseを利用
    return new kintone.Promise((resolve, reject) => {

      const url = 'https://connpass.com/api/v1/event/?' + palam + '&order=2&count=100';
      // 外部APIを実行するためのkintone.proxy
      kintone.proxy(url, 'GET', {}, {}).then((args) => {

        if (args[1] !== 200) {
          return event;
        }

        // Promiseによって完了される引数を渡す
        resolve(JSON.parse(args[0]));

      }, (error) => {
        event.error = error;
        resolve(event);
      });

      // 実行結果を処理する
    }).then((resp) => {
      // 検索結果0の時はエラー
      if (resp.events.length < 1) {
        event.error = '検索結果が0件でした。\nキーワードを再指定してください。';
        return event;
      }

      // テーブルの初期化
      record.Table.value = [];
      for (let i = 0; resp.events.length > i; i++) {

        // テーブル行内のフィールド値はオブジェクト宣言
        const tableFields = {};
        tableFields.Title = createFieldValue('SINGLE_LINE_TEXT',
          createAnchorTtile(resp.events[i].event_url, resp.events[i].title, '_blank'));
        tableFields.StartDateTime = createFieldValue('DATETIME', resp.events[i].started_at);
        tableFields.EndDateTime = createFieldValue('DATETIME', resp.events[i].ended_at);
        const Accepted = parseInt(createFieldValue('NUMBER', resp.events[i].accepted).value, 10) +
                parseInt(createFieldValue('NUMBER', resp.events[i].waiting).value, 10);
        tableFields.Accepted = createFieldValue('NUMBER', Accepted);
        tableFields.Limit = createFieldValue('NUMBER', resp.events[i].limit);
        tableFields.SubTitle = createFieldValue('SINGLE_LINE_TEXT', resp.events[i].title);

        // テーブルに追加
        record.Table.value.push({value: tableFields});
      }
      record.EventCount.value = resp.results_available;
      return event;

    }).catch((error) => {
      event.error = 'エラーが発生しました。';
      return event;
    });
  };

  // イベントデータをクリアにする
  const clearEventsData = function(event) {
    const record = event.record;
    // テーブル、フィールド値の初期化
    record.Table.value = [];
    record.EventCount.value = 0;
    return event;
  };

  const evSubmit = [
    'app.record.index.edit.submit',
    'app.record.create.submit', 'app.record.edit.submit'
  ];
  kintone.events.on(evSubmit, setEventsData);

  const evShow = [
    'app.record.index.edit.show', 'app.record.create.show'
  ];
  kintone.events.on(evShow, clearEventsData);

})();

解説(ハマるポイント)

テーブル行への値設定
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// フィールドに値を設定
const createFieldValue = function(fieldtype, value) {
  let valText = value;
  if ((fieldtype === 'NUMBER') && (value === null)) {
    valText = 0;
  }
  return {
    type: fieldtype,
    value: valText
  };
};

数値フィールドが空白の場合、グラフで正常に集計されないため「0」を指定しています。
テーブルに値を追加する際には、値の他にフィールドタイプを指定(仕様)しています。

外部 API 実行後の Promise を利用
 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
// 外部APIの結果を待ってテーブル書き込むため、Promiseを利用
const setEventsData = function(event) {
  return new kintone.Promise((resolve, reject) => {
    const url = 'https://connpass.com/api/v1/event/?' + palam + '&order=2&count=100';
    // 外部APIを実行するためのkintone.proxy
    kintone.proxy(url, 'GET', {}, {}).then((args) => {
      if (args[1] !== 200) {
        return event;
      }
      // Promiseによって完了される引数を渡す
      resolve(JSON.parse(args[0]));

    }, (error) => {
      event.error = error;
      resolve(event);
    });

    // 実行結果を処理する
  }).then((resp) => {
    // 詳細は省略
    return event;

  }).catch((error) => {
    event.error = 'エラーが発生しました。';
    return event;
  });
};

外部 API の実行結果を反映するために、kintone.Promise を利用します。
以下は、この関数を使うとよい利点です。

  • XHR による同期リクエストは非推奨となっている。
    Firefox 等ではコンソールに警告が表示されます。
  • Internet Explorer ではまったくネイティブで Promise がサポートされていない。

kintone.Promise を使う際には、最低限次の記述も付けましょう。

  • then: 実行結果を処理する。
  • catch: 実行失敗時を処理する。

まとめ

勉強会では集客が気になるところですので、このように公開されている API を利用し、kintone に貯めることで、さまざまな確度からの分析ができると思います。
ただ、毎日手動で登録していたので、定期実行が kintone で実現できるとよいですね。