会社の同僚からこんなのできるー?とお題を頂いたので2時間くらいで作ってみました。
MQTTみたいだなと思ったので用語をそっちに合わせてみた。
2020/10/03 追記
GASライブラリ利用パターンもやってみました。
codelife.cafe
動作概要
①LINE botに対してメッセージを送信するとGoogleスプレッドシートの通知先シートに登録されているユーザに対して自動で転送します。
※以下の画像は自分自身も通知先なのでメッセージが届いちゃってます。
通知先はスプレッドシートで管理しています。
※ユーザIDはLINEアプリから見える方ではなくWebhookで飛んできた長い文字列です。手動登録できません。
②全ての投稿はログシートに記録されます
日時はタイムスタンプを変換するのが面倒だったのでGAS側で new Date
しましたごめんなさい。
③通知先として登録してもらうには設定シートの合言葉と一致するメッセージを送信する
カンマ区切りで複数設定可能。「登録」だと簡単すぎるのでもうちょっと違う合言葉作ったらいいと思います。
構築手順
取り急ぎ箇条書きレベルで書いておきます。また後日画像いれつつ解説を追記します。
LINE Messaging API の利用方法はここが分かりやすく書いてありましたので参照ください。
細かい仕様は公式のドキュメントがめちゃ分かりやすくて感動した。
1. LINE botを作る
2. スプレッドシートを作成
3. GAS設定と公開
4. 利用者にbotの友達登録用のQRコードを配る
コード全文
エラー処理とかちゃんと出来てないので実用するにはもうちょっと書き直しが必要。
GASライブラリないのかなー。
const ACCESS_TOKEN = PropertiesService.getScriptProperties().getProperty("token"); const LOG_SHEET_NAME = 'ログ'; const SETTING_SHEET_NAME = '設定'; const SUBSCRIBER_SHEET_NAME = '通知先'; const ss = SpreadsheetApp.getActiveSpreadsheet(); const logSheet = ss.getSheetByName(LOG_SHEET_NAME); const settingSheet = ss.getSheetByName(SETTING_SHEET_NAME); const subscriberSheet = ss.getSheetByName(SUBSCRIBER_SHEET_NAME); function doPost(e) { const event = JSON.parse(e.postData.contents).events[0]; const date = Utilities.formatDate(new Date(), 'JST', 'yyyy/MM/dd HH:mm:ss'); const userId = event.source.userId; const userProfile = getLineUserName(userId); const userName = userProfile.displayName; const userMessage = event.message.text; const rowContents = [date,userId,userName,userMessage]; logSheet.appendRow(rowContents); // 設定シートのキーワードを含むかどうかで動作分岐 const keywords = getKeywords(); const replyMessage = keywords.includes(userMessage) ? register(userId,userName) : push(userMessage,userName); const replyToken = event.replyToken; UrlFetchApp.fetch('https://api.line.me/v2/bot/message/reply', { 'headers': { 'Content-Type': 'application/json; charset=UTF-8', 'Authorization': 'Bearer ' + ACCESS_TOKEN, }, 'method': 'post', 'payload': JSON.stringify({ 'replyToken': replyToken, 'messages': [{ 'type': 'text', 'text': replyMessage, }], }), }); return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON); } function register(userId,userName){ const subscriber = getSubscriber(); if(!subscriber.includes(userId)){ const rowContents = [userId,userName]; subscriberSheet.appendRow(rowContents); return '登録完了'; } else { return '既に登録済みです'; } } function push(userMessage,userName){ const subscriber = getSubscriber(); if(subscriber.length === 0){ return '通知先が登録されていません'; } try{ UrlFetchApp.fetch('https://api.line.me/v2/bot/message/multicast', { 'headers': { 'Content-Type': 'application/json; charset=UTF-8', 'Authorization': 'Bearer ' + ACCESS_TOKEN, }, 'method': 'post', 'payload': JSON.stringify({ 'to': subscriber, 'messages': [{ 'type': 'text', 'text': `送信者: ${userName}\n本文: ${userMessage}`, }], }), }); return '送信完了'; } catch(e) { console.error(e); return '送信に失敗しました'; } } function getLineUserName(userId){ const response = UrlFetchApp.fetch(`https://api.line.me/v2/bot/profile/${userId}`, { 'headers': { "Content-Type" : "application/json charset=UTF-8", 'Authorization': 'Bearer ' + ACCESS_TOKEN, }, 'method': 'get' }); return JSON.parse(response); } function getKeywords(){ const keywords = settingSheet.getRange(2, 2).getValue().split(','); return keywords; } function getSubscriber(){ const subscriberSheetLastRow = subscriberSheet.getLastRow(); let subscriber = new Array(); if(subscriberSheetLastRow > 1){ subscriber = subscriberSheet.getRange(2, 1, subscriberSheetLastRow - 1,1).getValues().flat(); } return subscriber; }