【チャットワーク】タスクをgoogleカレンダーに自動連携する(Google Apps Script)

Google Apps Script

2020/03/10更新 コードを修正(V8ランタイムに対応)しました!
2020/04/27更新 コードを修正しました!
2020/05/09更新 予定が重複してしまう不具合を修正しました。

できること

チャットワークのタスクをGoogleカレンダーに自動連携します。
具体的には、期限が設定され未完了の自分のタスクを、Googleカレンダーに予定として自動で登録します。

チャットワークのタスクとGoogleカレンダーを同期してほしいという要望があったので、APIとGoogle Apps Scriptを使って作成してみました。Googleカレンダー側の通知機能を使うことでアラート(リマインド)することもできます。

わかりやすく説明したつもりなので、ぜひお試しください。

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

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

新しいカレンダーを作る

専用のカレンダーを作成します。
Googleカレンダーを開き、マイカレンダー横の「▼」から「新しいカレンダーの作成」をクリック。

カレンダー名に適当に名前をつけて「カレンダーボタンを作成」をクリック。

カレンダーのIDを調べる

作成したカレンダーの「カレンダー設定」を開きます。

少し下にスクロールし、「カレンダーのアドレス」項目にカレンダーIDが表示されます。
このIDは後ほど使用します。

GoogleドライブでGoogleAppsScriptを作成する

Googleドライブを開き、「新規」ボタンから「Google Apps Script」をクリックします。

※「Google Apps Script」が出てこない場合は、「アプリを追加」から「Google Apps Script」を検索して、接続をクリックしてください。

無題のプロジェクトが開きます。
(最初に入っている「function myFunction() …」のコードは消しちゃってください。)

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

下のコードをすべてコピーし、作成したプロジェクトのコード入力欄に貼り付けます。

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

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

// googleカレンダーIDを設定 ※専用のカレンダーを作成することをオススメします
var CALENDAR_ID = 'xxxxxxxxxxxxxxxxxxxxxxxxxx@group.calendar.google.com';

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

// 識別キー
var SIGNATURE = "fromChatWork";

/*---- メインFunction ----*/

function myFunction(){
  
  // 最初にすべての予定をクリアする
  clearAllEvents();
  
  // ChatWork apiに投げるパラメータを設定
  var params = {
    headers : {"X-ChatWorkToken" : ChatWorkToken},
    method : "get"
  };
  
  //未完了のタスクを取得するURL
  var url = "https://api.chatwork.com/v2/my/tasks?status=open";

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

  //レスポンスがない場合は終了
  if(strRespons == "") return false;

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

  Logger.log( "未完了タスク数: " + json.length );
  
  // googleカレンダーオブジェクト作成
  var calendar = CalendarApp.getCalendarById(CALENDAR_ID);
  
  // タスク毎に予定を作成
  json.forEach(function(obj) {

    // タイトルを設定
    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文字で切る
    
    // 期限のないタスクの場合はログを残してスキップ
    if( obj.limit_time !== 0 ){
      
      // UNIXTIMEを変換してdateにセット
      var date = new Date( obj.limit_time * 1000 ); 
      
      // 説明欄を設定
      var description = obj.body;
      description += String.fromCharCode(10) + "------------------------------";
      description += String.fromCharCode(10) + obj.room.name; // ルーム名
      description += String.fromCharCode(10) + "https://www.chatwork.com/#!rid" + obj.room.room_id; // ルームURL
      description += String.fromCharCode(10) + "依頼者: " + obj.assigned_by_account.name; // 依頼者
      
      var options = {description: description}; 
      
      // 終日のイベントを作成
      var event = calendar.createAllDayEvent(title, date, options);
      
      // イベントにタグ付け
      event.setTag(SIGNATURE, "true");
    }
  });
}

/*---- 前後1年間の予定をクリアするFunction ----*/

function clearAllEvents() {
  
    // googleカレンダーオブジェクト作成
    var calendar = CalendarApp.getCalendarById(CALENDAR_ID);
  
    // 今日の日付取得
    var date = new Date();
  
    // 今日の年、月、日を格納
    var year = date.getFullYear();
    var month = date.getMonth()+1;
    var day = date.getDate();
  
    // 前後1年間の予定を取得
    var events = calendar.getEvents(new Date(year - 1, month ,day), new Date(year + 1, month, day));

    // イベントの数だけ繰り返し処理
    for(var n=0; n<events.length; n++){

      // カレンダーの説明に指定の単語があれば予定を削除
      if ( events[n].getTag(SIGNATURE) == "true" ) {
        events[n].deleteEvent();
      }

    }
}

コード上部のチャットワークのトークンとカレンダーIDを書き換える

コードの上の方に、チャットワークのAPIトークンと、GoogleカレンダーのカレンダーIDを入力する箇所があるので、ご自分のトークンと、先ほど作成したカレンダーIDに書き換えてください。

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

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

// googleカレンダーIDを設定 ※専用のカレンダーを作成することをオススメします
var CALENDAR_ID = 'xxxxxxxxxxxxxxxxxxxxxxxxxx@group.calendar.google.com';

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

保存ボタンを押して、適当なプロジェクト名をつけて保存します。

実行してみる

プルダウンメニューで「myFunction」を選択した状態で、実行ボタン(三角のボタン)をクリック。

※初回のみ実行の承認と許可を求められるので「許可」ボタンを押してください。

処理が完了すると、カレンダーに予定が登録されます。

トリガーを設定する

トリガーを設定することで、自動で最新のタスクをカレンダーに反映できます。

まず、(時計みたいな)トリガーボタンをクリックして、トリガーを追加します。

「myFunction」、「時間主導型」、「時タイマー」、「1時間ごと」を選択して保存。

これで1時間に1度、自動的にカレンダーを更新するよう設定できました。

まとめ

以上が、チャットワークの未完了タスクをGoogleカレンダーに自動連携する方法でした。
カレンダーの設定を変更することで、◯日前の◯時に通知するという設定もできます。

更新時には、カレンダー内のすべての予定をチェックして削除し、新しく予定(タスク)を登録しなおしてます。
なので、カレンダーに予定がたくさん入っていたり、未完了タスクが多かったりすると処理が間に合わなくなることがあります。
もし不具合などあれば教えてください。

コメント

  1. まさる より:

    有難うございます、参考にさせて頂きました。

    折角の有用な記事ですが、コピペだとうまく動かないようです。

    ・期限の無いタスクの処理ですが、breakではなく continue ですね。
    ・chatworkの] タグ変換の変換処理ですが、前の行から改行されていなくコメントアウトされてます。

    では、有難うございました。

    • ながすん より:

      まさるさん

      ご指摘ありがとうございます!
      凡ミス失礼しました。。修正して更新いたしました^^

  2. HERO より:

    「短時間に作成したカレンダーまたはカレンダーの予定の数が多すぎます。しばらくしてからもう一度お試しください。」
    このようなエラー表示が出るんですが、放置しておいても時間が経過すれば、連携が始まってGoogleカレンダーにタスクが立つんでしょうか?

    • ながすん より:

      HEROさん

      コメントありがとうございます!
      純粋にタスクの数が多いか、コードにバグがあるか、のどちらかだと思いますが、
      どれくらい未完了タスクが登録されてますでしょうか。

  3. Keays より:

    大変参考になり、早速自動化できて助かりました。

    1点追加で教えて頂きたいのですが、

    「タスク追加日(今日)からタスク期限日」までの全期間をカレンダーに
    反映させたい 場合、どこをどういじればいいでしょうか?

    あまりGASにも詳しくなく、ご教示お願いできますでしょうか?

  4. さとう より:

    チャットワークのタスクがグーグルカレンダー連携すればいいのにと思っていた時に見つけた記事でした。ありがとうございます。

    さて、1時間おきのトリガーをしているのですが、タスクが重なってグーグルカレンダーに連携されるのですが、なにかやり方がまずかったのでしょうか?
    一晩で十何個同じタスクがカレンダーに連携されます。

    >更新時には、カレンダー内のすべての予定をチェックして削除し、新しく予定(タスク)を登録しなおしてます

    が正常に動かないのでしょうか?

    よろしくお願いいたします。

    • ながすん より:

      コメントありがとうございます!
      こちら確認してご返信しますね。
      少々お待ちください。

    • ながすん より:

      こちらで再現できなかったのですが、前回コードを修正(V8ランタイムに対応)した時に修正漏れの箇所が1点見つかりまして、再度コードを修正しました。
      ご確認いただけますと幸いです。

    • ながすん より:

      ご迷惑をおかけしすみません。
      原因がわかりましたのでコードを修正しました!
      修正箇所は90行あたりにあるこの箇所です。
      // 今日の年、月、日を格納
      var year = date.getFullYear();
      var month = date.getMonth()+1;
      var day = date.getDate();
      ご不明な点などございましたらいつでもご連絡ください。

  5. すずき より:

    ありがとうございます。
    参考にさせて頂きました。

    ただ、上記でもコメントがあるようにタスクが何度もGoogleカレンダーに登録されてしまう現象になっています。

    なんとか自分で解決しようと試みたのですが、
    初心者には難しく、、、

    現状、チャットワークからGoogleカレンダーに登録する予定は5つだけです。

    どの様にすれば解決できるかお教え頂けると大変ありがたいです。

    • ながすん より:

      ご迷惑をおかけしすみません。
      原因がわかりましたのでコードを修正しました!
      修正箇所は90行あたりにあるこの箇所です。
      // 今日の年、月、日を格納
      var year = date.getFullYear();
      var month = date.getMonth()+1;
      var day = date.getDate();
      ご不明な点などございましたらいつでもご連絡ください。

  6. たてかべ より:

    ながすん様

    有益な記事をいつもありがとうございます!

    2020/6/4現在ですが、
    上の方と同様に、
    特定のタスクがGoogleカレンダーに二重登録されてしまうという現象が起こっております。

    Googleカレンダーに二重登録された予定を削除してしばらくすると、またその予定が二重登録されています。

    また、規則性は分かりませんでしたが、二重登録されるタスクと二重登録されないタスクがあるようです。

    どの様にすれば解決できるかお教え頂けると大変ありがたいです。

    よろしくお願いいたします。

  7. たてかべ より:

    ながすん様

    タスクがダブってGoogle Calendarに登録されてしまうという件について、
    「同じ名前のタスクがあった場合には、登録をスキップする」などというコードを追加していただければ、
    解決できそうだなと考えました。

    ですが、当方、ちんぷんかんぷんで、その実装ができません。

    もし、ながすん様がお手すきの際に教えていただけたら大変助かりますm(_ _)m

    • ながすん より:

      たてかべさま

      コメントありがとうございます。
      こちらでもテストしてみましたがまだ再現できていません。

      >「同じ名前のタスクがあった場合には、登録をスキップする」などというコードを追加
      このスクリプトは実行する度にすべての予定を削除してから再度予定を登録するようにしています。
      予定の削除ができていれば重複することはないですし、逆に削除が正常にできていなければ2重ではなくもっとたくさん登録されることになります。
      同時に2つのスクリプトが動いていたりすると2重登録となる可能性がありますが…
      何か手がかりになりそうなことがあればご共有いただけると助かります。
      よろしくお願いします。

  8. g6 より:

    いつも大変助けられております。
    タスクが重複して登録されてしまう件ですが、私の方でも起きており、google からは下記のような文面でエラーのメールが来ております。


    スクリプト Tasks from Chatwork for Calendar を正常に完了できませんでした。失敗のまとめを下記に示します。このスクリプトのトリガーを設定したり、今後の失敗の通知の受信設定を変更したりするには、ここをクリックしてください。

    概要:

    エラー メッセージ カウント
    短時間に作成したカレンダーまたはカレンダーの予定の数が多すぎます。しばらくしてからもう一度お試しください。(行 71、ファイル「コード」) 2
    短時間に作成したカレンダーまたはカレンダーの予定の数が多すぎます。しばらくしてからもう一度お試しください。(行 74、ファイル「コード」) 6

    起動 関数 エラー メッセージ トリガー End
    20/08/25 15:20 myFunction 短時間に作成したカレンダーまたはカレンダーの予定の数が多すぎます。しばらくしてからもう一度お試しください。(行 74、ファイル「コード」) time-based 20/08/25 15:21

    このエラーを受信して見に行くと、いくつかのタスクが2〜3個重複してカレンダーに登録されている状態になっている感じです。すべてのタスクではないのが面倒な感じですが…

    • ながすん より:

      g6さま

      コメントありがとうございます。貴重な情報ありがとうございました。
      確かに短時間に予定を大量に作成する仕様なので何らかの根本的な対処ですね。
      時間を見てロジックの修正を検討します。
      引き続きよろしくお願いします。

  9. RR より:

    参考にさせて頂き、設置完了しました。
    要望として、前にコメントされていた方と同じように

    ・「タスク追加日(今日)からタスク期限日」までの全期間をカレンダーに反映させたい
    ・チャットワークのタスクの「時間」を入れると、カレンダーに「期限の時間」も入れる

    上記2つ反映させたいのですが、初心者には難しく、
    どこをどういじればよいでしょうか?

    • ながすん より:

      RR さま

      コメントありがとうございます。回答遅くなり申し訳ありません。

      > ・「タスク追加日(今日)からタスク期限日」までの全期間をカレンダーに反映させたい
      Chatwork

      GASで期間の予定を作成する場合は createAllDayEvent(title, startDate, endDate, options) を使用します。
      しかし、Chatwork側がタスク追加日の情報を持っていないため、このスクリプトをカスタマイズして作成するのは難しいかもしれません。
      やるとすれば、スプレッドシートからコンテナバインド型でGASを作成し、シートでタスク追加日の情報を管理する形になるかと思います。

      > ・チャットワークのタスクの「時間」を入れると、カレンダーに「期限の時間」も入れる

      未検証ですが、

      description += String.fromCharCode(10) + “依頼者: ” + obj.assigned_by_account.name; // 依頼者

      の下に

      description += String.fromCharCode(10) + “日時: ” + Utilities.formatDate(date, “Asia/Tokyo”, “yyyy/MM/dd HH:mm:ss”);

      を追加すると予定の説明欄に日時が追加されると思います。

      もし終日の予定ではなく時間単位の予定にしたい場合は、

      // 終日のイベントを作成
      var event = calendar.createAllDayEvent(title, date, options);

      の部分を

      // イベントを作成
      var startDate = new Date(date.getTime());
      var endDate = new Date(date.getTime());
      endDate.setHours(date.getHours()+1);
      var event = calendar.createEvent(title, startDate, endDate, options);

      にしていただくと対応できるかと思います。
      よろしくお願いします。

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