SlackのStatusをカレンダーに合わせて自動的に変更するプログラム
Table Of Contents
- 用意するもの
- 使い方
- コード① Googleカレンダーを読み込むルーチン
- コード② SlackのAPIを呼ぶルーチン
- コード③ 毎朝未明に、最初のステータス設定をする時刻のトリガーを設定するルーチン
- コード⑤ ステータス設定時刻に呼び出される、ステータス設定と次の予定のトリガー設定を行うルーチン
Slackがここまで普及してきて、リモートワークも普及してくると、自身のStatusをこまめに変更して状況をお知らせするというシーンも増えてきますが、案外変更わすれて「保育園の送りが終わったのに対応出来ませんのママだった」「仕事が終わってたのにWork from Homeのままだった」みたいなことが起こるといやだなーということで、Googleカレンダーを読み込んで自動的にStatusを変えるGoogle Apps Scriptアプリを書いてみました。
初出: note
用意するもの
- Google Spreadsheet(tokenを置いておくための場所)
- 上記に紐付くスクリプト
- Slackのtoken(必要な権限…users.profile:write) ※昔作ったlegacy tokenで開発しちゃってるので、適切な権限を持ったtokenの作り方は別途調べてください…
- Googleカレンダーで新しい専用のカレンダーを作成する
これらを用意したら、以下のコード①~をスクリプトに並べた上で、setStatusTrigger関数を毎日未明に起動するようトリガーを掛ければ動作します
使い方
用意した専用のカレンダーに、ステータスを設定したい時間帯に予定をいれ、タイトルに表示する文字列を、説明に絵文字を設定するだけです。
最終的にこんな塩梅のカレンダーになります
コード① Googleカレンダーを読み込むルーチン
用意したGoogleカレンダーのカレンダーID(@group.calendar.google.comで終わるもの)を事前に確認ください。
// カレンダー取得
function getScheduleCalendar(startDate, endDate){
var cal = CalendarApp.getCalendarById("*******@group.calendar.google.com");
var myevents = cal.getEvents(startDate, endDate);
return myevents;
}
この中の***で書かれている部分に、用意したカレンダーのカレンダーIDを入れます。
コード② SlackのAPIを呼ぶルーチン
単純にSlackのAPIを呼んでいます。妙にAPIを呼ぶルーチンが重々しいのは、もっと頻繁にAPIを叩くスクリプトで使ったコードの使い回しです…
// Slack Status設定
function setSlackStatus(expire_time, free_status_text, free_status_emoji){
var expire_unixtime = expire_time.getTime()/1000;
// tokenを取得する
var logsheet = SpreadsheetApp.openByUrl("シートのURL").getSheetByName('シート名');
var token = logsheet.getRange('tokenがあるセル名').getValue();
var json = JSON.stringify(
{
"status_text": free_status_text,
"status_emoji": free_status_emoji,
"status_expiration": expire_unixtime
}
);
call_slack_api_common(token, 'users.profile.set',{"profile" : json});
};
/**
* call_slack_api_common(slack_token, api, param)
* @param {string} slack_token APIで利用するtoken
* @param {string} api 呼び出したいAPIの名称
* @param {Hash} param APIに受け渡すパラメータ
* @return {Hash} APIの返り値
*/
function call_slack_api_common(slack_token, api, param) {
// GETメソッドでAPIを叩く専用になっていることに留意
// URL生成1行コードは http://d.hatena.ne.jp/snaka72/20090220/1235141033 こちらから頂いた
var apiUrl = "https://slack.com/api/"+api+"?"+[(enc=encodeURIComponent)(i)+"="+enc(param[i]) for (i in param)].join('&');
var apiOptions =
{
"headers" : {
Authorization: 'Bearer ' + slack_token
},
"muteHttpExceptions" : true,
"method" : "get"
};
var responseApi = [];
var responseArray = [];
var responseOk = '';
do {
responseApi = UrlFetchApp.fetch(apiUrl, apiOptions );
if( responseApi.getResponseCode() == 200 ) {
responseArray = JSON.parse(responseApi.getContentText());
responseOk = responseArray.ok;
if (responseOk == false) {
if (responseArray.error == "rate limit") {
Utilities.sleep(60000);
Logger.log('Rate limit, Retry-After is unknown. Wait 60[s].')
} else {
Logger.log('Error: '+responseArray.error)
responseOk = true;
};
};
} else {
waittime = parseInt(responseApi.getAllHeaders()["Retry-After"],10)
Utilities.sleep(waittime*1000);
Logger.log('Rate limit, Retry-After is '+waittime+'[s], Waiting.')
}
} while ( responseOk != true );
return responseArray;
}
シートのURLとシート名、tokenがあるセル名は自分で埋めます。
コード③ 毎朝未明に、最初のステータス設定をする時刻のトリガーを設定するルーチン
毎朝未明に起動するように設定し、その日のカレンダーを全部読み込んで、最も時間がはやい予定の開始時刻(=初回のSlackステータス設定時刻)にコード⑤を起動するトリガーを設定するルーチンです
// 処理本体
// 毎朝動かすもの
function setStatusTrigger() {
var startDate = new Date();
startDate.setHours(0, 0, 0, 0);
var endDate = new Date();
endDate.setHours(23, 59, 59, 999);
var myevents = getScheduleCalendar(startDate, endDate);
if (myevents.length > 0) {
// 最初のカレンダーの開始時刻をみて初回を設定する
ScriptApp.newTrigger("set_freeformat").timeBased().at(myevents[0].getStartTime()).create();
} else {
// 土日などはカレンダーゼロという前提
setSlackStatus("weekend", endDate);
}
}
コード④ Google Apps Scriptのトリガーを消すルーチン
このスクリプトでは任意の時刻に起動するトリガーを用いてSlackのステータス変更をしますが、使用後のトリガーを放置するとゴミのようにたまって悲しいことになるので、毎回けす必要がありますが、そのルーチンです
// Triggerの消去
function removeTrigger(function_name){
// kickしたtriggerを消去する
var triggers = ScriptApp.getProjectTriggers();
for (var i = 0; i < triggers.length; i++) {
if (triggers[i].getHandlerFunction() == function_name)
{
ScriptApp.deleteTrigger(triggers[i]);
}
}
}
コード⑤ ステータス設定時刻に呼び出される、ステータス設定と次の予定のトリガー設定を行うルーチン
まず、自分自身のトリガーを全部消した上で、カレンダーを再取得し、SlackのStatusを変え、その日の残りの予定の有無(予定の個数で確認、1個は必ずあるはずなので2個以上かどうかで確認)を確認して、あれば次の起動トリガーをかけます。
// 自由な設定を出来るようにするモード
function set_freeformat(){
// kickしたtriggerを消去する
removeTrigger("set_freeformat")
// 起動された時間周辺のカレンダーを取得する
var startDate = new Date();
startDate.setMinutes(startDate.getMinutes()-5);
var endDate = new Date();
endDate.setHours(23, 59, 59, 999);
var myevents = getScheduleCalendar(startDate, endDate);
var status_text = myevents[0].getTitle();
var status_emoji = myevents[0].getDescription();
var status_endtime = myevents[0].getEndTime();
// Slackのstatusを変える
setSlackStatus(status_endtime, status_text, status_emoji);
// 次のカレンダーは入っているか?
if (myevents.length > 1) {
// あればこの関数のトリガーを設定する
ScriptApp.newTrigger("set_freeformat" ).timeBased().at(myevents[1].getStartTime()).create();
}
};