kintoneとOutlookを連携してスケジュール管理をする#02

## 経緯
kintoneのOutlookを連携してスケジュール管理をしたい。
けど検索して出てくる記事が古いため、アレンジしてなるべく最新のものに対応する。

要するに「[Outlook連携 - kintoneからOutlookスケジュールを登録しよう！！](https://developer.cybozu.io/hc/ja/articles/360022249111-Outlook%E9%80%A3%E6%90%BA-kintone%E3%81%8B%E3%82%89Outlook%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%82%92%E7%99%BB%E9%8C%B2%E3%81%97%E3%82%88%E3%81%86-)」のOutlook連携をほぼサンプルのまま使っていたのだけど、先日急に動かなくなったので最新化対応したいということ。

### やりたいこと
- MSAL v2 に対応してkintoneとOutlookのスケジュールを連携させたい。
- kintone UI Component v1 対応したUIを構築したい。
- FullCalendar.js を導入してカレンダー表示させたい。

## 参考サンプル
こちらの２つのサンプルを参考にOutlook連携カスタマイズを行います。
1. [Outlook連携 - kintoneからOutlookスケジュールを登録しよう！！](https://developer.cybozu.io/hc/ja/articles/360022249111-Outlook%E9%80%A3%E6%90%BA-kintone%E3%81%8B%E3%82%89Outlook%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%82%92%E7%99%BB%E9%8C%B2%E3%81%97%E3%82%88%E3%81%86-)
2. [クイックスタート: PKCE 対応の承認コード フローを使用して JavaScript SPA 内でユーザーをサインインさせ、アクセス トークンを取得する](https://docs.microsoft.com/ja-jp/azure/active-directory/develop/quickstart-v2-javascript-auth-code)

## 今回（本記事）のゴール
AzureADで認証しサインインする。

## 記事一覧
1. [#01.ボタンを表示](https://qiita.com/iNaoki04/items/237f3828d103a8dc684e)
2. #02.サインイン ← 当記事
3. [#03.サインアウトとボタン表示制御](https://qiita.com/iNaoki04/items/059ef1d51f567416eb25)

## AzureADの設定
「[クイックスタート: PKCE 対応の承認コード フローを使用して JavaScript SPA 内でユーザーをサインインさせ、アクセス トークンを取得する](https://docs.microsoft.com/ja-jp/azure/active-directory/develop/quickstart-v2-javascript-auth-code)」の記事を見て環境を構築し、サンプルを実際に動かしてサインインできることを確認します。

認証の設定でプラットフォームは「シングルページ アプリケーション」でリダイレクトURIを設定します。
サンプルを動かして認証を確認するのであれば「 http://localhost:3000/ 」が設定されていれば大丈夫です。
kintoneに実装する際は、アプリのURLを追加で設定します。
![ninsyo.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126147/b7a6c2e7-8227-f845-4678-00445c850c0c.png)

MSAL v2 では暗黙的な許可を使用しないので、チェックはしないでください。
※MSAL v1 では両方にチェックを入れます。
![setting.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126147/da921948-4531-5b53-dbf2-0478efbc07af.png)

サンプルを動かし、サインインボタンを押してサインインできれば環境構築はOKです。
サンプルはAzureADのクイックスタートから入手すると諸々設定済みなので確認が簡単です。
![start.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126147/f7077f5a-533e-8366-ea75-62ef1c2feecd.png)

![login.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126147/30501f76-a3f7-9f0a-4944-7cdca4cd0969.png)

## サインイン処理を実装する
Microsoftのサンプルをそのまま動くように実装します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126147/df7da568-a8f4-d5bc-21cc-58251fbc24d5.png)

### javascript
1. https://unpkg.com/kintone-ui-component/umd/kuc.min.js
2. https://js.cybozu.com/jquery/3.3.1/jquery.min.js
3. https://alcdn.msauth.net/browser/2.13.1/js/msal-browser.js ← ★追加
4. authConfig.js ← ★追加
5. authPopup.js ← ★追加
6. buttonSettings.js
7. ui.js

### css
1. buttons.css

## ボタンに処理を登録

サインインボタン作成時にボタン押下時の処理を登録します。
実行する処理は authPopup.js の signIn() です。

```ui.js
// ボタンの表示情報を取得
let BS = window.buttonSettings;

// カスタマイズのメイン処理
let uiService = {
    setting: {
        lang: {},
        i18n: {},
        ui: {}
    },
    data: {
        ui: {},
    },

    // 初期処理
    init: function () {
        // ログインユーザーの言語設定を取得
        this.setting.lang = kintone.getLoginUser().language || 'ja';
        this.setting.i18n = this.setting.lang in BS.lang ? BS.lang[this.setting.lang] : BS.lang.en;
        this.setting.ui = BS.setting.ui;
    },

    // ボタン表示設定
    uiNotSignCreateForIndex: function (kintoneHeaderSpace) {
        if (typeof kintoneHeaderSpace === 'undefined') {
            return;
        }

        // サインイン前のボタン表示
        this.data.ui.HeaderNotSigned = document.createElement('div');
        // ボタンを作成
        this.data.ui.btnSignIn = this.createButton(this.setting.ui.buttons.signIn, this.setting.i18n.button);
        // サインインボタン押下時の処理を登録
        this.data.ui.btnSignIn.addEventListener('click', function (event) {
            authPopupService.signIn();
        });
        // ボタンを表示用に格納
        this.data.ui.HeaderNotSigned.appendChild(this.data.ui.btnSignIn);
        kintoneHeaderSpace.appendChild(this.data.ui.HeaderNotSigned);
    },

    // ボタンを作成
    createButton: function (setting, lang) {
        if (typeof setting === 'undefined' || !setting) {
            return null;
        }

        let uiButton;
        let text = lang ? lang[setting.text] || setting.text || '' : setting.text || '';
        let type = setting.type;
        let className = setting.className ? setting.className : '';

        uiButton = new Kuc.Button({ text: text, type: type, className: className });
        return uiButton;
    },
};

// 画面表示時イベント
kintone.events.on('app.record.index.show', function (event) {
    // 初期処理
    uiService.init();
    // サインインボタン表示
    uiService.uiNotSignCreateForIndex(kintone.app.getHeaderSpaceElement());
});
```


## 認証プログラムの実装
Microsoftのサンプルをそのまま使います。
やることは認証情報を設定して `loginPopup` をしているだけです。
authConfig.js の redirectUri には実装するkintoneアプリのURLを設定してください。
※AzureADのリダイレクトURIにも同じURLを設定してください。

```authConfig.js
const msalConfig = {
    auth: {
        clientId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        authority: "https://login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        redirectUri: "https://xxx.cybozu.com/k/xxx/",
    },
    cache: {
        cacheLocation: "sessionStorage",
        storeAuthStateInCookie: false,
    },
    system: {
        loggezrOptions: {	
            loggerCallback: (level, message, containsPii) => {	
                if (containsPii) {		
                    return;		
                }		
                switch (level) {		
                    case msal.LogLevel.Error:		
                        console.error(message);		
                        return;		
                    case msal.LogLevel.Info:		
                        console.info(message);		
                        return;		
                    case msal.LogLevel.Verbose:		
                        console.debug(message);		
                        return;		
                    case msal.LogLevel.Warning:		
                        console.warn(message);		
                        return;		
                }	
            }	
        }	
    }
};

const loginRequest = {
    scopes: ["User.Read"]
};
```

authPopup.js は基本そのままいいですが、ログインに成功したことを確認するためコンソールにメッセージを出力するよう追加しています。


```authPopup.js
const myMSALObj = new msal.PublicClientApplication(msalConfig);

let username = "";

let authPopupService = {
    // ログイン情報による制御
    selectAccount: function() {
        const currentAccounts = myMSALObj.getAllAccounts();
        if (currentAccounts.length === 0) {
            return;
        } else if (currentAccounts.length > 1) {
            console.warn("Multiple accounts detected.");
        } else if (currentAccounts.length === 1) {
            username = currentAccounts[0].username;
            console.log(username);
        }
    },

    //サインイン後の処理
    handleResponse: function(response) {
        if (response !== null) {
            username = response.account.username;
            // 認証の成功を確認
            console.log("succsess");
            console.log(username);
        } else {
            this.selectAccount();
        }
    },

    // サインイン
    signIn: function() {
        myMSALObj.loginPopup(loginRequest)
            .then(this.handleResponse)
            .catch(error => {
                console.error(error);
            });
    },
}
```

## 実装できたらボタンを押下して確認
kintone画面のボタンを押下するとログイン画面が表示されます。
ログインを行い、認証に成功するとコンソールにメッセージ（ログインユーザーのメールアドレス）が表示されることが確認できます。

![cons.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126147/c83a4075-ef6b-f9e9-bf40-fc96d995d66f.png)

認証まで成功すれば、あとはその後にやりたい処理を加えていくだけです。

## 次回
サインアウトとボタン表示制御