LoginSignup
5
2

More than 1 year has passed since last update.

Slackに通知してくれる日直リマインダーを作る

Last updated at Posted at 2021-12-02

背景

弊社では、エンジニアの進捗管理や情報共有なとを目的とした日次定例MTGがあります。
日次定例MTGでは、日ごとに日直を決めて司会進行と気になる記事(ニュース)を共有することになっているのですが、

「あ、やべ、今日は日直だった!なにも準備してない!」

ということが度々起きたので、日直リマインダーを作ることにしました。

前提

日次定例MTGで使っているツール

  • 日報やニュースの共有:Slack
  • MTG時刻の管理:Googleカレンダー
  • 日直の管理:スプレッドシート
  • ビデオ通話:Zoom

日直の管理方法

日次定例MTGではスプレッドシート上に簡単なカレンダーが作られていて、日毎に日直の名前を入れる。という方法で管理されていました。
後述しますが、このシートから日直リマインダーを作る場合、今日の日付から日直の名前を参照する必要があったので、少し複雑な処理ができるツールを利用することになりました。
スプレッドシート上のカレンダーは下記画像のような形式です。
スクリーンショット 2021-12-02 15.28.07.png

ツールの選定

Slackはとても便利で、手軽にリマインダーを作れそうなツールがいくつかあったので、選定からはじめました。

  1. Slackのリマインド機能
    特別なツールやインストールを必要とせず、簡単に設定できる。
    しかし、スプレッドシートと連携できないため、いつ、誰にリマインドするかを毎度設定しなければならない。
    不採用

  2. Slackワークフロー
    ワークフロービルダーにスプレッドシートアプリをインストールする必要があるが、ノーコードで設定が完結する。
    スプレッドシートと連携できてCRUDの機能が一通り用意されているが、「日毎に参照するセルの値を変える」などの細かい操作はできなかった。
    いまの日直管理シートの書き方では、うまく通知できなさそう。
    不採用

  3. GAS(Google Apps Script)
    Googleによって開発されたスクリプト言語で、JavaScriptでプログラムを記述して複雑な処理を実行できる。
    スプレッドシートやカレンダーとも連携でき、SlackAPI経由でSlack側にメッセージ送信等も可能。
    採用

リマインダの作成

1. SlackAPIトークンを取得する

大まかに下記の3ステップで取得できます。
取得方法について、こちらの記事の説明が詳しくて分かりやすいです。
 1. Slack Botを作成する
 2. Slackのワークスペースに作ったSlack Botをインストールする
 3. メッセージ送信用トークンを取得する

2. Apps Scriptのエディタを開く

ブラウザでスプレッドシートを開き、拡張機能 > Apps Script を選択すると、GASの編集画面が起動します。
スクリーンショット 2021-12-02 15.46.07.png
スクリーンショット 2021-12-02 15.49.52.png

3. コードを書く

②で開いたApp ScriptのエディタにJavaScriptでリマインド機能を実装します。
詳細は省きますが、大まかに下記の用件を満たす機能を作成しました。
・ 土日、祝祭日に通知をしないように、Googleカレンダーを参照して日次定例MTGの予定のある日だけ実行する
・ 当日に通知されても準備が間に合わないケースがあるため、日直がある日の2営業日前から毎日通知する
・ 日直にはメンションで通知する

実装したコードも載せておきます。

// 毎日の日直を通知する
function dailyFacilitatorReminder() {
  const date = new Date();

  // カレンダーを参照して定例がある日だけ実行
  if (!hasDailyMeeting(date)) {
     console.log('本日は定例がありません。');
    return;
  }

  // スプレッドシード上にある日直カレンダーから最大10日先までの日程を参照し、
  // 直近の最大3名に日直のリマインドメッセージを生成する。
  let messages = [];
  for (let i = 0; i < 10; i++) {
    const facilitator_name = findFacilitatorNameFromSpreadsheet(date);
    if (facilitator_name) {
      if (messages.length == 0) {
        messages.push('本日の日直は<@' + facilitator_name + '>さんです。');
      } else if (messages.length == 1) {
        messages.push('次の日直は<@' + facilitator_name + '>さんです。');
      } else if (messages.length <= 2) {
        messages.push('その次の日直は<@' + facilitator_name + '>さんです。');
        break;
      }
    }
    date.setDate(date.getDate() + 1);
  }

  // メッセージをSlackに送信する
  sendSlackMessage(messages.join('\n'));
}

// 技術部日次定例があるか
function hasDailyMeeting(date) {
  const calendar_id = 'foobar@gmail.com';
  const event_name = '技術部日次定例';
  const calendar = CalendarApp.getCalendarById(calendar_id);
  const calendar_events = calendar.getEventsForDay(date, {search: event_name, max: 1});
  return Boolean(calendar_events.length);
}

// スプレッドシート上に作成されたカレンダーから日直の名前を取得する
function findFacilitatorNameFromSpreadsheet(date)
{
  const year = date.getFullYear() % 100;
  const month = date.getMonth() + 1;
  const day = date.getDate();
  const sheet_name = year + '-' + month + '';
  const targeet_date = month + '/' + day;
  const sheet_id = '/** シートID **/';
  const ss = SpreadsheetApp.openById(sheet_id);
  const sheet = ss.getSheetByName(sheet_name);
  const text_finder = sheet.createTextFinder(targeet_date);
  const cell = text_finder.findNext().getA1Notation();
  const target_cell = cell.slice(0, -1) + (Number(cell.slice(-1)) + 2);
  const facilitator_name = sheet.getRange(target_cell).getValue();
  return getSlackName(facilitator_name);
}

// カレンダーに記載されている名前からSlackでの名前を取得する
function getSlackName(name) {
  const user_name_map = {
    '〇〇': 'U01A0DFSQ2Y',
    '△△': 'ECGE22YGAHT',
    '◇◇': 'P3E1ALVMEWD',
  };
  return user_name_map[name] ?? '';
}

// Slackにメッセージを送信
async function sendSlackMessage(message) {
  const url     = 'https://slack.com/api/chat.postMessage';
  const method  = 'post'
  const payload = {
    'token'      : '/** SlackAPIのトークン **/',
    'channel'    : '/** チャンネル名 **/',
    'text'       : message,
  };
  const params = {
  'method' : method,
  'payload' : payload
  };
  UrlFetchApp.fetch(url, params);
}

4. スクリプトを自動で実行してくれるように、トリガーを設定する

  • App Scriptのエディタ画面の左のタブメニューから[トリガー]を押下し、トリガー管理画面に遷移
  • 画面右下の[+トリガーを追加]ボタンを押下して、トリガー登録に遷移
  • 毎日定時に実行してくれるように入力後に[保存]ボタンを押下し、トリガーを登録

 今回作成したスクリプトの場合)
 実行する関数:dailyFacilitatorReminder
 イベントのソース:時間主導型
 トリガーのタイプ:日付ベースのタイマー
 時刻:午前9時〜10時

5. 動作テスト

ここまで来たら、リマインダーは一通り完成です。
トリガーが発火するのを待つか、エディタから直接実行することで動作を確認することができます。
うまくいくと下記画像のようになります。

最後に

今回初めてGASに触れましたが、GASでもっといろいろなことができそうでワクワクしました。
こんなに便利な機能をタダで提供してくれるGoogleさまには頭が上がりません。

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2