虎の穴開発室ブログ

虎の穴ラボ株式会社所属のエンジニアが書く技術ブログです

MENU

GoogleスプレッドシートとGASでイベント出欠管理ツールを作ってみた話 その2

こんにちは、虎の穴ラボのA.M.です。

前回の記事の最後の方でも触れていますが、作った出欠管理ツールを運用していく中で、「スマートフォンから入力しづらい」または「入力できない」という声が多く上がっていました。 そこで、今回はその解決策としてイベント出欠管理ツールを拡張し、Googleフォームでも出欠登録・変更(Discordにも通知)ができるようにしたいと思います。

※本記事の内容は、以前の記事「GoogleスプレッドシートとGASでイベント出欠管理ツールを作ってみた話」の続きとなりますので、先のこちらの記事を一読いただくことをおすすめいたします。

toranoana-lab.hatenablog.com

目次

用語

前回の記事からの流用です。有識者の方は読み飛ばしていただいても構いません。

単語 意味
MMORPG Massively Multiplayer Online Role-Playing Gameの略。大規模多人数同時参加型オンラインRPGを指す。いわゆるネトゲ。
ギルド ゲーム内で設立された団体・コミュニティ。ゲームによってはクラン、サークル等と称されることもある。
パーティ 共に冒険する仲間。ゲームによって人数下限や上限が異なるが、基本的には3~8人程度。
レイド 多数のプレイヤーが協力し、少人数ではクリアが困難な高難易度要素を攻略すること。ゲームのシステム上では、複数のパーティを束ねたレイドパーティを指すこともある。
その他の関連用語:レイドボス(≒高難易度ボス)、レイドダンジョン(≒高難易度ダンジョン)
戦力 ゲーム内のキャラクターの強さ(レベル、スキル、装備やその他の強化要素)を総合的に評価した数値。ゲームによってはスコア、戦闘力等と称されることもある。

要件

  1. スマートフォンからでも簡単に出欠登録・変更ができること(細かく手順を説明しなくても登録・変更ができること)

今回の要件はこれだけです。 これはGoogleフォームで解決できそうなので、作っていきます。

使用するもの

  • Googleスプレッドシート
  • Googleフォーム new
  • Google Apps Script (以降、GAS)
  • Discord

前提

  • Googleアカウントを作成し、ログイン済みであること
  • Discordインストール済みであること
  • Discordのサーバは作成済みであること
  • 前回の記事でご紹介した出欠管理表が作成済みであること

実際に作ってみる

STEP1 Googleフォームを作る

まずはスプレッドシートからGoogleフォームを作成します。

ツール>新しいフォームを作成 f:id:toranoana-lab:20210930194456p:plain

次のようなフォームが作成されます。 f:id:toranoana-lab:20210930194707p:plain

続いて、フォームの入力項目を設定していきます。
まずは「キャラクター名」の入力項目を作成します。 f:id:toranoana-lab:20210930194820p:plain

「職業」項目を作成します。 f:id:toranoana-lab:20210930194943p:plain

「戦力」項目を作成します。 f:id:toranoana-lab:20210930194956p:plain

「イベント出欠」項目を作成します。 f:id:toranoana-lab:20210930195102p:plain

「イベント出欠」項目はコピーして、必要な数だけ作成します。
今回は4つ作成したものとして説明していきます。
f:id:toranoana-lab:20210930195312p:plain

「コメント」項目を作成します。 f:id:toranoana-lab:20211001012040p:plain

これで出欠登録フォームは完成なので、URLを取得して表示してみます。
画面右上の「送信」ボタンを押します。
f:id:toranoana-lab:20210930195632p:plain

ポップアップが表示されたら、クリップアイコンをクリックし、リンクのURLをコピーしておきます。
※他の人に共有する場合は、「URLを短縮」にチェックを入れておくと良いでしょう。
f:id:toranoana-lab:20210930195642p:plain

コピーしたURLを開くと、以下のようなフォームが表示されます。
f:id:toranoana-lab:20211001012108p:plain

フォームを作成した時点で、スプレッドシート側に回答記録用の「フォームの回答 1」シートが作成されています。 f:id:toranoana-lab:20210930200250p:plain

試しにフォームの内容を入力して送信すると、「フォームの回答 1」シートにデータが登録されます。
f:id:toranoana-lab:20211001012138p:plain

STEP2 回答記録シートに「反映済み」チェックボックスを追加する

フォームから登録されたデータは、「キャラクター名」をキーとして出欠表に反映するため、キャラクター名に入力ミスがあると反映できない場合があります。
その場合は管理者が手動で反映を行う必要があるので、出欠表に反映済みかどうかのステータスが分かるように「フォームの回答 1」シートに少し工夫を加えます。

まずは「フォームの回答 1」シートの回答結果の右側に「反映済み」チェックボックスの列を追加します。 f:id:toranoana-lab:20211001012214p:plain

次に、チェックした行の背景色がグレーに変わるように「条件付き書式設定ルール」を追加します。 f:id:toranoana-lab:20211001012242p:plain

チェックを入れた行がグレーに変わればOKです。 f:id:toranoana-lab:20211001012252p:plain

STEP3 GASの実装

ここまでできたら、あとはGASを実装していくだけです。

出欠表のスプレッドシートから、スクリプト エディタを開きます。
拡張機能>Apps Script f:id:toranoana-lab:20210930201957p:plain

スクリプトエディタを開くと、前回実装したコードが表示されます。
今回はここに関数を追加していきます。 f:id:toranoana-lab:20210930202112p:plain

フォームが送信されたらDiscordに通知する

まずは、次のようにフォームで入力された内容をDiscordに通知する関数onFormPostを追加します。

// フォームから登録あった場合の通知
function onFormPost() {
  let activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet(); // スプレッドシート
  let activeSheet = activeSpreadsheet.getActiveSheet(); // アクティブシート
  
  if(activeSheet.getName() != "フォームの回答 1"){
    return;
  }
  
  let activeCell = activeSheet.getActiveCell(); // アクティブセル
  let nowInputRow = activeCell.getRow(); // 入力のあった行番号
  let nowInputColumn = activeCell.getColumn(); // 入力のあった列番号
  
  let charName = activeSheet.getRange(nowInputRow, 2).getValue(); // キャラクター名取得
  let job = activeSheet.getRange(nowInputRow, 3).getValue(); // 職業取得
  let power = activeSheet.getRange(nowInputRow, 4).getValue(); // 戦力取得
  let attend1 = activeSheet.getRange(nowInputRow, 5).getValue(); // イベント出欠取得
  let attend2 = activeSheet.getRange(nowInputRow, 6).getValue();
  let attend3 = activeSheet.getRange(nowInputRow, 7).getValue();
  let attend4 = activeSheet.getRange(nowInputRow, 8).getValue();
  let comment = activeSheet.getRange(nowInputRow, 9).getValue(); // コメント取得

  // イベント名を取得
  let eventName1 = activeSheet.getRange(1, 5).getValue();
  let eventName2 = activeSheet.getRange(1, 6).getValue();
  let eventName3 = activeSheet.getRange(1, 7).getValue();
  let eventName4 = activeSheet.getRange(1, 8).getValue();
  
  // 送信するテキスト
  let sendText = charName + "さんが出欠フォームから出欠登録したよ!ヨシ!\n" +
    "```" +
    "キャラ名: " + charName + "\n" +
    "職業: " + job + "\n" +
    "戦力: " + power + "\n" +
    eventName1 + ": " + attend1 + "\n" +
    eventName2 + ": " + attend2 + "\n" +
    eventName3 + ": " + attend3 + "\n" +
    eventName4 + ": " + attend4 + "\n" +
    "コメント: " + comment +
    "```";
        
  sendDiscord(sendText);

  // 以下に、出欠表への反映処理を追記する
}

フォームが送信されたら出欠表に自動反映する

次に、「フォームの回答 1」シートの内容を「出欠表」シートに反映するスクリプトを実装していきます。

「キャラクター名」から出欠表の行番号を特定するための検索用関数findRowを追加します。

// 指定した値と一致する行番号を返す
function findRow(sheet, val, col){
  // シートのデータを二次元配列として取得
  let data = sheet.getDataRange().getValues();

  for(let i=1;i<data.length;i++){
    if(data[i][col-1] === val){
      return i+1;
    }
  }
  // 見つからなかった場合は0を返す
  return 0;
}

そして、先程追加したonFormPost関数の続きに反映処理を追記していきます。

// フォームから登録あった場合の通知
function onFormPost() {
(省略)

  // 以下、出欠表への反映処理
  let attendSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("出欠表");
  
  let targetRow = findRow(attendSheet, charName, 2) // キャラクター名から行を検索
  if(targetRow == 0){ // 見つからなかった場合はメンションを飛ばす
    sendDiscord("@here 「" + charName + "」さんが出欠表に存在しないため、自動反映できなかったよ!手動で反映してね☆");
    return;
  }
  
  attendSheet.getRange(targetRow, 3).setValue(job); // 職業
  if(power != ""){ // 入力がないときは反映しない 
    attendSheet.getRange(targetRow, 5).setValue(power); // 戦力
    // 戦力の更新日時を記録 
    attendSheet.getRange(targetRow, 10).setValue(Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy-MM-dd HH:mm:ss'))
  }
  if(attend1 != ""){
    attendSheet.getRange(targetRow, 5).setValue(attend1); // 出欠1
  }
  if(attend2 != ""){
    attendSheet.getRange(targetRow, 6).setValue(attend2); // 出欠2
  }
  if(attend3 != ""){
    attendSheet.getRange(targetRow, 7).setValue(attend3); // 出欠3
  }
  if(attend4 != ""){
    attendSheet.getRange(targetRow, 8).setValue(attend4); // 出欠4
  }
  if(comment != ""){
    attendSheet.getRange(targetRow, 9).setValue(comment); // コメント
  }
  
  // 反映済みチェックを入れる
  activeSheet.getRange(nowInputRow, 10).setValue(true); 
  sendDiscord("「" + charName + "」さんの出欠を出欠表に反映したよ!ヨシ!");
}

STEP4 トリガーの設定

最後に、スプレッドシートが変更されたら、実装したスクリプトが実行されるように、トリガーの設定を行います。

スクリプトエディタの左側メニューの時計マークから、トリガーの設定を開きます。
f:id:toranoana-lab:20210930205656p:plain

「トリガーを追加」で新規にトリガーを追加します。
f:id:toranoana-lab:20211001010921p:plain

フォームが送信された場合にonFormPost関数を実行したいので、

  • 実行する関数: onFormPost
  • イベントソースの選択: スプレッドシートから
  • イベントの種類を選択: フォーム送信時

を指定して、トリガーを保存します。
f:id:toranoana-lab:20211001010936p:plain

トリガー一覧に反映されていればOKです。 f:id:toranoana-lab:20211001011026p:plain

STEP5 動かしてみる

トリガーの追加までできたら、Discordに通知が届くようになっているはずなので、出欠登録フォームから送信してみます。
f:id:toranoana-lab:20211001011044p:plain
Discordに通知が送られていますね。
出欠表にもフォームから送信した内容が反映されています。
f:id:toranoana-lab:20211001011220p:plain

出欠表への自動反映が失敗した場合は次のような通知が飛びます。
f:id:toranoana-lab:20211001011609p:plain

この通知が来た場合は、手動で出欠表に反映した後、「反映済み」チェックを入れてください。 f:id:toranoana-lab:20211001011700p:plain

あとがき

今回作成したイベント出欠管理表のスプレッドシートはGASと共に公開していますので、もし出欠管理に困っているという場合はぜひ使ってみてください。

イベント出欠管理表 - Google スプレッドシート

※上記スプレッドシートを開き、「ファイル>コピーを作成」でマイドライブなどに保存してご使用ください。
※スプレッドシートをコピーすれば、通知用のGASとフォームも一緒にコピーされますので、あとはWebhookURLの記述とトリガー設定だけ行えば通知が届くようになります。
※コピーしたスプレッドシートから、フォームの編集を行うには「ツール>フォームを管理>フォームを編集」を選択してください。
f:id:toranoana-lab:20211001021102p:plain

また、ソースコード全文はGitHubでも公開していますので、参考にしてみてください。

github.com

P.S.

アイコンで使用しているメイドちゃんはとらラボ素材集に収録されています。
無料で利用可能なので、発表資料などでぜひ使ってみてください。 yumenosora.co.jp

採用情報

■募集職種
yumenosora.co.jp

カジュアル面談も随時開催中です

■お申し込みはこちら!
news.toranoana.jp

■ToraLab.fmスタートしました!

メンバーによるPodcastを配信中!
是非スキマ時間に聞いて頂けると嬉しいです。
anchor.fm

■Twitterもフォローしてくださいね!

ツイッターでも随時情報発信をしています
twitter.com