他人の予定表を取得するアプリ
- Power Appsでよく出てくる方法はOutlookコネクタの「FindMeetingTimesV2」
- この方法のデメリットは、空き時間しか分からない、他人が会議に返答していないと空き時間扱いになる
- そこで、Graph APIを使ってOutlookと同じく会議の開始~終了の時間や参加の情報まで一覧で取得します。
- 例えば以下のように表示します。 工夫すればガントチャート表示もできると思います。
Outlookの予定表のアクセス権
デスクトップアプリの画面では、以下のような4段階のアクセス権があります。
既定では他人からタイトルと場所の表示が可能です。組織によっては共有相手が自組織の配下に制限されている場合もあります。
アクセス権と予定の取得方法を整理すると
- Power AppsのOutlookコネクタでは、他人の予定が見えるのは空き時間のみのようです
- 他人のメールアドレスを指定して予定を見るには、GraphAPIを使う必要がありそうです
- 間違ってたらごめんなさい
予定表のアクセス権 | 他人から見える情報 | Outlookコネクタ | Graph API |
---|---|---|---|
空き時間情報の表示が可能 | 空き時間の表示 | FindMeetingTimesV2 | findMeetingTimes |
タイトルと場所の表示が可能(既定) | 会議時間、場所、タイトル | 他人の予定は不可 | getSchedule |
全ての詳細を表示可能(本文を含む) | 上記に加えて本文 | 他人の予定は不可 | events |
Graph APIとGetSucheduleエンドポイント
- 以下のドキュメントの通りです
- 予定表を見たい相手のカレンダーが自分に対して「タイトルと場所の表示が可能」で共有されていることが前提ですが、Outlookのように詳細な情報が取得できます
要求の例
- メールアドレスアドレスと、開始時間、終了時間、時間間隔を指定します
POST https://graph.microsoft.com/v1.0/me/calendar/getSchedule
Content-Type: application/json
{
"schedules": ["adelev@contoso.com", "meganb@contoso.com"],
"startTime": {
"dateTime": "2019-03-15T09:00:00",
"timeZone": "Tokyo Standard Time"
},
"endTime": {
"dateTime": "2019-03-15T18:00:00",
"timeZone": "Tokyo Standard Time"
},
"availabilityViewInterval": 30
}
応答の例
- ユーザーのスケジュールID、スケジュールアイテムが配列で返されます
- 会議の応答ステータス、件名、場所、時間の情報が見えます
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(microsoft.graph.scheduleInformation)",
"value": [
{
"scheduleId": "adelev@contoso.com",
"availabilityView": "000220000",
"scheduleItems": [
{
"isPrivate": false,
"status": "busy",
"subject": "Let's go for lunch",
"location": "Harry's Bar",
"start": {
"dateTime": "2019-03-15T12:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-03-15T14:00:00.0000000",
"timeZone": "Pacific Standard Time"
}
}
],
"一部省略": {
}
}
]
}
Power AutomateとGraph APIで他人の予定を取得する
- 直接Power Appsから呼び出すと応答JSONの解析が面倒そうなので、一旦Power Automateで前処理します
- 最近登場したユーザー定義型変数に期待?
フロー全体像
解説
抜粋して解説します。
トリガー
Graph APIの呼び出し
JSONをフラットに変換してアプリで扱いやすくする
JSONの解析
- GraphAPIの応答を、JSONの解析で加工しやすくしておきます
- スキーマは一工夫が必要です
- 予定がPrivateだとsubjectなどがnullになるので許容するよう変更が必要です
スキーマ
{
"type": "array",
"items": {
"type": "object",
"properties": {
"scheduleId": {
"type": "string"
},
"availabilityView": {
"type": "string"
},
"scheduleItems": {
"type": "array",
"items": {
"type": "object",
"properties": {
"isPrivate": {
"type": [
"boolean",
"null"
]
},
"status": {
"type": "string"
},
"subject": {
"type": [
"string",
"null"
]
},
"location": {
"type": [
"string",
"null"
]
},
"isMeeting": {
"type": [
"boolean",
"null"
]
},
"isRecurring": {
"type": [
"boolean",
"null"
]
},
"isException": {
"type": [
"boolean",
"null"
]
},
"isReminderSet": {
"type": [
"boolean",
"null"
]
},
"start": {
"type": "object",
"properties": {
"dateTime": {
"type": "string"
},
"timeZone": {
"type": "string"
}
}
},
"end": {
"type": "object",
"properties": {
"dateTime": {
"type": "string"
},
"timeZone": {
"type": "string"
}
}
}
},
"required": [
"status",
"start",
"end"
]
}
},
"workingHours": {
"type": "object",
"properties": {
"daysOfWeek": {
"type": "array",
"items": {
"type": "string"
}
},
"startTime": {
"type": "string"
},
"endTime": {
"type": "string"
},
"timeZone": {
"type": "object",
"properties": {
"name": {
"type": "string"
}
}
}
}
}
},
"required": [
"scheduleId",
"availabilityView",
"scheduleItems",
"workingHours"
]
}
}
Apply to Eachを入れ子にして、scheduleItemsを配列に格納していく
- scheduleIdとscheduleItemsの要素がフラットになるように配列変数に追加していきます
作成の数式
{
"scheduleId": @{items('Apply_to_each:本文')['scheduleId']},
"status": @{items('Apply_to_each:Items')['status']},
"subject": @{coalesce(items('Apply_to_each:Items')?['subject'], '-')},
"location": @{coalesce(items('Apply_to_each:Items')?['location'], '')},
"start": @{items('Apply_to_each:Items')?['start']?['dateTime']},
"end": @{items('Apply_to_each:Items')?['end']?['dateTime']}
}
最後はアプリに応答します
Power Appsから呼び出す
- 以下の数式でPower Automateを呼び出します
- colSchedulesにスケジュール一覧がセットされるので、任意の形式で表示します
- 以下の例で_userEmailに他人のEmailが入るようにします
- カンマ区切りで指定すると複数ユーザーの予定を取得できると思います
// 8時~22時の時間テキスト
UpdateContext(
{
_startDatetimeJST : Text(DatePicker1.SelectedDate,"yyyy-mm-dd") & "T08:00:00",
_endDatetimeJST : Text( DatePicker1.SelectedDate,"yyyy-mm-dd") & "T22:00:00"
}
);
// スケジュールを取得
ClearCollect(
colSchedules,
ForAll(
// フローを実行してParseJson
Table(ParseJSON(
Outlook_スケジュールを取得.Run(_userEmail, _startDatetimeJST,_endDatetimeJST).value
)),
// 匿名型を型オブジェクトにマッピング
{
scheduleId: Text(ThisRecord.Value.scheduleId),
subject: Text(ThisRecord.Value.subject),
location: Text(ThisRecord.Value.location),
status: Text(ThisRecord.Value.status),
start: DateAdd( DateTimeValue(ThisRecord.Value.start), 9,TimeUnit.Hours) ,
end: DateAdd( DateTimeValue(ThisRecord.Value.end), 9,TimeUnit.Hours)
}
)
);
If(IsEmpty(colSchedules),Notify("本日のスケジュールは一件も見つかりませんでした。",NotificationType.Information,2000))