どうも。つじけ(tsujikenzo)です。このシリーズでは 「Googleフォームとイベントオブジェクトを極めよう」 について全6回でお送りします。今日は6回目で最終回です。
前回のおさらい
前回は、 「フォームのコンテナバインドのフォーム送信時トリガー」 ということで、 [フォーム送信時にスプレッドシートへ入力する(1対多)] のツールをご紹介しました。
今回は、最終回で、「トリガー作成アカウントと実行アカウントの違いについて」 をお届けします。
問題が起こったきっかけ
ここに 「納品書入力用フォーム」 があり、 コンテナバインドスクリプトのフォーム送信時トリガー が、1つ設定されているとします。
このトリガーを作成したのは、私自身なので、オーナーには 「自分」 が表示されています。
トリガーで発火するFunctionは 「onFormSubmit()」 です。Gmailの下書きを作成するコードを書きます。
function onFormSubmit(e) {
const formResponseObject = e.response; //{} FormResponseオブジェクト
const itemResponses = formResponseObject.getItemResponses();
const itemResponsesText = itemResponses.map(itemResponse => itemResponse.getResponse());
const recipient = 'hoge@gmail.com';
const subject = '納品書入力用フォームから回答です';
const body = `以下が回答されました。
書類作成日:${itemResponsesText[0]}
じゃがいも数量:${itemResponsesText[1]}`;
GmailApp.createDraft(recipient, subject, body);
}
GmailApp や SpreadsheetApp などの「トップレベルオブジェクト」が含まれるコードをはじめて実行する際は、一度だけ認証が必要です。
スクリプトエディタから、 onFormSubmit() を手動で実行して、認証を済ませておきましょう。※手動で実行しなくても、マニュフェストファイルに認証情報を書くことでも回避できますが、その方法はまた別のブログで紹介します。
「納品書入力用フォーム」 からテスト回答を送信します。
Gmailの [下書き] を開くと、1件の下書きが作成されています。
ここまでは問題ありません。
では、このフォームに 「別のGoogleアカウント」 から回答してみましょう。別のGoogleアカウントでログインし( 他のブラウザを使用する とアカウントの切り替えが楽です。)、フォームを送信します。
そのままGmailを開いて、 [下書き] を確認します。しかし、下書きが作成されていません。
一方で、トリガーを作成したアカウントでログインし(ブラウザを切り替えて)、Gmailの [下書き] を開きましょう。 下書きが1件作成されています。
これは、インストーラブルトリガーを設定したアカウントと、スクリプトを実行したアカウントの違いによるものです。
トリガーアカウントと、スクリプト実行アカウント
onOpen() や onEdit() で設定される、シンプルトリガー は、ファイルを作成したオーナーが誰であろうと、実行アカウントは [自分] になります。
ファイルのオーナー | 実行アカウント |
---|---|
自分 | 自分 |
他アカウント | 自分 |
しかし、 インストーラブルトリガー は、 トリガーを作成したアカウントが、実行アカウント になります。
トリガー設定アカウント | 実行アカウント |
---|---|
自分 | 自分 |
他アカウント | 他アカウント |
この、トリガーを作成したアカウントが、実行アカウント になることの、「回避方法」 をご紹介します。
回避方法
フォーム送信者のメールアドレスを取得する
まず、フォームに、 回答者のメールアドレスを送信させる ように設定します。
もし、ドメインで運用していて、フォーム送信者が ドメイン内のメンバーのみ の場合は、メールアドレスの入力が不要になります。
ひとりでも gmail.comアカウント がいる場合は、メールアドレスを手入力する必要がありますのでご注意ください。
トリガーの作成
次に、「フォームの送信時トリガー」 を、フォームを送信する全員が1つずつ作成します。(全員のファイル権限を 編集者 にする必要があります。トリガーは編集権限を失うと失効してしまうのでご注意ください。)
回答の送信者のメールアドレスは、イベントオブジェクトのFormResponseオブジェクトに、 getRespondentEmail()メソッド をぶつけると取得できます。
e.response.getRespondentEmail()
後ほどGASを書きますが、このように変数に代入しておきましょう。
const formUesr = e.response.getRespondentEmail();
プロパティサービスのユーザープロパティーズ
GASのプロジェクトには、 ユーザープロパティーズ という、GASを実行しているユーザーのみアクセスできるデータの保管場所(プロパティストア)があります。
スクリプトプロパティーズ という、オーナー権限をもつアカウントのみ編集できるデータ保管場所(プロパティストア)のことは、みなさんも聞いたことがあるかもしれません。
ユーザープロパティーズ には、GASを実行するアカウント(自分のメールアドレス)を 文字列 で格納できます。
こちらに、ユーザープロパティーズ にメールアドレスを格納する setUserProperty() 関数を用意しました。フォームを送信する前に、一度だけ実行する必要があります。
/**
* 業務前に、一度自分のアカウントから[メールアドレス]を入力して実行してください
*/
function setUserProperty() {
//自分のメールアドレスを登録してください
const email = 'tsujike@gmail.com';
const userProperties = PropertiesService.getUserProperties();
userProperties.setProperty('USER', email);
}
この、 ユーザープロパティーズに格納されているメールアドレス と、最初に取得した 回答の送信者のメールアドレス が一致していたら、 onFormSubmit()の処理を続行しましょう。 というのが、回避方法のロジックです。
完成したコード
上記を組み合わせて、完成したコードがこちらです。
/**
* フォーム送信時に、フォーム送信アカウントでGmailの下書きを作成する関数
*
* @param {object} イベントオブジェクト
* @return none
*時限トリガー:フォームのフォーム送信時トリガー
*/
function onFormSubmit(e) {
const userProperties = PropertiesService.getUserProperties();
const user = userProperties.getProperty('USER');
const formUesr = e.response.getRespondentEmail();
if (user === formUesr) {
const formResponseObject = e.response; //{} FormResponseオブジェクト
const itemResponses = formResponseObject.getItemResponses();
const itemResponsesText = itemResponses.map(itemResponse => itemResponse.getResponse());
const recipient = 'hoge@gmail.com';
const subject = '納品書入力用フォームから回答です';
const body = `以下が回答されました。
書類作成日:${itemResponsesText[0]}
じゃがいも数量:${itemResponsesText[1]}`;
GmailApp.createDraft(recipient, subject, body);
}
}
テスト回答を送信してみましょう。※テスト回答を送信する前に、setUserProperty()関数を実行することを忘れないようにしましょう。
/**
* 業務前に、一度自分のアカウントから[メールアドレス]を入力して実行してください
*/
function setUserProperty() {
//自分のメールアドレスを登録してください
const email = 'tsujike@gmail.com';
const userProperties = PropertiesService.getUserProperties();
userProperties.setProperty('USER', email);
}
フォームを送信したアカウントでGmailの [下書き] を開くと、下書きが1件作成されています。
確認のため、スクリプトエディタの [実行数] を開きます。
「フォーム送信時トリガー」 が3件同時に発火しています。トリガーは3件発火していますが、if (user === formUesr) が true になるのは、 実行アカウントとフォーム送信者が一致する1件 のみです。
最終回の記事は、私が所属しているノンプロ研の@etau氏の頭の中を、弟子である私が通訳したものです。師匠、いつもありがとうございます。
まとめ
以上で、 「トリガー作成アカウントと実行アカウントの違いについて」 お届けしました。
アカウントの違いについて、策を講じましたが、 [ウェブアプリ] として公開した場合は、さほど気にしないでいいと思います。なので、あくまで 社内運用 したときに困った場合、参考にしていただければ幸いです。
このシリーズでは 「Googleフォームとイベントオブジェクトを極めよう」 ということで、さまざまなフォームの活用方法をご紹介しました。
ノーコード・ローコードアプリ作成が流行りの昨今ですが、まだまだ 「ちょっとカスタマイズしたいだけなのに」 や 「こんなこともやってみたい」 という現場の声は多いはずです。
引き続き 「実務で使えるツール作り」 を意識して、学習を続けたいと思います。