GoogleSpreadsheet + GAS + Slackで日直管理と通知
やりたいこと
一定期間ごとに何らかの日直をローテーションで担当し、担当者にSlackで通知したい。
日直の内容や期間、メンバー表はGoogleSpreadsheetで管理する。
前提:SlackのIncoming Webhookを使えるようにする
https://api.slack.com/apps からIncoming Webhookを使えるようにアプリを登録する。
https://hooks.slack.com/services/*****
のようなWebhook URLが払い出されるので取得しておく。
GoogleSpreadsheetの設定
メンバー表や通知設定をシートで定義する。
membersシート
SlackのIDの名前の対応表。
「朝会司会」や「レポート作成」などの仕事ごとにローテーション表を管理する際には名前で管理しておき、日直が決まったら名前 → SlackIDを引いてメッセージ通知時に使用する。
works
日直を設定したい仕事ごとの定義。
name
は仕事の名前。
intervals
は通知間隔の日数で、毎日であれば1を、1週間ごとであれば7を指定する。
next
は次回の通知日。定期開催ではなく、何らかの調整が発生したら手動で修正する。
朝会司会、レポート作成
worksで定義したnameのシート名でシートを作成する。
シートの2行目以降に日直の候補となる名前を記述する。
GASの設定
拡張機能
→ Apps Script
をクリックすると、GASの入力画面になる。
コード
シートの定義を読み込み、日直担当を決め通知を行う。
さらに、次回の通知日や担当者を更新し、シートの定義に反映させる。
トリガーの実行対象は main
関数。
const SLACK_URL = 'https://hooks.slack.com/services/...'
function getRows(sheetName) {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName)
const [header, ...rows] = sheet.getDataRange().getValues()
return rows.map(row => Object.fromEntries(header.map((key, i) => [key, row[i]])))
}
function getNames(sheetName) {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName)
//namesは [[user1], [user2], ...] のような二次元配列
const [_, ...names]= sheet.getDataRange().getValues()
return names
}
function rotate(sheetName) {
const names = getNames(sheetName)
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName)
// 先頭を末尾に移動
names.push(names.shift())
// 元のデータをクリア
sheet.getRange(2, 1, sheet.getLastRow() - 1).clearContent()
// 並び替えたデータをシートに反映
sheet.getRange(2, 1, names.length, 1).setValues(names)
}
function isSameDate(date1, date2) {
return date1.getFullYear() === date2.getFullYear() &&
date1.getMonth() === date2.getMonth() &&
date1.getDate() === date2.getDate()
}
function postSlack(workName, slackId) {
const text = `今日の ${workName} の担当は <@${slackId}> です`
const payload = JSON.stringify({text: text})
const options = {
method: 'post',
contentType: 'application/json',
payload: payload,
}
UrlFetchApp.fetch(SLACK_URL, options)
}
function calculateNextDate(work) {
const nextDate = work.next
return new Date(nextDate.setDate(nextDate.getDate() + work.intervals))
}
// 次回通知日を更新する
function updateWorksSheet(work, index) {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('works')
const nextDate = calculateNextDate(work)
// 行は1から始まり、1行目はヘッダー行なので+2
// C列なので3を指定
sheet.getRange(index + 2, 3).setValue(nextDate)
}
function main() {
const members = getRows('members')
const works = getRows('works')
const today = new Date()
works.forEach((work, index) => {
// 通知日以外はスキップ
if ( !isSameDate(work.next, today) ) { return }
const dayshift = getNames(work.name).flat()[0]
const member = members.find(member => member.name === dayshift)
postSlack(work.name, member.id)
updateWorksSheet(work, index)
rotate(work.name)
})
}
トリガー
コードを実行するためのトリガーを設定する。
毎日実行するようにしておき、コード側で実行日が通知日かどうかを判定して通知する。
時刻は通知したい時間に合わせて設定する。
実行結果
ローテーションの順番を変えたいとき
GoogleSpreadsheet上で行を選択してドラッグ&ドロップで順番を入れ替えることができる。
日直担当が次の日に休みで順番を調整したい場合に便利。
Discussion