はじめに
あけましておめでとうございます。
日報書いてますか?
私の所属するチームには日報の文化はないのですが、日々の振り返りのために自主的に日報を書き始めました。
新人研修の頃にはテキストエディタを開いてマークダウン形式で日報を書いていました。
書き終わったらテキストをコピーしてSlackの新人研修チャンネルにスニペットで貼り付けていました。
これはイケてない。
今日のスケジュールを振り返るためにいちいちカレンダーを開かなくてはいけないし、夕礼の時間までに日報を書かなくてはいけないのに忘れてしまうこともしばしば。書き終わってからいちいちコピペするのも面倒です。
私の理想の日報体験は以下の通りです。
- 終業時間のちょっと前に日報のリマインダーが欲しい
- 今日のスケジュールを振り返りながら書きたい
- 書き終わったらSlackのチームチャンネルに日報を共有したい
これをGoogleフォームとGoogle Apps Scriptの組み合わせで実現できましたので紹介します。
以下、Google Apps ScriptをGASと表記します。
Googleフォームで日報フォームを作成
フォームに今日のスケジュールを追加しSlackに回答用URLを送信するGASを書く
GASで新規プロジェクトを作成してスクリプトを書きます。
function main() {
// GoogleフォームをID指定でオープン
var form = FormApp.openById('abcd');
// フォームのタイトルに今日の日付を設定
var today = new Date();
var year = today.getYear() + '';
var month = (today.getMonth() + 1)+ '';
var day = today.getDate() + '';
var form_desc = year + '年' + month + '月' + day + '日';
form.setTitle('日報@' + form_desc);
var schedules = getTodayEvents();
form.setDescription(schedules)
// 回答用のURLをSlackに投稿
form_url = form.getPublishedUrl();
postMessage(form_url);
}
function getTodayEvents() {
// アカウントのデフォルトカレンダーから
// 00:00~23:59までのイベントを取得
var now = new Date();
var today_start = new Date(now.getYear(), now.getMonth(), now.getDate());
var today_end = new Date(today_start.getTime() + (23 * 60 * 60 * 1000 + 59 * 60 * 1000));
var events = CalendarApp.getDefaultCalendar().getEvents(today_start, today_end);
var allDayEvents = []
var notAllDayEvents = []
var text = '';
// allDayイベントとそうでないイベントをわける
for (var i = 0; i < events.length; i++) {
if (events[i].isAllDayEvent()) {
allDayEvents.push(events[i]);
} else {
notAllDayEvents.push(events[i]);
}
}
notAllDayEvents.sort(function(left, right) {
// 開始時間でソートする
var l_start = left.getStartTime().getHours() * 100 + left.getStartTime().getMinutes();
var r_start = right.getStartTime().getHours() * 100 + right.getStartTime().getMinutes();
if (l_start < r_start) return -1;
if (l_start > r_start) return 1;
// 開始時間が同じなら終了時間でソートする
var l_end = left.getEndTime().getHours() * 100 + left.getEndTime().getMinutes();
var r_end = right.getEndTime().getHours() * 100 + right.getEndTime().getMinutes();
if (l_end < r_end) return -1;
if (l_end > r_end) return 1;
return 0;
});
// allDayイベント
for (var i = 0; i < allDayEvents.length; i++) {
text = text + allDayEvents[i].getTitle() + '\n';
}
// 日中イベント
for (var i = 0; i < notAllDayEvents.length; i++) {
var startTime = notAllDayEvents[i].getStartTime();
var endTime = notAllDayEvents[i].getEndTime();
var start = ('00' + startTime.getHours()).slice(-2) + ':' + ('00' + startTime.getMinutes()).slice(-2);
var end = ('00' + endTime.getHours()).slice(-2) + ':' + ('00' + endTime.getMinutes()).slice(-2);
text = text + start + '~' + end + ': '+ notAllDayEvents[i].getTitle() + '\n';
}
return text
}
function postMessage(form_url) {
// incoming webhookのURL
var url = "https://hooks.slack.com/services/A/AAAAAAAA"
var block = {
"type": "section",
"text": {
"type": "mrkdwn",
"text": "日報を書きましょう\n<" + form_url + "|リンク>"
}
}
var payload = {
"text": '日報の時間です',
"blocks": [block]
}
// POSTオプション
var options = {
"method" : "post",
"contentType": 'application/json',
"payload": JSON.stringify(payload),
"muteHttpExceptions": true
}
// POSTリクエスト
var response = UrlFetchApp.fetch(url, options);
var responseCode = response.getResponseCode();
}
Slackに投稿するところはincoming webhook
でもchat.postMessage
でもお好きな方法でどうぞ。
GASを実行すると許可を求められるので内容を確認したうえで許可します。
問題なければSlackに回答用フォームのリンクが投稿されます。
リンクを開くとフォームが表示されます。
フォームのタイトルには今日の日付が入り、説明欄には今日のスケジュールが表示されていい感じ
Slackにリマインダーを投稿
GASが平日の夕方に実行されるようにトリガーを設定します。
毎週月曜日、毎週火曜日、毎週水曜日、毎週木曜日、毎週金曜日にトリガーを追加します。
もうちょっと柔軟な設定ができるといいんだけどなぁ。
フォームに回答すると実行されるGASを書く
フォーム編集画面を開き、右上のボタンを押してスクリプトエディタを選択します。
フォーム回答時に実行されるGASを書きます。
Googleフォーム回答時に受け取るイベントオブジェクトについての詳細は↓のGoogle Forms eventsのForm submitをご覧ください。
Event Objects | Apps Script | Google Developers
function main(e) {
// フォーム回答時にはEvent Objectを受け取る
var form_response = e.response;
// Slackに投稿するペイロードを作成
var payload = build_payload(form_response)
postMessage(payload);
}
function build_payload(form_response) {
var payload = {
'blocks': []
}
var itemResponses = form_response.getItemResponses();
for (var i = 0; i < itemResponses.length; i++) {
var itemResponse = itemResponses[i];
var title = itemResponse.getItem().getTitle();
var response = itemResponse.getResponse();
var block = {
'type': 'section',
'text': {
'type': 'mrkdwn',
'text': '*' + title + '*' + '\n' + response
}
};
payload.blocks.push(block);
}
return payload
}
function postMessage(payload) {
// incoming webhookのURL
var url = "https://hooks.slack.com/services/A/AAAAAAAA"
// POSTオプション
var options = {
"method" : "post",
"contentType": 'application/json',
"payload": JSON.stringify(payload),
"muteHttpExceptions": true
}
// POSTリクエスト
var response = UrlFetchApp.fetch(url, options);
var responseCode = response.getResponseCode();
}
回答されるとスクリプトが実行されるようにトリガーを設定します。
赤枠のなかがポイントです。
デモ
Slackに送られてきたURLを開いてフォームに回答します。
うまくいきました。
参考
Google Developers
Class FormApp | Apps Script | Google Developers
Event Objects | Apps Script | Google Developers
Class UrlFetchApp | Apps Script | Google Developers
Slack
Slack でのIncoming Webhook の利用 | Slack
chat.postMessage method | Slack