毎日定刻に予定を知らせてくれるやつが欲しい
ラボでSlackを導入したところタイトルのような要望があったのでやってみました。
もともと#generalにGoogle Calender Appが予定前日に投稿してくれていたのですが、「当日朝にもDMがほしいけど設定ができない」との声があったという経緯があります。
本記事の目次
ラボの日程管理にGoogle Calenderを使っていたので、Google Apps Scriptを利用しました。
いるもの
- Googleアカウント
- 参照したいGoogle Calender
- slack api token (scopeはusers:read, chat:write:bot あたりかな)
- 投稿先のchannelまたはuserのID
slack appのインテグレーションとtoken取得は調べるといろいろ出てくるので割愛します。
流れとしては
Google Apps Scriptのtriggerでスクリプト起動
→投稿する文章を形成
→json形式でPOST request
→発言
といった感じになります。
user IDの取得
channelに対して投稿する場合はchannel名でいいけれど、個人にDMという形で投稿するならuser IDを取得する必要があります。
今回はひとりのIDを取得するだけだったので手軽にブラウザで
https://slack.com/api/users.list?token=<取得したtoken>
して探しました。
カレンダーの取得とイベントの取得
//カレンダー取得 var myCals = CalendarApp.getCalendarById(<カレンダーID>); //todayを今日に設定 var today = new Date(); //今日の予定を取得 var myEvents = myCals.getEventsForDay(today);
<カレンダーID>には"*@group.calendar.google.com"を入力します。
これで今日の予定がmyEventsに格納されました。
POST bodyの整形
2/24 There are n events today イベント名 12:00 at 2階ラウンジ 担当:maple イベント名 17:00 at 302講義室 担当:おもち ~
こんな感じにしてほしいということだったのでこの通り整形していきます。
日時表記の整形
todayには
Sat Feb 24 12:19:40 GMT+09:00 2018
こんな感じで日時が入っているので、これを目的の形式にしていきます。
イベントの開始時刻もこれなので、併せて処理を書いてみました。
//日付表記を 'M/d' 形式に function MMdd(date){ return Utilities.formatDate(date, 'JST', 'M/d'); } //時刻表記を 'HH:mm' 形式に function HHmm(date){ return Utilities.formatDate(date, 'JST', 'HH:mm'); }
1行目を決定
日付とイベントの数を記入
2/24 There are n events today
英語はisとかareとかあって面倒ですね。
var strBody = "*" + MMdd(today) + "* "; if(myEvents.length == 0){ strBody += "There are no events today"; } else if(myEvents.length == 1){ strBody += "There is *1* event today"; } else{ strBody += "There are *" + myEvents.length + "* events today"; }
2行目以降を決定
ゴリ押しです。
for(var i = 0; i < myEvents.length; i++){ strBody += "\n*" + myEvents[i].getTitle(); strBody += "* " + HHmm(myEvents[i].getStartTime()); strBody += " at " + myEvents[i].getLocation(); strBody += " 担当:" + myEvents[i].getDescription(); }
POST requestする
Google Apps ScriptではUrlFetchAppクラスでHTTPリクエストが定義されています。
Argumentsのkeyはslack側の指定に従います(slack API methods|chat.postMessage 参照)
//json形式に var Arguments = { token : <取得したtoken>, channel : <channel名またはユーザーID>, text : strBody }; //POST指定とArgumentsをpayloadに指定 var options = { 'method' : 'post', 'payload' : Arguments }; //以上の設定でPOSTリクエストを送信 var url = 'https://slack.com/api/chat.postMessage'; var response = UrlFetchApp.fetch(url, options); Logger.log(response.getContentText());
ここまででとりあえず予定を取得して投稿ができるようになりました。
次は毎日定刻に動くようにトリガーを設定します。
定刻に動くようにする
GASのトリガーって実はよくわからなくて、"日タイマー"で毎日9時って設定すると9時~10時の間のいつかに開始する、っていう感じになってしまうんです
しかし、"特定の日時"で時刻もきっちり指定できるという謎仕様。
この"特定の日時"指定は1回で使い捨てなので、少し工夫して使ってみました。
整理すると、
毎日、目的の時間より前にトリガーセットスクリプトを起動
→トリガーセットスクリプトがその日の9時に"特定の日時"指定でトリガーをセット
→そのトリガーに従ってリマインダースクリプトが起動
→slackに投稿される
という流れになります。
トリガーは2回発動するというわけです。
function setTrigger() { var triggerDay = new Date(); triggerDay.setHours(9); triggerDay.setMinutes(0); ScriptApp.newTrigger("Reminder").timeBased().at(triggerDay).create(); }
この関数について"日タイマー"で7時とかでトリガーを設定しておけばOKです。
これで作製したトリガーは日々たまってしまうので、リマインダースクリプト自体にトリガーを削除する文を入れておくと吉です。
function deleteTrigger() { var triggers = ScriptApp.getProjectTriggers(); for(var i=0; i < triggers.length; i++) { if (triggers[i].getHandlerFunction() == "Reminder") { ScriptApp.deleteTrigger(triggers[i]); } } }
以上で一応動くものができました。