LoginSignup
2
4

More than 3 years have passed since last update.

Slackでの勤怠入力でAPI経由でOutlookの予定表にイベントを追加するメモ

Last updated at Posted at 2021-01-25

できたことダイジェスト

image.png
image.png

ここまでのお話

前回といってもかなり前の話ですが、Slackで勤怠管理して可視化するということをやって、会社のグループ単位でYellowfin(BIツール)のダッシュボードを確認して勤怠を確認できるようにしました。(もし下記にあるコードを参照するならこの記事も確認してもらえると読みやすいと思います。)
その時スケジュール管理ツールにaipoを使っていたので、休日や半休等の場合、aipoのDBに直接アクセスして予定をinsert,update,deleteしていたのですが、オープンソースでの提供が終わりセキュリティ的にも懸念があることからOutlookへ移行しました。
一覧でグループの人の予定が見れないとか色々ありましたが、先述したSlack投稿での勤怠管理での休み登録で予定表に追加されないため手動でOutlookの予定表に休みを登録しなければならずめんどい、という声が多数でどうにかならないかなと感じでいたところでした。
そこでOutlookにもなにかAPIがあるはずで予定の登録くらいはできるだろうと調べ始めましたが、ドキュメントが見分けられずかなり大変でした。
実際には予定の登録ができたのですが、未検証の部分も多いので個人用のメモとして残しておきます。

Outlook予定表にイベントを登録するまでの課題(めんどかったこと)

大体一覧にすると、こんな感じです。
・Microsoftの関連ページがありすぎてどれを参考にしていいかわからない。
・認証方式やAPIの種類が豊富すぎて何を使えばいいかわからない。
・公式のページが多すぎてQiitaの記事や個人のBlogなどの情報が見つかりづらい
と、やる前から萎える感じの状態なのですが、AccessToken取得してPOSTするだけ(だと思う)なのになんでこんな分かりづらいんだと、たくさんの公式ドキュメントで関係ありそうなところを見まくりました。

必要だったこと

前置きが長くなりましたが、ここからAPIを通じてイベントを予定表に追加するための準備です。

Azure Active Directoryでアプリを登録する(Microsoft Azure Portalにログイン後) 。

ここでアプリの登録→新規登録を選択します。
image.png
名前をつけて登録ボタンを押下します。ここではリダイレクトURIはいらないと思います。
image.png

アプリの登録画面に戻ると追加したアプリケーションが表示されているので選択する。

ここで重要なのはアプリケーション(クライアントID)とディレクトリ(テナント)です。後に使うのでコピーしておきます。
image.png

証明書とシークレットを押下してクライアントシークレットを作成する。

新しいクライアントシークレットを押下して説明を入力し、有効期限を選択して追加を行う。
この時に生成されるクライアントシークレットの値も後に使うのでコピーしておきます。
image.png

APIのアクセス許可を押下して今回必要なカレンダー(予定表)へのアクセスができるようにする。

ここでアクセス許可の追加を押下してCalendars.ReadWriteを追加する。この時Azure,Office365の管理者ではない場合、管理者にこのアクセス許可の内容について同意が必要になるので適宜申請なりして許可をとってください。
※他にもCalendars.ReadやMail.Send、User.Readを追加していますが今回はおそらくいりません。
image.png
アクセス許可の追加押下後、Microsoft Graphを選択する。その後、アクセス許可の種類を選択する画面がでますが、今回はサインインするユーザーなしで多人数のカレンダーに予定を追加するので、アプリケーションの許可を選択します。
image.png
その後、アクセス許可の種類を選択する画面がでますが、今回はサインインするユーザーなしで多人数のカレンダーに予定を追加するので、アプリケーションの許可を選択します。
ここで必要な権限Calendars.ReadWriteにチェックを入れアクセス許可の追加をします。
image.png

認証を押下してトークンの種類を選択する。

アクセストークン、IDトークンにチェックを入れます。また、パブリッククライアント フローを許可するではいを選択します。
※実際はアクセストークンのチェックだけでよいかもしれません。。またパブリッククライアントフローの許可も厳密に検証していません。すみません。
image.png

ここまできたらアプリ自体の登録は完了です!

実際のコーディング

ここまでの準備でAccessTokenの取得や、イベントの追加をAPI経由でできるようになっているので、そこにアクセスするためのコーディングを行います。
逐次説明が大変なので、コメントでフォローしました。クライアントID、クライアントシークレット、テナントとDB情報は置き換えてください。
途中でDBに接続してSlackの名前から、メールアドレス(ログインID)とOffice365の表示名を取得しています。
イベント追加時のURLですが、公式ドキュメントでは「POST /users/{id | userPrincipalName}/events」となっており、userPrincipalNameというのがログインID(メールアドレス)であるため、それをイベントを追加する人ごとに分ける感じです。

addEvent.php
/**
 * Outlookへの休日登録
 * @param  string  $text        確認する文字列
 * @param  string  $user        Slackユーザー名
 * @param  date $date      対象日付(Y-m-d)
 * @param  time $hhdstart  対象日時(H:i:00)
 * @param  time $hhdend    対象日時(H:i:00)
 *
 * @return boolean
 */

function toOutlook($text,$user,$date,$hhdstart,$hhdend){
    global $wdsn,$wdbuser,$wpass;//PDOを使ったDBアクセスをしているので設定を適宜置き換えてください
    $CURLERR = NULL;

    $data = array(
        'client_id' => 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX',//クライアントID
        'scope' => 'https://graph.microsoft.com/.default',
        'client_secret' => 'XXXXXXXXXXXXXXXXXXXXXXXXX',//クライアントシークレット
        'grant_type' => 'client_credentials',
    );

    $url = 'https://login.microsoftonline.com/XXXXXXXXXXXXXXXXXXXXXXX/oauth2/v2.0/token';//XXXをテナントで置換する

    $ch = curl_init($url);

    curl_setopt($ch, CURLOPT_POST, TRUE);                            //POSTで送信
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));    //データをセット
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);                    //受け取ったデータを変数に
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
    $html = curl_exec($ch);

    if(curl_errno($ch)){        //curlでエラー発生
        $CURLERR .= 'curl_errno:' . curl_errno($ch) . "\n";
        $CURLERR .= 'curl_error:' . curl_error($ch) . "\n";
        $CURLERR .= '▼curl_getinfo' . "\n";
        foreach(curl_getinfo($ch) as $key => $val){
            $CURLERR .= '■' . $key . ':' . $val . "\n";
        }
        echo nl2br($CURLERR);
    }
    curl_close($ch);

    $res = json_decode($html,true);//レスポンスJsonにアクセスできるようにする。$res['access_token']がアクセストークン

    $name = $user;
    $loginId = '';
    $fullname = '';

    try {
        $upsert_pdo = new PDO(
            $wdsn,
            $wdbuser,
            $wpass,
            array(
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES => false,
            )
        );

        $sql = 'SELECT mailaddress,ename FROM ユーザーテーブル名 WHERE nname = \''.$name.'\'';//Slackの登録名からmailaddressとOffice365の登録名を取得する
        $result = $upsert_pdo->query($sql);
        foreach ($result as $row) {

            $loginId = $row['mailaddress'];
            $fullname = $row['ename'];

            $CURLERR = NULL;

            $data = array(
                'subject' => "${text}",
                'body' => array('contentType' => 'HTML','content' => "${text}です。"),
                'start' => array('dateTime' => "${date}T${hhdstart}",'timeZone' => 'Asia/Tokyo'),
                'end' => array('dateTime' => "${date}T${hhdend}",'timeZone' => 'Asia/Tokyo'),
                'attendees' => array(array('emailAddress' => array('address' => $loginId,'name' => $fullname)),array('type' => 'required')),
            );
            $data = json_encode($data,JSON_UNESCAPED_UNICODE);
            $url = 'https://graph.microsoft.com/v1.0/users/'.$loginId.'/events';//登録するユーザーのメールアドレスがURLに必要になります。

            $ch = curl_init($url);

            curl_setopt($ch, CURLOPT_POST, TRUE);                            //POSTで送信
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);    //データをセット
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);                    //受け取ったデータを変数に
            curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json','Authorization: Bearer '.$res['access_token']));
            $html = curl_exec($ch);//ここでAPIを通じてイベントが登録されます。

            if(curl_errno($ch)){        //curlでエラー発生
                $CURLERR .= 'curl_errno:' . curl_errno($ch) . "\n";
                $CURLERR .= 'curl_error:' . curl_error($ch) . "\n";
                $CURLERR .= '▼curl_getinfo' . "\n";
                foreach(curl_getinfo($ch) as $key => $val){
                    $CURLERR .= '■' . $key . ':' . $val . "\n";
                }
                error_log(nl2br($CURLERR),0);
            }
            curl_close($ch);

        }
    } catch (PDOException $e) {
        // 外側のTryブロックに対してスロー
        throw $e;
        return FALSE;
    }

}

感想

最初はとてつもなく大きなものに立ち向かっていく感があったのですが、こうして書いてみると、わかっていればすぐなんでしょうね。。。もうちょっとドキュメントの読解力を磨きます。

参考にしたサイト様

Outlook カレンダー API の概要
イベントを作成する
dateTimeTimeZone リソースの種類
event リソースの種類
ユーザーなしでアクセスを取得
Microsoft ID プラットフォーム エンドポイントでのアクセス許可と同意
Microsoft ID プラットフォームのアプリケーションの種類
Microsoft Outlook API で遊ぶ
PostMan を使った Graph API の始め方
AzureでAccessTokenを取得する方法

2
4
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
2
4