素人が翌日の勤務(シフト)を告げるLINEbotを作った話【5】
メッセージ送信機能の追加
前回の記事で、スプレッドシートとの連携(ユーザー登録、メッセージログ)機能のコードを書きました。
このあと、【勤務表からデータを取得】してそれをユーザーに【送信】するわけですが、まずはこの【送信】部分のコードを今回書いていこうと思います。
メッセージ送信のいろいろ
一口にメッセージを送信すると言っても、ユーザー全員に送るのか、特定のユーザーに送るのかで書き方が変わってきます。今回は、
①replyTokenへ送信(返信)
②ユーザー全員へ送信
③特定のユーザーへ送信
④特定のユーザー(管理者)へ送信
以上4つに分けて記述していこうと思います。
①replyTokenへの送信(返信)
メッセージイベントやフォローイベントが発生したときに、replyTokenというものが発行されます。ちょっと意味がわかりませんが、要するに「返信先」ってことなのだと思います。
この機能を使うと、友達登録されたときに登録ありがとうメッセージを送ったり、ユーザーからのメッセージに対して返信したりすることができます。
function sendLineMessageFromReplyToken(token, replyText) {
var url = "https://api.line.me/v2/bot/message/reply";
var headers = {
"Content-Type": "application/json; charset=UTF-8",
"Authorization": "Bearer " + channel_access_token
};
var postData = {
"replyToken": token,
"messages": [{
"type": "text",
"text": replyText
}]
};
var options = {
"method": "POST",
"headers": headers,
"payload": JSON.stringify(postData)
};
return UrlFetchApp.fetch(url, options);
}
②ユーザー全員への送信
次に、ユーザー全員に同じメッセージを送信するときに使う関数です。
function sendLineMessageUsingBroadcast(text) {
var Url = "https://api.line.me/v2/bot/message/broadcast";
var postData = {
"messages": [{
"type": "text",
"text": text,
}
]};
var options = {
"method": "POST",
"headers": headers,
"payload": JSON.stringify(postData)
};
return UrlFetchApp.fetch(Url, options);
}
③特定のユーザーへ送信
続いて、特定のユーザーにメッセージを送るコードです。ユーザーに合わせて送信内容を変えることもできる便利な機能です。
function sendLineMessageFromUserId(text,userId) {
var url = "https://api.line.me/v2/bot/message/push";
var postData = {
"to": userId,
"messages": [{
"type": "text",
"text": text,
}]
};
var options = {
"method": "POST",
"headers": headers,
"payload": JSON.stringify(postData)
};
return UrlFetchApp.fetch(url, options);
}
④特定のユーザー(管理者)へ送信
最後に、管理者(自分)だけに送る関数も書いておきます。筆者はテスト送信するときなんかにこれを使います。コードの内容は③とほぼ一緒ですが、④行目の"ユーザーID"に自分のIDを入れる部分だけ違います。
function sendLineMessageToAdmin(text) {
var url = "https://api.line.me/v2/bot/message/push";
var postData = {
"to": "ユーザーID",
"messages": [{
"type": "text",
"text": text,
}]
};
var options = {
"method": "POST",
"headers": headers,
"payload": JSON.stringify(postData)
};
return UrlFetchApp.fetch(url, options);
}
IDは前回、
ブロック、ブロック解除のテストをしたときに、スプレッドシートに記入されていると思います。
青枠部分の文字列がIDです。これをコピーして、”ユーザーID”の部分に貼り付けてください。
メッセージ送信の注意点
LINEBotでメッセージを送るときに気をつけないといけない点があります。それは、上記の②~④の方法で送信する場合、無料枠が1000通/月に限られているということです。例えばユーザーが100人いる場合、”broadcast(全員)”では月に10通しか送れません。結構少ないです。
月に出勤日数が平均20日として、毎日全員にシフトを送るとすると、
1000通 / 20日 = 50人 が限度となりますが・・・
月によっては月末に1000通を超えて送信できなくなる
後々「勤務変更通知機能」を追加する予定なのですが、その分の「枠」も考えると、現実的には30人程度で無料枠は使い切ってしまう計算になります。
なので、一気に送信数が増える”broadcast”はできるだけ少なく使い、”reply”や"userId"を中心に使って送信数を抑える工夫もしなければいけません。
ちょっと不便なところも垣間見えてしまいましたが、一応抜け道もあります。例えば100人以上規模の大きな事業所でしたら、部署やチームという単位があると思います。公式アカウントを部署やチーム単位で1つずつ作ると、アカウントの数は増えますが、それぞれに1000通あてがわれますので、単純に送信できる数は増やせます。そんな工夫の仕方もあるということで。
テストの準備
前回書いた関数messageEventに少し書き加えます
function messageEvent(webhookData){
const userId = webhookData.source.userId;
const nickname = getUserProfile(userId);
const timestamp = new Date(webhookData.timestamp)
const message = webhookData.message.text.split("\n");
const replyToken = webhookData.replyToken;
const whatToDo = message[0];
const name = message[1];
const date = message[2];
const newshift = message[3];
const last_row = userSheet.getLastRow();
const lastRow = logSheet.getLastRow();
logSheet.getRange(lastRow+1,1).setValue(timestamp);
logSheet.getRange(lastRow+1,2).setValue(nickname);
logSheet.getRange(lastRow+1,3).setValue(userId);
logSheet.getRange(lastRow+1,4).setValue(message[0]);
logSheet.getRange(lastRow+1,5).setValue(message[1]);
logSheet.getRange(lastRow+1,6).setValue(message[2]);
logSheet.getRange(lastRow+1,7).setValue(message[3]);
}
前回ここまで書きました。最後の行( logSheet.getRange(lastRow+1,7).setValue(message[3]);の下)に以下のコードを加えてください。
switch (whatToDo) {
case 'こんにちは':
sendLineMessageFromReplyToken(replyToken, "さようなら");
break;
default:
return;
break;
}
"messageEvent"は、メッセージが来たら〇〇する、という関数ですが、これまではメッセージ内容のログを残すだけでした。今回足したのはメッセージの内容に対してのアクションの部分です。
「こんにちは」というメッセージには”sendLineMessageFromReplyToken”をつかって返事をする、返事の内容は「さようなら」、というコードです。
case文を使って書いているので、caseを増やせば他にもどんどん条件を追加していくことができます。
function messageEvent(webhookData){
const userId = webhookData.source.userId;
const nickname = getUserProfile(userId);
const timestamp = new Date(webhookData.timestamp)
const message = webhookData.message.text.split("\n");
const replyToken = webhookData.replyToken;
const whatToDo = message[0];
const name = message[1];
const date = message[2];
const newshift = message[3];
const last_row = userSheet.getLastRow();
const lastRow = logSheet.getLastRow();
logSheet.getRange(lastRow+1,1).setValue(timestamp);
logSheet.getRange(lastRow+1,2).setValue(nickname);
logSheet.getRange(lastRow+1,3).setValue(userId);
logSheet.getRange(lastRow+1,4).setValue(message[0]);
logSheet.getRange(lastRow+1,5).setValue(message[1]);
logSheet.getRange(lastRow+1,6).setValue(message[2]);
logSheet.getRange(lastRow+1,7).setValue(message[3]);
switch (whatToDo) {
case 'こんにちは':
sendLineMessageFromReplyToken(replyToken, "さようなら");
break;
default:
return;
break;
}
}
テストしてみましょう
書けたら一旦保存して、ウェブアプリとして公開(新規)をしてからテストしてみましょう。
このように返事が返ってきたらOKです!
これまでのコードまとめ
const channel_access_token = "トークン";
const headers = {
"Content-Type": "application/json; charset=UTF-8",
"Authorization": "Bearer " + channel_access_token
};
const spreadsheet = SpreadsheetApp.openById("ID");
const sheet = spreadsheet.getSheetByName("勤務表");
const userSheet = spreadsheet.getSheetByName("ユーザー");
const logSheet = spreadsheet.getSheetByName("ログ");
function doPost(e) {
const webhookData = JSON.parse(e.postData.contents).events[0];
const eventType = webhookData.type;
const replyToken = webhookData.replyToken;
switch(eventType){
case "follow":
follow(webhookData);
break;
case "message":
messageEvent(webhookData);
break;
case "unfollow":
unfollow(webhookData)
break;
}
}
function follow(webhookData){
const userId = webhookData.source.userId;
const nickname = getUserProfile(userId);
const last_row = userSheet.getLastRow();
userSheet.getRange(last_row+1,2).setValue(nickname);
userSheet.getRange(last_row+1,3).setValue(userId);
userSheet.getDataRange().removeDuplicates([3])
}
function messageEvent(webhookData){
const userId = webhookData.source.userId;
const nickname = getUserProfile(userId);
const timestamp = new Date(webhookData.timestamp)
const message = webhookData.message.text.split("\n");
const replyToken = webhookData.replyToken;
const whatToDo = message[0];
const name = message[1];
const date = message[2];
const newshift = message[3];
const last_row = userSheet.getLastRow();
const lastRow = logSheet.getLastRow();
logSheet.getRange(lastRow+1,1).setValue(timestamp);
logSheet.getRange(lastRow+1,2).setValue(nickname);
logSheet.getRange(lastRow+1,3).setValue(userId);
logSheet.getRange(lastRow+1,4).setValue(message[0]);
logSheet.getRange(lastRow+1,5).setValue(message[1]);
logSheet.getRange(lastRow+1,6).setValue(message[2]);
logSheet.getRange(lastRow+1,7).setValue(message[3]);
switch (whatToDo) {
case 'こんにちは':
sendLineMessageFromReplyToken(replyToken, "さようなら");
break;
default:
return;
break;
}
}
function unfollow(webhookData){
const data = userSheet.getDataRange()
const userId = webhookData.source.userId;
const userFinder = data.createTextFinder(userId).findAll();
for ( var i = 0; i < userFinder.length; i++ ) {
var userRow = userFinder[i].getRow();
var user = userFinder[i].offset(0,1).getValue()
userSheet.deleteRows(userRow);
}
}
function getUserProfile(userId){
const Url = 'https://api.line.me/v2/bot/profile/' + userId;
const userProfile = UrlFetchApp.fetch(Url,{
'headers': {
'Authorization' : 'Bearer ' + channel_access_token,
},
})
return JSON.parse(userProfile).displayName;
}
function sendLineMessageFromReplyToken(token, replyText) {
var url = "https://api.line.me/v2/bot/message/reply";
var headers = {
"Content-Type": "application/json; charset=UTF-8",
"Authorization": "Bearer " + channel_access_token
};
var postData = {
"replyToken": token,
"messages": [{
"type": "text",
"text": replyText
}]
};
var options = {
"method": "POST",
"headers": headers,
"payload": JSON.stringify(postData)
};
return UrlFetchApp.fetch(url, options);
}
function sendLineMessageUsingBroadcast(text) {
var Url = "https://api.line.me/v2/bot/message/broadcast";
var postData = {
"messages": [{
"type": "text",
"text": text,
}
]};
var options = {
"method": "POST",
"headers": headers,
"payload": JSON.stringify(postData)
};
return UrlFetchApp.fetch(Url, options);
}
function sendLineMessageFromUserId(text,userId) {
var url = "https://api.line.me/v2/bot/message/push";
var postData = {
"to": userId,
"messages": [{
"type": "text",
"text": text,
}]
};
var options = {
"method": "POST",
"headers": headers,
"payload": JSON.stringify(postData)
};
return UrlFetchApp.fetch(url, options);
}
function sendLineMessageToAdmin(text) {
var url = "https://api.line.me/v2/bot/message/push";
var postData = {
"to": "ユーザーID",
"messages": [{
"type": "text",
"text": text,
}]
};
var options = {
"method": "POST",
"headers": headers,
"payload": JSON.stringify(postData)
};
return UrlFetchApp.fetch(url, options);
}
ずいぶん長くなってきました。ここまで書けただけでも素人的には満足なのですが、一番重要な中身となる部分が次回から登場するので、ラスボスまでしっかり書ききりたいと思います。
この記事が気に入ったらサポートをしてみませんか?