前提
Google Workspace のアカウントで検証・実装しています。
API によっては個人アカウントと挙動が異なる可能性があります。多分。
やりたいこと
Google ドライブに保存しているファイルの最終更新者を取得したい。
ググった感じ、古い情報しかなかったり最終更新日時しか取得できなかったりで自分の環境で動かなかった。
インターネッツによると、Drive.Files.get() でlastModifyingUserName
が取得できるらしいんだけど、ワイがアクセスしたときのレスポンスがこれ↓だったからググってコピペでイッセンマンにはなれませんでした。
{ "name": "XXXXX", "mimeType": "XXXXX", "kind": "XXXXX", "id": "XXXXX" }
ドキュメントに記載されてるリソースと違いすぎて笑えてきまちゅわ〜(泣)
(多分Google Workspaceのアカウントだったりファイルの共有設定とかの環境のせいもあると思うけど、単純にワイのドキュメントに対する読解力がないだけ)
やったこと
ということでできないもんは仕方ない!別の方法でやっていこう!
GAS の設定周り
1. 必要なサービスを追加する
以下の使用するAPIをサイドバーのサービスから追加する。
- Drive
- DriveActivity
- People
サイドバー->サービス
->+ボタンのサービスを追加
をクリックすると以下のようなモーダルが出てくるので該当 API を選んで追加する。
IDはプロジェクト内の他の定義と重複していなければこのままでOK
2. appsscript.json
に oauthScopes
を定義する
プロジェクトの設定
->全般設定
にある「appsscript.json」マニフェスト ファイルをエディタで表示する
にチェックを入れる。
サイドバーのエディタにappsscript.json
が出てくるからoauthScopes
を定義して、以下の権限を記述する。1
"oauthScopes": [ "https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/contacts.readonly", "https://www.googleapis.com/auth/drive.readonly", "https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/drive.activity", "https://www.googleapis.com/auth/drive.activity.readonly" ],
GAS が用意してる API は基本的に設定しなくても使えるはずなんだけど、People API の以下の 2 つだけは明示しないと呼び出せないみたいだった。
https://www.googleapis.com/auth/userinfo.profile
https://www.googleapis.com/auth/contacts.readonly
と同時に、oauthScopes
を定義すると設定しなくても使えるはずの他のサービス(Drive, DriveActivity…etc)の権限が死ぬみたいで、最終的に使うサービスのスコープはすべてoauthScopes
に記述しないと動かなかった。(だったら最初から全部明示的に記述しないと動かないようにしとけ!!!)
このへんは実行したときに必要なスコープをログに出してくれるから指定値がわからなくなることはないと思う。Google ちゃん優しいね。
3. コード.gs の実装
3-1. ファイル情報を取得する
const activities = DriveActivity.Activity.query({ itemName: "items/XXXXXXX", // items/ファイルID の形式でファイルを指定 pageSize: 1, }).activities;
再現性取れてないけど、たまにactivitiesが空で返却されることがあるけどなんでだ?ファイルが存在する以上は履歴が空になることはなくない??
3-2. ファイル情報から最終更新ユーザーの識別子を取得する
const personName = activities?.[0]?.actors?.[0]?.user?.knownUser?.personName;
3-3. 識別子からユーザー情報を取得する
const lastModifyUser = People.People.get(personName, { personFields: "names" }) ?.names?.[0]?.displayName;
うん、済まないがoptional chaining アレルギーの人は帰ってくれないか(´・ω・`)2
コード全体(一例)
フォルダ内のファイル数が多い場合とか再帰的にアクセスしてく場合は、多分レートリミットにすぐ引っかかるから API にアクセスする直前に 1,2 秒の sleep 入れたほうがいいと思う。(10行目)
組織外のユーザーの情報も取得したい場合は多分 GAS 以外の設定もいるっぽい。多分。知らんけど。
4. GAS に対して権限を許可する
実行したらGASへのアクセス権限を聞かれるから許可してあげて完了。
トラブルシューティング
Exception: Specified permissions are not sufficient to perform the action. Required permissions: (https://www.googleapis.com/….)
と表示される
appsscript.json
に必要なスコープが記述されていない可能性があります。
記載されている URL をoauthScopes
に設定してあげましょう。
Quota exceeded for quota metric 'Critical read requests (xxxxx)' and limit 'Critical read requests (xxxxx) per minute per user' of service 'xxxxx.googleapis.com' for consumer
と表示される
短時間に複数のファイルにアクセスし続けている場合、API のレートリミットに引っかかっている可能性があります。
上限を引き上げる申請をするか、API へのアクセスの直前で 1,2 秒のスリープを入れてあげましょう。
最後に
いろんな条件が重なって lastModifyingUserName
で最終更新者が取得できてないだけだと思ってるんだけど、本当にここまでしないと取れないんか…?
ファイルが持ってる公開情報だからもっと簡単に取得できても良さそうなんだけど…
誰かもっと簡単に取得できる方法知ってる人がいたら教えてくだちい。
参考
rikoubou.hatenablog.com developers.google.com developers.google.com developers.google.com
株式会社エイルシステムではWebエンジニア・モバイルアプリエンジニアを募集しています。
実務経験がなくてもOKです。ご興味のある方は弊社HPよりご連絡ください。