【チャットワーク】タスクの自動リマインド機能をつける(Google Apps Script)※2020/3/10修正

Google Apps Script

(2020/03/10更新)
V8ランタイムに対応しました。

(2019/02/12更新)
コードを一部修正しました。ご指摘ありがとうございました!

(2018/06/11更新)
未完了タスクがない場合にエラー終了する不具合を修正しました!また、期限なしタスクはリマインドしないようにしました。

はじめに

チャットワークにはタスクのリマインド機能がありません。
期限をつけてタスクを登録したのに忘れてしまったり、他のメンバーにスルーされてしまったりして、いつの間にか期限が過ぎてた!ということもあるかと思います。

今回は チャットワークAPI と Google Apps Script (通称GAS)を使って、毎日指定した時間帯に自動でリマインドしてくれる機能をつくりました。無料でできて簡単なのでぜひお試しください。

やりたいこと

  • 期日が近づいたタスクをリマインドします。
  • GASのトリガー機能を利用して、毎日好きな時間帯にリマインドを実行できます。
  • どのグループチャットで通知するか、何日前からリマインドするか、をスプレッドシート上で設定できます。

チャットワークAPIトークンを取得

チャットワークAPIの利用申請し、APIトークンを取得してください。
トークンの取得方法はこちら→ https://developer.chatwork.com/ja/authenticate.html

Google Apps Scriptの設定

GoogleDriveで スプレッドシート を新規作成します。

スプレッドシート上部のメニューから「ツール > スクリプトエディタ」 を開きます。

デフォルトで入力されているコードは消しちゃいます。

下のコードをまるっとコピペします。

/*---- 初期設定ここから ----*/

// チャットワークAPIトークンを設定
 var ChatWorkToken = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

// 設定用シートのシート名
 var SHEETNAME = 'シート1';

/*---- 初期設定ここまで ----*/

// 管理用メニューを追加
function onOpen() {
  SpreadsheetApp.getUi()
      .createMenu('管理用')
      .addItem('最新のルーム一覧を読込む', 'getRooms')
      .addItem('いますぐリマインド実行', 'myFunction')
      .addToUi();
}

// リマインド実行のメインのファンクション
function myFunction(){

  // スプレッドシート読み込み 
  // spreadsheet読込->json取得
  var sheet = getSheet();
  var json = convertSheet2Json(sheet);

  if( json == false ){
    Browser.msgBox( "シートに何もありません" );
    return false;
  }
  // ルーム毎にリマインド
  for(var i=0; i<json.length; i++) {
    var obj = json[i];
    
    if( obj.num_of_days !== '' ){
      // ルーム毎にリマインド
      //Logger.log( obj.room_id + ", " + obj.num_of_days );
      sendRemind( obj.room_id, obj.num_of_days);
    }
  }
}

// 最新のルーム一覧を読込む
function getRooms(){

  // シートを読込み
  var sheet = getSheet();
  var previousValues = readSheet(sheet);  
  
  // 既存の設定をルームIDをキーにした連想配列に残す
  var array = [];
  if( previousValues != false ){
    for(var i=0; i<previousValues.length; i++) {
      var key = previousValues[i][0];
      var value = previousValues[i][1];
      array[key] = value;
    }
  }
    
  // ルーム一覧を読み込み
  // ChatWork apiに投げるパラメータを設定
  var params = {
    headers : {"X-ChatWorkToken" : ChatWorkToken},
    method : "get"
  };

  //ルーム一覧を取得するURL
  var url = "https://api.chatwork.com/v2/rooms";

  //チャットワークAPIエンドポイントからレスポンスを取得
  var strRespons = UrlFetchApp.fetch(url, params);

  // 中身がなかったら終了 (2018/6/11修正)
  if( strRespons.getContentText() == '' ){ return false; }

  // シートをクリア
  sheet.clearContents();
  
  // レスポンス文字列をJSON形式として解析しJSONオブジェクトとして返す
  var json = JSON.parse(strRespons.getContentText());

  // 二次元配列を作成し、シートに貼り付ける
  // 配列を定義
  var values = [];
  // 1行目はフィールド名を挿入
  values[0] = [ 'ルームID', 'リマインド日数', 'ルーム名' ];
  
  // jsonの内容を2行目以降に追加
  var i = 1;
  json.forEach(function(obj) {
    var num_of_days = ( array[obj.room_id] )? array[obj.room_id] : '';
    var line = [ obj.room_id, num_of_days, obj.name ];
    values.push( line );
  });
  
  // シートに貼付け
  sheet.getRange(1,1,values.length,values[0].length).setValues( values );
}

function sendRemind(room_id, num_of_days){

  // ルームのタスクを読込み
  // ChatWork apiに投げるパラメータを設定
  var params = {
    headers : {"X-ChatWorkToken" : ChatWorkToken},
    method : "get"
  };
  
  // 未完了のタスクを取得するURL
  var url = "https://api.chatwork.com/v2/rooms/" + room_id + "/tasks?status=open";

  //チャットワークAPIエンドポイントからレスポンスを取得
  var strRespons = UrlFetchApp.fetch(url, params);

  // 中身がなかったら終了 (2018/6/11修正)
  if( strRespons.getContentText() == '' ){ return false; }
  
  // レスポンス文字列をJSON形式として解析しJSONオブジェクトとして返す
  var json = JSON.parse(strRespons.getContentText());

  // 昇順で並べ替え
  json.sort(function(a,b){
    if(a.limit_time < b.limit_time) return -1; if(a.limit_time > b.limit_time) return 1;
    return 0;
  });  
  
  // 現在の日付取得
  var nowDate = new Date();
  // リマインドする最大の日付の23:59:59をセットする
  var refDate = new Date();
  refDate.setDate( nowDate.getDate() + num_of_days );
  refDate.setHours(23);
  refDate.setMinutes(59);
  refDate.setSeconds(59);
  
  /* チャットワークに送る文字列のヘッダー */
  var strBody = "[info][title]期限が近づいているタスクをお知らせします。[/title]";

  // 前回の日付を代入して比較する変数
  var lastLimitDate = '';
  
  // タスク毎に予定を作成
  json.some(function(obj) {
   
    // 期限なしタスクなら何もせず次へ
    if( obj.limit_time == 0 ) return false;
    
    // タスクの期限を取得
    var date = new Date( obj.limit_time * 1000 );

    // リマインド必要な日付でなければループを抜ける
    if( date > refDate ) return true;
 
    // タイトルを設定
    var title = obj.body;
    title = title.split(String.fromCharCode(10)).join(' '); // 改行をスペースに置換
    title = title.replace(/\[/g, "<"); // chatworkのタグを "[" → "<" に変換
    title = title.replace(/\]/g, ">"); // chatworkのタグを "]" → ">" に変換
    title = title.replace(/<("[^"]*"|'[^']*'|[^'">])*>/g, ""); // タグを削除
    title = title.substring(0,50); // タイトルは50文字で切る
  
    // 日付を文字列に変換
    var strDate = date.getMonth()+1 +"月" + date.getDate() + "日";

    // 
    var limit = '';
    if( nowDate > date ){
      limit = '期限切れ';
      title += " ( " + strDate + "まで )"
    } else {
      limit = ( date.getFullYear() === nowDate.getFullYear() && date.getMonth() === nowDate.getMonth() && date.getDate() === nowDate.getDate() )?'本日 '+ strDate + 'まで' : strDate + 'まで';
    }
    
    // 日付が異なる場合は水平線挿入
    var hr = ( lastLimitDate == '' || lastLimitDate == limit )? '' : '[hr]';
    if( lastLimitDate == '' || lastLimitDate != limit ) hr = hr + limit + ':\n' + ' ';
    
    strBody = strBody + hr + '[picon:' + obj.account.account_id + '] ' + title + '\n'; //チャットワークに送る文字列にタスクを追加
    lastLimitDate = limit;
  });

  // リマインド不要なら終了
  if( lastLimitDate == '' ) return false;

  // インフォタグを閉じる
  strBody = strBody + '[/info]';
  
  // ルームにメッセージ送信
  sendMessage(room_id, strBody);

  return true;
}

function getSheet(){
  var book = SpreadsheetApp.getActiveSpreadsheet();
  return book.getSheetByName(SHEETNAME);
}

// シートを読み込んでjson形式で返す
function convertSheet2Json(sheet) {
  
  // シートを読み込んで二次元配列を返す
  var values = readSheet(sheet);

  if( values == false ) return false;
  // create json
  var jsonArray = [];
  for(var i=0; i<values.length; i++) {
    var json = new Object();
    json['room_id'] = values[i][0];
    json['num_of_days'] = values[i][1];
    jsonArray.push(json);
  }
  return jsonArray;
}

// シートを読み込んで二次元配列を返す
function readSheet(sheet){

  var lastRow = sheet.getLastRow();
  if( lastRow <= 1 ) return false;
  var rowIndex = 2;
  var colStartIndex = 1;
  var colNum = 2;
  var range = sheet.getRange(rowIndex, colStartIndex, lastRow, colNum);
  var values = range.getValues();
  return values;
}

// メッセージ送信
function sendMessage(room_id, strBody){
  var params = {
    headers : {"X-ChatWorkToken" : ChatWorkToken},
      method : "post",
      payload : {
        body : strBody
      }
  };
  var url = "https://api.chatwork.com/v2/rooms/" + room_id + "/messages";
  UrlFetchApp.fetch(url, params);
}

コードの4行目にAPIトークンを設定する箇所があります。
取得したチャットワークのAPIトークンをコピペして、スクリプトを保存します。

プロジェクト名の入力欄が出るのでテキトーに入力してOK。

好きな時間帯にトリガーを設定します。

myFunction を選択。

時間主導型→日タイマーにするとリマインドする時間帯が選べます。朝でも夜でも好きな時間帯を選んでください。

保存します。

保存できたら、スプレッドシートに戻ります。

チャットルーム毎の個別設定

スプレッドシート上部のメニューから「管理用 > 最新のルーム一覧を読込む」をクリック。

初回のみ承認と許可が必要なので許可します。

チャットワークのグループチャットの一覧が表示されます。

チャットルーム毎にリマインドする日数(何日前からリマインドするか)を半角数字で入力します。
「3」を入力すれば、3日前からリマインドします。
リマインド不要の場合は、セルを空欄にすれば一切リマインドしません。

これでトリガーで設定した時間に毎日リマインドが実行されます。

試してみる

試しに実行してみたい場合は、「管理用 > いますぐリマインド実行」 をクリックすると、トリガーに関係なくすぐに実行できます。

実行すると、チャットワークにメッセージが送られます。
※リマインド対象のタスクがない場合は何も送られません。

まとめ

チャットワークでタスクを追加したのに、忘れられてしまう…という時にぜひ使ってみてください。
他にもチャットワークであったら良いな、という機能が、APIを利用すれば実現できちゃったりします。
こんなのあったら良いな、というご要望などあればご連絡ください。

コンノマTVで動画で解説

タイトルとURLをコピーしました