見出し画像

Google formで出欠をとってLINE Groupに通知する

サークルやグループで1ヶ月単位など長期の出欠を取る際、今日は誰が参加するのかということがわかりづらいなと思ったため、LINEグループに参加メンバーを通知することにした。

(例えば、毎週土曜日に練習すると決まっているグループで1ヶ月の出欠を取って、練習日の前日に通知するなど...)

使用するのは
・Google Form
・GAS(Google App Script)
・LINE Notify
の3つ

画像1


1. Google Formを作成する

まずはメンバーに出欠を入力してもらうgoogle Formを作成する

スクリーンショット 2021-03-08 20.53.04

回答者と参加日を聞く質問を作る。

参加日の設問はチェックボックスを使って、行に日付、列に出欠の可否を入力できるようにした。

この際、日付の記入は「西暦/月/日」に統一しておくと、この後のGASのプログラムをあまり変更しなくて済む。


2. GASでプログラムを書く

google formの回答から書き出したgoogle スプレッドシートとGASを紐付けて、まずは出欠を色分けしていく

また、参加するメンバーを書き出す

そして、任意の日付と候補日が一致した場合、その日に参加するメンバーをログに書きだす

const COLORED_SHEET_NAME = "色分け_"; //任意のシートの名前

/**
* フォームの受付が終了したあとに呼び出される関数
* 新しいシートに色付きでフォーマットする
*/
function fixSheet() {
 const mySheet = SpreadsheetApp.openById('スプレッドシートのURLの https://docs.google.com/spreadsheets/d/「ここの部分」');
 const originalAnswer = mySheet.getSheetByName('フォームの回答 1');

 // シートをコピー
 const copyAnswer = originalAnswer.copyTo(mySheet);
 // シートに名前をつける
 copyAnswer.setName(COLORED_SHEET_NAME);
 //コピーしたシートを左から一番目に移動する
 mySheet.setActiveSheet(copyAnswer);
 // 作成したシートの位置を移動
 mySheet.moveActiveSheet(1);

 // 最終行を取得
 const lastRow = copyAnswer.getLastRow();
 // 最終列を取得
 const lastColumn = copyAnswer.getLastColumn();
 console.log("lastRow: " + lastRow + "\nlastColumn: " + lastColumn);
 // ◯△×で色分けする
 for(let i=2; i<=lastRow; i++){
   for(let j=3; j<=lastColumn; j++){
     let tmpCell = copyAnswer.getRange(i,j);
     let tmpVal = tmpCell.getValue();
     tmpCell.setBackground(tmpVal === "◯" ? "#ffc0cb" : (tmpVal === "△" ? "#b0c4de" : "#dcdcdc"));   //三項演算子     
   }
 }

 // 参加者の名前の配列
 const memberList = copyAnswer.getRange(2, 2, lastRow-1); 
 
 // 参加日ごとに◯の人数をカウントして,その数と参加者の名前を表示
 for (let col=3; col<=lastColumn; col++) {
   const attendList = copyAnswer.getRange(2, col, lastRow-1);
   const attendNum = countMembers(attendList.getValues());
   copyAnswer.getRange(lastRow+1, col).setValue(attendNum);
   copyAnswer.getRange(lastRow+2, col, attendNum).setValues(getAttendMembers(memberList.getValues(), attendList.getValues()));
 }

 // 今日の日付でテスト
 console.log("今日の場合")
 console.log(getDateMembers(Utilities.formatDate(new Date(), 'Asia/Tokyo', 'YYYYMMdd')));

 // 練習のある日でテスト
 console.log("2/14の場合")
 console.log(getDateMembers("20210214"));
}

// ◯の人をカウントする
function countMembers(attendList) {
 console.log(attendList);
 return attendList.filter( function(val) {return val[0] === "◯"}).length;  //無名関数
}

// ◯の人の名前のリストを生成する
function getAttendMembers(memberList, attendList) {
 const attendMembersList = [];
 for (let i=0; i<attendList.length; i++) {
   console.log(memberList[i][0] + ": " + attendList[i][0]);
   if (attendList[i][0] === "◯") {
     attendMembersList.push([memberList[i][0]]);  //リストの末尾に要素を追加する
   }
 }
 return attendMembersList;
}

// MMddの文字列で日付を受け取るとその日の練習メンバーのリストを返す
function getDateMembers(dateStr) {
 const mySheet = SpreadsheetApp.openById('スプレッドシートのURLの https://docs.google.com/spreadsheets/d/「ここの部分」');
 const originalAnswer = mySheet.getSheetByName('フォームの回答 1');
 const copyAnswer = mySheet.getSheetByName(COLORED_SHEET_NAME);
 const lastRow = originalAnswer.getLastRow();
 const lastColumn = originalAnswer.getLastColumn();
 const dateHeadStrList = copyAnswer.getRange(1, 3, 1, lastColumn-3).getValues();
 console.log(dateHeadStrList);

 // 練習日の一覧
 //桁数を揃える(2020/2/14 => 2020/02/14)
 const meetingDaysList = dateHeadStrList[0].map(x => {
   console.log("x: " + x);
   //()でグルーピングすることでmatchしたグループごとに配列に入る
   const result = x.match(/(\d{4})\/(\d+)\/(\d+)/); //正規表現[\d]は整数 {}は数の指定 +は直前の文字が一個以上 ()はグルーピング

   console.log(result);
   const dateStr = result[1] + ("00" + result[2]).slice(-2) + ("00" + result[3]).slice(-2);
   return dateStr
 });
 console.log("meetingDaysList: " + meetingDaysList);
 const today = new Date();
 const todayStr = Utilities.formatDate(today, 'Asia/Tokyo', 'YYYYMMdd');
 if (!meetingDaysList.includes(dateStr)) {
   console.log(dateStr + "は練習日ではない");
   return -1
 } else {
   console.log(dateStr + "は練習日だよ");
   const tmpIndex = meetingDaysList.indexOf(dateStr);
   const tmpMemberNum = copyAnswer.getRange(lastRow+1, 3+tmpIndex).getValue();
   console.log("lastRow: " + lastRow + "\ntmpIndex: " + tmpIndex + "\ntmpMemberNum: " + tmpMemberNum);
   //.valuesで取得した値は二次元配列
   const attendMembersList = copyAnswer.getRange(lastRow+2, 3+tmpIndex, tmpMemberNum, 1).getValues(); 
   return attendMembersList.flat(); //二次元配列を一次元配列に直す
 }
}

あとはLINEに通知するコードを書く

ただ、この部分はLINE Notifyの登録が必要なのでLINE Notifyの説明を先にします。


3.  LINE Notifyに登録する

上記にログインして、マイページにアクセスする

スクリーンショット 2021-03-10 16.33.17

その後、アクセストークンを発行し、LINE Notifyで通知させたいグループに追加してあげる

この時、発行されるアクセストークンは一度しか表示されないので、しっかり控えておく

スクリーンショット 2021-03-10 16.36.30


これで準備は整ったので、先程のGASのコードに追加して、以下のLINEにメッセージを送るコードを追加していく。

function sendText(){
 const tmpDate = new Date();
 //明日の日付
 tmpDate.setDate(tmpDate.getDate()+1);
 console.log('日付:' + tmpDate);
 
 const attendMembers = getDateMembers(Utilities.formatDate(tmpDate, 'Asia/Tokyo', 'YYYYMMdd'));
 console.log(attendMembers);

 let messageText;

 if(attendMembers === -1){
   messageText = '明日は練習日じゃないよ';
 }else{
   messageText = '\n明日の参加者は\n\n' + attendMembers.join('\n') + '\nだよ\n\n参加人数は' + attendMembers.length + '人だよ' ;
 }

 
  // LINEから取得したトークン
 const TOKEN = "LINE notifyで発行したトークン"; 

   let options = {
  "method" : "post",
  "headers" : {
    "Authorization" : "Bearer "+ TOKEN
  },
  "payload" : {
    "message" : messageText
  }
}


 let url  = "https://notify-api.line.me/api/notify";
 UrlFetchApp.fetch(url, options);
}


これでコードの準備はできたので、動作確認する

下の図の青枠の部分で「fixSheet」を選択し、実行する

スクリーンショット 2021-03-10 16.40.28

これで、以下のようにスプレッドシートに新しいシートの追加と色分けが行われれば正常に動作している

スクリーンショット 2021-03-10 16.47.22

また、先程の青枠の部分を「sendText」に変えて、メッセージが届いていればLINEに通知する方もうまく動作していると言える。

ただし、明日の日付が候補日と一致している場合、「参加メンバー」、一致していない場合、「明日は練習日じゃないよ」と届くはず

画像8

4. トリガーを設定する

正常に動作していたら、トリガーを設置し、毎日自動でメッセージを通知するようにする。

GASのトリガーを以下のように設定する。

スクリーンショット 2021-03-10 17.20.06

時間については通知したい時間を自由に設定する。

これで、毎日この時間にsendText関数を実行して、明日が候補日に一致しているかしていないかを判定し、LINEにメッセージを通知することができる。


5. まとめ

LINE notifyやGASを使えばいろんなものを通知したり、自動化したりできる。非常に便利。

ちなみに、候補日じゃない日は通知しないようにするには、以下のようにSendText関数を変更すればOK

function sendText(){
 const tmpDate = new Date();
 //明日の日付
 tmpDate.setDate(tmpDate.getDate()+1);
 console.log('日付:' + tmpDate);
 
 const attendMembers = getDateMembers(Utilities.formatDate(tmpDate, 'Asia/Tokyo', 'YYYYMMdd'));
 console.log(attendMembers);

 let messageText;

 if(attendMembers === -1){
   return 0;
 }else{
   messageText = '\n明日の参加者は\n\n' + attendMembers.join('\n') + '\nだよ\n\n参加人数は' + attendMembers.length + '人だよ' ;

    // LINEから取得したトークン
    const TOKEN = "発行したトークン"; //本番環境
    let options = {
    "method" : "post",
    "headers" : {
    "Authorization" : "Bearer "+ TOKEN
    },
    "payload" : {
    "message" : messageText
    }
    }
    
    
    let url  = "https://notify-api.line.me/api/notify";
    UrlFetchApp.fetch(url, options);
    }
}


この記事が気に入ったらサポートをしてみませんか?