CData Software Blog

クラウド連携のCData Software の技術ブログです。

サービスアカウントでGoogle Calendarのスケジュール情報にアクセスする

この記事ではGoogle Calendar APIにサービスアカウントを使ってアクセスする方法を紹介します。

今回は以下のシナリオを前提に説明します。 Google Calendarのユーザ(User1)のアカウントでサービスアカウントを作成し、当該ユーザのカレンダーにアクセスできるようにします。

f:id:urabe_shintaro:20210329184801p:plain

User1のカレンダーには1件のスケジュールが登録されています。

f:id:urabe_shintaro:20210326164300p:plain

1. APIの有効化

Google CalendarのユーザアカウントでGoogle Cloud Platformにログインし、ナビゲーションメニューの[APIとサービス]から[ライブラリ]を開きます。 サービス一覧からGoogle Calendar APIを選択し、[有効にする]をクリックします。

f:id:urabe_shintaro:20210326154757p:plain

2. サービスアカウントの作成

Google CalendarのユーザアカウントでGoogle Cloud Platformにログインします。

2.1 OAuth同意画面の作成

はじめにGoogle Calendar APIにアクセスするアプリを作成します。 ナビゲーションメニューの[APIとサービス]から[OAuth同意画面]を開きます。 [User Type]を選択し、[作成]をクリックします。 [User Type]はアプリの公開範囲に従って選択してください。 因みに「内部」はGoogle Workspace (旧G Suite)の組織内のアカウントの場合のみ選択可能です。

f:id:urabe_shintaro:20210330090548p:plain

[アプリ名]に適当な名前を入力し、[ユーザサポートメール][デベロッパーの連絡先情報]にメールアドレスを入力します。

f:id:urabe_shintaro:20210326155036p:plain

これ以降の画面では特に何も設定せず、すべて[保存して次へ]をクリックします。

2.2 サービスアカウントの作成

ナビゲーションメニューの[APIとサービス]から[認証情報]を開きます。 [認証情報の作成]を開き、[サービスアカウント]を選択します。

f:id:urabe_shintaro:20210326155135p:plain

適当なサービスアカウント名を入力し、[完了]をクリックします。

f:id:urabe_shintaro:20210326155202p:plain

2.3 サービスアカウントのキーの生成

サービスアカウント一覧から作成したサービスアカウントを選択し詳細画面を開きます。 [キー]タブを選択し、[鍵を追加]を開いて[新しい鍵を作成]をクリックします。

f:id:urabe_shintaro:20210326155303p:plain

希望する鍵タイプをチェックし[作成]をクリックします。ここでは「JSON」を選択します。

f:id:urabe_shintaro:20210326155314p:plain

鍵が生成されダウンロードされます。 このファイルは認証時に必要となりますので保管しておいてください。

f:id:urabe_shintaro:20210326155334p:plain

3. サービスアカウントへのカレンダーの共有

サービスアカウントからアクセスするユーザ(user1@test.page)のカレンダーをサービスアカウントに共有します。 Google Calendarを開き、カレンダーのオーバーフローメニューを開いて(マウスオーバーすると表示されるアイコンをクリック)、[設定と共有]をクリックします。

f:id:urabe_shintaro:20210326155504p:plain

[カレンダーの設定]を開き、[特定のユーザとの共有]セクションで[ユーザの追加]をクリックします。

f:id:urabe_shintaro:20210326155524p:plain

サービスアカウントのメールアドレスを入力し、[権限]を選択して[送信]をクリックします。 今回は権限としてフルアクセスを行う「変更及び共有の管理権限」を選択しました。

f:id:urabe_shintaro:20210326155536p:plain

以下のように共有にサービスアカウントが追加されたことを確認してください。

f:id:urabe_shintaro:20210326155754p:plain

動作確認

それではJavaでサービスアカウントを使ったカレンダーの取得を試してみます。 以下のコードはUser1(カレンダーID : user1@test.page)のスケジュール一覧を取得します。 path/to/credentialにはステップ2.3で生成した鍵ファイルのパスを指定してください。

GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("path/to/credential"))
.createScoped(Collections.singleton(CalendarScopes.CALENDAR_EVENTS));

final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
Calendar service = new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).setApplicationName(APPLICATION_NAME).build();

Events events = service.events().list("user1@test.page").execute();
List<Event> items = events.getItems();
for (Event event : items) {
     DateTime start = event.getStart().getDateTime();
     DateTime end = event.getEnd().getDateTime();
     System.out.printf(event.getSummary() + " (" + start + " - " + end + ")");
}

上のコードを実行した結果を示します。 User1のスケジュールが取得できることを確認しました。

全体ミーティング(2021-02-16T15:00:00.000+09:00 - 2021-02-16T16:00:00.000+09:00)

これまでの手順で、サービスアカウントから個別のカレンダーのスケジュールを取得する方法を紹介しました。 他のカレンダーも取得できるようにする際はカレンダーごとにステップ3の共有設定を行ってください。

f:id:urabe_shintaro:20210329191335p:plain

4. カレンダーリストへのカレンダーの追加

個別のユーザのスケジュールを取得するには各カレンダーのIDが分からないと取得できません。 ここではサービスアカウントが各ユーザのカレンダーIDを取得できるように、カレンダーリストにユーザのカレンダーを追加します。

通常、カレンダーリストへの追加はGoogle Calendar[設定][カレンダーを追加]から行いますが、サービスアカウントはUI画面を持たないため画面から追加することができません。 そこでAPIを使ってカレンダーリストへ追加します。

以下のエンドポイントにPOSTメソッドを発行し、追加するカレンダーのIdを送信します。

https://www.googleapis.com/calendar/v3/users/me/calendarList

リクエストボディ:

{
  "id": "<追加するカレンダーID>"
}

curlでアクセスする場合以下のコマンドを実行します。 AuthorizationヘッダにはサービスアカウントのOAuthアクセストークンを指定してください。

curl --location --request POST "https://www.googleapis.com/calendar/v3/users/me/calendarList" 
--header "Authorization: Bearer <OAuthアクセストークン>" 
--header "Content-Type: text/plain" 
--data-raw "{  \"id\": \" <カレンダーID> \" }"

例:カレンダーリストにカレンダー(user1@test.page)を追加する

curl --location --request POST "https://www.googleapis.com/calendar/v3/users/me/calendarList" 
--header "Authorization: Bearer ya29.c.Kp4B-QdjWtz3XZoRt1Bt7EvMb29GxuH9frk66ZlsKeCxrTiExQkYUGZn4iiCrL9Utmr9ncHYxTDk1tNbrhnVoIEl8qkA69hsKN7UdVD96Lxo6GOGYICMrGIsjhx-joRrywJjT_APiBxEeLxJA2oVlAbtom_cBDbWW9Di3_wyU_sj45twaYmYqZcM4i1KiBrOtCfqOQAx49WjLcE7H3Ho6Bo" 
--header "Content-Type: text/plain" 
--data-raw "{  \"id\": \"user1@cdatatest.page\" }"

カレンダーリストからカレンダーを削除するには以下のエンドポイントにDELETEメソッドを発行します。

https://www.googleapis.com/calendar/v3/users/me/calendarList/<削除するカレンダーID>

例:カレンダーリストからuser1@test.pageのカレンダーを削除する

curl --location --request POST 'https://www.googleapis.com/calendar/v3/users/me/calendarList' \
--header 'Authorization: Bearer ya29.c.Kp4B-QdjWtz3XZoRt1Bt7EvMb29GxuH9frk66ZlsKeCxrTiExQkYUGZn4iiCrL9Utmr9ncHYxTDk1tNbrhnVoIEl8qkA69hsKN7UdVD96Lxo6GOGYICMrGIsjhx-joRrywJjT_APiBxEeLxJA2oVlAbtom_cBDbWW9Di3_wyU_sj45twaYmYqZcM4i1KiBrOtCfqOQAx49WjLcE7H3Ho6Bo' \
--header 'Content-Type: text/plain' \
--data-raw '{
  "id": "user1@cdatatest.page"
}'

動作確認

それではJavaでサービスアカウントを使ったカレンダーリストの取得を試してみます。

GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream(path/to/credential))
.createScoped(Collections.singleton(CalendarScopes.CALENDAR));

final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
Calendar service = new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
        .setApplicationName(APPLICATION_NAME)
        .build();

String pageToken = null;
do {
  CalendarList calendarList = service.calendarList().list().setPageToken(pageToken).execute();
  List<CalendarListEntry> items = calendarList.getItems();

  for (CalendarListEntry calendarListEntry : items) {
    System.out.println(calendarListEntry.getSummary());
  }
  pageToken = calendarList.getNextPageToken();
} while (pageToken != null);

実行結果は以下の通りです。 カレンダーリストに登録されているUser1のカレンダーIDが取得できることを確認しました。

user1@test.page