Open1

Google Calendar APIの知見

kboykboy

Flutter大学では、Google Calendar APIを使って、slackに毎日8時と18時にその日の予定を投稿している。

ある日、質問zoomの担当講師が代行になった時に、Google Calendarの繰り返し予定の1つのタイトルを変更した。

その時に変更前と変更後の2つ飛んでしまった。

今回要らない部分は省いてるが、レスポンスは下のような感じ。

{
 "items": [
  {
   "id": "6vr9tlqp0tejvq5q59guransg5",
   "status": "confirmed",
   "created": "2022-08-21T03:36:11.000Z",
   "updated": "2022-08-21T03:36:47.383Z",
   "summary": "Aoiさんによる質問zoom",
   "start": {
    "dateTime": "2022-08-21T20:00:00+09:00",
    "timeZone": "Asia/Tokyo"
   },
   "end": {
    "dateTime": "2022-08-21T21:00:00+09:00",
    "timeZone": "Asia/Tokyo"
   },
   "recurrence": [
    "RRULE:FREQ=WEEKLY;BYDAY=SU"
   ],
  },
  {
   "id": "6vr9tlqp0tejvq5q59guransg5_20230129T110000Z",
   "status": "confirmed",
   "created": "2022-08-21T03:36:11.000Z",
   "updated": "2023-01-28T07:00:21.842Z",
   "summary": "【代行】kosukeさんによる質問zoom",
   "start": {
    "dateTime": "2023-01-29T20:00:00+09:00",
    "timeZone": "Asia/Tokyo"
   },
   "end": {
    "dateTime": "2023-01-29T21:00:00+09:00",
    "timeZone": "Asia/Tokyo"
   },
   "recurringEventId": "6vr9tlqp0tejvq5q59guransg5",
   "originalStartTime": {
    "dateTime": "2023-01-29T20:00:00+09:00",
    "timeZone": "Asia/Tokyo"
   },
  }
 ]
}

items配列中に2つの要素が入っていて、変更前が前者。変更後が後者。

1つだけ消したりすると、statusがcancelledになったので判別できてたのだが、「タイトル変更」は対応できていなかった。

ということで、前者と後者の差分を発見し、対応したい。

差分は

   "recurringEventId": "6vr9tlqp0tejvq5q59guransg5",
   "originalStartTime": {
    "dateTime": "2023-01-29T20:00:00+09:00",
    "timeZone": "Asia/Tokyo"
   },

だとわかった。

https://developers.google.com/calendar/api/v3/reference/events?hl=ja にはeventのrecurringEventIdについて少し書いてあるが、一個消した場合に出るよとかそういうことは書いてない。

けど、まあ多分1個変更した時こうなるのだという結果がわかったので、recurringEventIdがあるとき、その値と同一のidを持つitemを消すみたいな処理をすればいいという結論に至った。

Firebase Functionsの対応コードを後述する。

const json = response.data;
const jsonArray: Array<any> = json.items;
const confirmedJsonArray: Array<any> = jsonArray.filter((item, index, array) => {
    return item.status === 'confirmed';
});
// statusがcancelledもしくはconfirmedかに関わらず、既存の定期予定を打ち消すitemにはrecurringEventIdが入っている
const jsonArrayWithRecurringEventId: Array<any> = jsonArray.filter((item, index, array) => {
    return item.recurringEventId !== undefined;
});
// recurringEventIdを持つイベント(上書きitem)でconfirmedのイベントを打ち消す
const activeJsonArray: Array<any> = confirmedJsonArray.filter((item, index, array) => {
    // jsonArrayWithRecurringEventIdがなければ全部true
    if (jsonArrayWithRecurringEventId.length === 0) {
        return true;
    }
    // jsonArrayWithRecurringEventIdの中に、recurringEventIdがitemと一致するものがあれば、そのitemは弾く
    return !jsonArrayWithRecurringEventId.some((item2, index2, array2) => {
        return item2.recurringEventId === item.id;
    });
});

// このあとactiveJsonArrayを使ってslackに投稿する

以上