6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

cybozu.com に登録されているユーザーの情報を、kintone アプリに同期する。

Last updated at Posted at 2020-06-19

0.はじめに

cybozu.com に登録されているユーザー情報の一覧を、kintone アプリで、簡単に取得したかったので、やってみました。

1. kintone アプリに JavaScript ライブラリ (reloadCybozuUsers.js) を追加する。

  1. まずは、kintone アプリの「アプリの設定」を開きます。


  2. 「設定」タブを選択し、「カスタマイズ/サービス連携」→「JavaScript / CSSでカスタマイズ」を開きます。


  3. 以下の JavaScript ライブラリを追加します。

    reloadCybozuUsers.js
    /*
    cybozu.com ユーザー一覧更新処理
    */
    
    // kintone API – cybozu developer network
    //https://developer.cybozu.io/hc/ja/articles/360028177472
    
    // PromiseがわからないのでAsync/Awaitを使う - Qiita
    // https://qiita.com/_muraham/items/697e1d53a09ff40530e5
    
    // プログレスバーを簡単に実装できるprogressbar.js - bagelee(ベーグリー)
    // https://bagelee.com/design/javascript/create_progress_bars_with_progressbarjs/
    
    // https://rawgit.com/kimmobrunfeldt/progressbar.js/master/dist/progressbar.js
    // https://rawgit.com/kimmobrunfeldt/progressbar.js/master/dist/progressbar.min.js
    
    (function() {
        "use strict";
        kintone.events.on('app.record.index.show', function(event) {
            var myProgressDiv = document.createElement('div');
            myProgressDiv.id = "my_progress_container";
            //myProgressDiv.style.backgroundColor = 'red';
            myProgressDiv.style.width = '600px';
            myProgressDiv.style.height = '8px';
            if (document.getElementById('my_index_button') !== null) {
                return;
            }
            var myIndexButton = document.createElement('button');
            myIndexButton.id = 'my_index_button';
            myIndexButton.innerText = ' 更  新 ';
            myIndexButton.onclick = async function() {
                var bar = new ProgressBar.Line(my_progress_container, {
                    strokeWidth: 4,
                    easing: 'easeInOut',
                    duration: 100,
                    color: '#FFEA82',
                    trailColor: '#eee',
                    trailWidth: 1,
                    svgStyle: {width: '100%', height: '100%'},
                    text: {
                        style: {
                            color: '#999',
                            position: 'relative',
                            left: '560px',
                            top: '-70px',
                            padding: 0,
                            margin: 0,
                            transform: null
                        },
                        autoStyleContainer: false
                    },
                    from: {color: '#FFEA82'},
                    to: {color: '#ED6A5A'},
                    step: (state, bar) => {
                        bar.path.setAttribute('stroke', state.color);
                        bar.setText(Math.round(bar.value() * 100) + ' %');
                    }
                });
                //console.log(event.records);
                var respUsers = await kintone.api(kintone.api.url('/v1/users', true), 'GET', {});
                //console.log(respUsers);
                var respRecords = await kintone.api(kintone.api.url('/k/v1/records', true), 'GET', {
                    'app': kintone.app.getId()
                });
                //console.log(respRecords);
                var recordIDs = {};
                var postRecords = [];
                var putRecords = [];
                for(let i = 0; i < respRecords.records.length; i++) {
                    recordIDs[respRecords.records[i]['$id']['value']] = {
                        'userid': respRecords.records[i]['id']['value'],
                        'idx': i
                    }
                }
                //console.log(recordIDs);
                for(let i = 0; i < respUsers.users.length; i++) {
                    bar.animate(i/respUsers.users.length);
                    var respUserOrgs = await kintone.api(kintone.api.url('/v1/user/organizations', true), 'GET', {
                        'code': respUsers.users[i]['code']
                    });
                    //console.log(respUserOrgs);
                    var organizations = []
                    for(let ii = 0; ii < respUserOrgs['organizationTitles'].length; ii++) {
                        organizations.push({
                            'code': respUserOrgs['organizationTitles'][ii]['organization']['code'],
                            'name': respUserOrgs['organizationTitles'][ii]['organization']['name']
                        });
                    }
                    let record = {};
                    record['id'] = {'value': respUsers.users[i]['id']}
                    record['name'] = {'value': respUsers.users[i]['name']}
                    record['surName'] = {'value': respUsers.users[i]['surName']}
                    record['givenName'] = {'value': respUsers.users[i]['givenName']}
                    record['surNameReading'] = {'value': respUsers.users[i]['surNameReading']}
                    record['givenNameReading'] = {'value': respUsers.users[i]['givenNameReading']}
                    record['code'] = {'value': respUsers.users[i]['code']}
                    record['email'] = {'value': respUsers.users[i]['email']}
                    if (respUsers.users[i]['valid']) {
                        record['valid'] = {'value': ['使用中']}
                    } else {
                        record['valid'] = {'value': []}
                    }
                    record['organizations'] = {'value': organizations}
                    record['primaryOrganization'] = {'value': respUsers.users[i]['primaryOrganization']}
                    record['phone'] = {'value': respUsers.users[i]['phone']}
                    record['url'] = {'value': respUsers.users[i]['url']}
                    //
                    record['callto'] = {'value': respUsers.users[i]['callto']}
                    record['mobilePhone'] = {'value': respUsers.users[i]['mobilePhone']}
                    record['locale'] = {'value': respUsers.users[i]['locale']}
                    record['timezone'] = {'value': respUsers.users[i]['timezone']}
                    record['localNameLocale'] = {'value': respUsers.users[i]['localNameLocale']}
                    record['localName'] = {'value': respUsers.users[i]['localName']}
                    //
                    record['employeeNumber'] = {'value': respUsers.users[i]['employeeNumber']}
                    record['joinDate'] = {'value': respUsers.users[i]['joinDate']}
                    record['birthDate'] = {'value': respUsers.users[i]['birthDate']}
                    record['sortOrder'] = {'value': respUsers.users[i]['sortOrder']}
                    record['description'] = {'value': respUsers.users[i]['description']}
                    //
                    record['customItemValues'] = {'value': respUsers.users[i]['customItemValues']}
                    record['extensionNumber'] = {'value': respUsers.users[i]['extensionNumber']}
                    //
                    record['ctime'] = {'value': respUsers.users[i]['ctime']}
                    record['mtime'] = {'value': respUsers.users[i]['mtime']}
                    //console.log(record);
                    var matchRecordIDs = []
                    Object.keys(recordIDs).forEach(function(key) {
                        if (this[key]['userid'] == respUsers.users[i]['id']) {
                            matchRecordIDs.push({
                                'key': key,
                                'idx': this[key]['idx']
                            });
                        }
                    }, recordIDs);
                    //console.log(matchRecordIDs);
                    if (matchRecordIDs.length > 0) {
                        //console.log(respRecords.records[matchRecordIDs[0]['idx']]);
                        if (record['id']['value'] != respRecords.records[matchRecordIDs[0]['idx']]['id']['value']
                        || record['name']['value'] != respRecords.records[matchRecordIDs[0]['idx']]['name']['value']
                        || record['surName']['value'] != respRecords.records[matchRecordIDs[0]['idx']]['surName']['value']
                        || record['givenName']['value'] != respRecords.records[matchRecordIDs[0]['idx']]['givenName']['value']
                        || record['surNameReading']['value'] != respRecords.records[matchRecordIDs[0]['idx']]['surNameReading']['value']
                        || record['givenNameReading']['value'] != respRecords.records[matchRecordIDs[0]['idx']]['givenNameReading']['value']
                        || record['valid']['value'] != respRecords.records[matchRecordIDs[0]['idx']]['valid']['value']
                        || record['code']['value'] != respRecords.records[matchRecordIDs[0]['idx']]['id']['code']
                        || record['email']['value'] != respRecords.records[matchRecordIDs[0]['idx']]['id']['email'] ) {
                            putRecords.push({'id': matchRecordIDs[0]['key'], 'record': record});
                        }
                        delete recordIDs[matchRecordIDs[0]['key']];
                    } else {
                        postRecords.push(record);
                    }
                }
                console.log("recordIDs :");
                //console.log(recordIDs);
                console.log(Object.keys(recordIDs));
                console.log("putRecords :");
                console.log(putRecords);
                console.log("postRecords :");
                console.log(postRecords);
                if (Object.keys(recordIDs).length > 0) {
                    var resp = await kintone.api(kintone.api.url('/k/v1/records', true), 'DELETE', {
                        'app': kintone.app.getId(),
                        'ids': Object.keys(recordIDs)
                    });
                }
                if (putRecords.length > 0) {
                    var resp = await kintone.api(kintone.api.url('/k/v1/records', true), 'PUT', {
                        'app': kintone.app.getId(),
                        'records': putRecords
                    });
                }
                if (postRecords.length > 0) {
                    var resp = await kintone.api(kintone.api.url('/k/v1/records', true), 'POST', {
                        'app': kintone.app.getId(),
                        'records': postRecords
                    });
                }
                bar.animate(1.0);
                location.reload();
                return event;
            };
            kintone.app.getHeaderMenuSpaceElement().appendChild(myIndexButton);
            kintone.app.getHeaderMenuSpaceElement().appendChild(myProgressDiv);
            //kintone.app.getHeaderSpaceElement().appendChild(myProgressDiv);
        });
    })();
    
<br>
    * ※ 以降は、コードの簡単な説明。
<br><br>
    * ユーザー情報の取得
        * [ユーザーエクスポートAPI – cybozu developer network](https://developer.cybozu.io/hc/ja/articles/202363040-%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%88API#step2)

    ```javascript
    var respUsers = await kintone.api(kintone.api.url('/v1/users', true), 'GET', {});
* アプリのレコード情報の取得
    * [レコードの取得(GET) – cybozu developer network](https://developer.cybozu.io/hc/ja/articles/202331474-%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E5%8F%96%E5%BE%97-GET-#step2)

```javascript
var respRecords = await kintone.api(kintone.api.url('/k/v1/records', true), 'GET', {
    'app': kintone.app.getId()
});
    * ユーザーの所属する組織情報の取得
        * [ユーザーの所属組織エクスポートAPI – cybozu developer network](https://developer.cybozu.io/hc/ja/articles/202124774#step2)

    ```javascript
    var respUserOrgs = await kintone.api(kintone.api.url('/v1/user/organizations', true), 'GET', {
        'code': respUsers.users[i]['code']
    });
* アプリのレコード情報の削除
    * [レコード削除(DELETE) – cybozu developer network](https://developer.cybozu.io/hc/ja/articles/201941794)

```javascript
var resp = await kintone.api(kintone.api.url('/k/v1/records', true), 'DELETE', {
    'app': kintone.app.getId(),
    'ids': Object.keys(recordIDs)
});
    * アプリのレコード情報の更新
        * [レコードの更新(PUT) – cybozu developer network](https://developer.cybozu.io/hc/ja/articles/201941784)

    ```javascript
    var resp = await kintone.api(kintone.api.url('/k/v1/records', true), 'PUT', {
        'app': kintone.app.getId(),
        'records': putRecords
    });
* アプリのレコード情報の登録
    * [レコードの登録(POST) – cybozu developer network](https://developer.cybozu.io/hc/ja/articles/202166160)

```javascript
var resp = await kintone.api(kintone.api.url('/k/v1/records', true), 'POST', {
    'app': kintone.app.getId(),
    'records': postRecords
});

# 2. [kintone](https://kintone.cybozu.co.jp/) アプリに JavaScript ライブラリ ([ProgressBar.js](https://kimmobrunfeldt.github.io/progressbar.js/#intro)) を追加する。

1. こちらの手順に従って、追加します。
    * [Kintone アプリにプログレスバーを表示してみる。 \- Qiita](https://qiita.com/kusokamayarou/items/70acde31d3fd4e790478#%EF%BC%91-kintone-%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AB-javascript-%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA-progressbarjs-%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B)

# 3. [kintone](https://kintone.cybozu.co.jp/) アプリにフォームを設定する。

1. 以下のデータ構造に合わせて、項目を追加します。
    * [User APIで使用するデータの構造 – cybozu developer network](https://developer.cybozu.io/hc/ja/articles/205309740)
        * ※ フィールドコードには、上記のデータ構造のキーを設定します。
        * ※ 上記のデータ構造の項目を全て追加しなくても、大丈夫です。
    * ![FireShot Capture 383 - アプリの設定 - genbasupport.cybozu.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161939/265f21c9-6cbf-9c10-8b82-8808cc91f697.png)

# 99.ハマりポイント

* ハマりポイントというか、そもそも [kintone](https://kintone.cybozu.co.jp/) アプリの JavaScript カスタマイズとか、HTML とか、JavaScript とかを普段あまりいじっておらず…、慣れてないので時間掛かっちゃいました…。
<br><br>
* Async/Await の使い方もよく知らなかったので、こちらの記事を参考にさせて頂きました。クロージャ使わないと、コードが綺麗になって見易くて Good !!!
    * [PromiseがわからないのでAsync/Awaitを使う \- Qiita](https://qiita.com/_muraham/items/697e1d53a09ff40530e5)
<br><br>
* あと、これは [kintone](https://kintone.cybozu.co.jp/) アプリの JavaScript カスタマイズでいつも困るんですが、POST や PUT の際の JSON フォーマットの形式ですね。いつもどの形式で登録するのかわからなくて、今回も結構ハマりました…。

# XX.まとめ

[cybozu\.com](https://www.cybozu.com/jp/) に登録されているユーザー情報について、組織によっては、全てのユーザー情報は見せられない、といった場合もあるかと思いますので、今回の Tips がそのまま使えるか難しい面もあるかと思いますが…。

参考になれば♪

👋👋👋
6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?