ノベルティメディア

MEDIA

GASでお手軽DX!チャットツールとカレンダーを連携して業務改善を!

GASでお手軽DX!チャットツールとカレンダーを連携して業務改善を!
橋本大地
GASでお手軽DX!チャットツールとカレンダーを連携して業務改善を!

みなさんこんにちは、ノベルティのエンジニア橋本です。

今回はローコードでお手軽DXということで、ツールをまたいだ操作を自動化していこうと思います!

実際にスポットを当てていきたい点がこちら、Googleカレンダーへの予定連携です。

予定といってもいろいろありますよね?

普段から会議だったり、有給だったり、作業だったり、チャット内でメンバーとやりとりをした結果をカレンダーに書き込んでいる場合も多いのではないでしょうか?

それを今回はチャットに書き込むだけでカレンダーにも連携しよう、ということで進めていきます!

できるだけコピペで実行できるようにしたいので、開発環境などは可能な限り簡単にセッティングします。

準備すること

今回利用するツールはこちらです!

  • Googleカレンダー
  • Google Apps Script(GAS)
  • メッセージ送信アクションを検知できるチャットツールなど

今回の開発には、ローコード開発ができてGoogleカレンダーと親和性の強いGASを選定しました。

GASはJavaScriptベースでwebアプリケーション開発ができるツールで、設定のシンプルさはとても魅力です。

エンジニアのみなさんだけでなく、生成AIも発展している現在はGASを利用した非エンジニア向けのDX記事も熱いジャンルだと思いますので、ぜひこの機会に学習してみてはいかがでしょうか!

便利なGASの詳細については、下記ブログもぜひご参照ください!

https://noveltyinc.jp/media/gas_mailsend2024

また、このGASと通信ができるチャットツールとして、ノベルティでも利用しているChatworkを選びました。

Chatworkを前提とする場合、ある程度運用面で必要な情報をカスタマイズいただければコピペでもOKです。

開発フローとしては、簡単3ステップです。

  1. GASで受信処理とカレンダー書き込み処理を実装したアプリケーションを開発する
  2. チャットツールの設定でGASアプリと連携する
  3. 実際に動いているかチェックする

では、まずはステップ1として、具体的な処理を書いていきましょう!

GASでアプリケーション開発!

まずは環境の準備からです。

開発環境の準備ってすごく大変なイメージがありますよね。

しかし、GASを利用することでGoogle製品との連携が容易に、開発環境の準備も非常に簡単にできます!

なお、GASを利用する場合、Googleのアカウントが必要です。

Googleカレンダーへの連携を目的とするのでGoogleアカウントはあると思いますが、本仕様ではGASプロジェクトを作成したアカウントが自身のアカウントのカレンダーに書き込みます。

社内みんなが閲覧できるアカウントとして運用できるとよいですね。

前置きはこのあたりにして...下記のURLからGASプロジェクトを作成します。

https://script.google.com/

次に新しいプロジェクトを立ち上げると、GASのコードを書ける画面に遷移します。

これで準備は完了なので、工程を進めます。難しい設定ファイルなどを触らずに準備できるので、簡単でよいですね!

受信処理とカレンダー書き込み処理を実装する

まず、コードの全容がこちらです。

function addEventToCalendar(title, startTime, endTime, allDay = false) {
    var calendar = CalendarApp.getDefaultCalendar();
    if (allDay) {
      calendar.createAllDayEvent(title, startTime);
    }else{
      var title = title;
      var startTime = new Date(startTime);
      var endTime = new Date(endTime);
      calendar.createEvent(title, startTime, endTime);
    }
}

function sendChatworkMessage(message) {
  var roomId = "ルームIDを入力"
  var token = PropertiesService.getScriptProperties().getProperty('CHATWORK_API_TOKEN');
  var endpoint = "https://api.chatwork.com/v2/rooms/" + roomId + "/messages";
  var payload = {
    "body": message
  };
  var options = {
    "method" : "post",
    "headers" : {
      "X-ChatWorkToken": token
    },
    "payload" : payload,
    "muteHttpExceptions": true // HTTP例外をミュートに設定
  };
  var response = UrlFetchApp.fetch(endpoint, options);;
}

function doPost(e) {
  try {
    if (!e.postData) {
      throw new Error("postDataが存在しません。");
    }

  } catch (error) {
    sendChatworkMessage("エラーが発生しました")
    return ContentService.createTextOutput(JSON.stringify({result: "error", message: error.toString()}));

  }

  try {
    var postData = JSON.parse(e.postData.contents);
    var message = postData.webhook_event.body; // この部分は実際のWebhookの形式に合わせて調整が必要
    if (message.indexOf("#カレンダー") !== -1) { //特定の文言で処理を発火させる
      // メッセージからイベントの詳細を抽出
      var titleMatch = message.match(/タイトル:(.+?)\s/);
      var startMatch = message.match(/開始:(\d{4}\/\d{2}\/\d{2} \d{2}:\d{2})\s/);
      var endMatch = message.match(/終了:(\d{4}\/\d{2}\/\d{2} \d{2}:\d{2})/);
      var allDayEventMatch = message.match(/終日:(\d{4}\/\d{2}\/\d{2})/);
      var title = titleMatch[1];
      if (allDayEventMatch) {
        var date = new Date(allDayEventMatch[1]);
        addEventToCalendar(title, date, null, true); // 終日イベントとして追加
      }else if (titleMatch && startMatch && endMatch) {
        var startTime = new Date(startMatch[1]);
        var endTime = new Date(endMatch[1]);
        addEventToCalendar(title, startTime, endTime,false);
      } else {
        sendChatworkMessage("メッセージ形式が不正です: " + message)
        return;
      }
      // 処理完了を示すためにHTTPレスポンスを返す
      sendChatworkMessage(title+"のイベント追加が完了しました。")
      return HtmlService.createHtmlOutput("イベント追加完了");
    }

  } catch (error) {
      sendChatworkMessage(title + "エラーが発生しました: " + error.toString())
      return ContentService.createTextOutput("エラーが発生しました: " + error.toString());
  }

}

なかなかのボリューム感に感じるかもですが、一般的な開発と比較すると、コード量はかなり抑えられていると思います。

処理フローの詳細は、下記のとおりです。

  1. GASで作ったアプリがチャットツールからの送信を検知する
  2. カレンダーに書き込むための情報を取得する
  3. カレンダーへ書き込む処理をする
  4. 結果をチャットツールに応答する

といったフローです。

さっそく詳細を見ていきましょう。

1.GASで作ったアプリが送信を検知する

メッセージ送信→GASへの連携については、チャットツールのwebhookという機能に依存するため処理は書きません。

こちらは後述します。

実装で着目すべきは、チャットツールから送信されたデータをGASで受けるために、doPost(e)というGASの機能を利用する点です。

これはお決まりのルールで、非常に簡単に情報を受け取ることのできる仕組みとなっています。

上記の受信を前提とし、メッセージデータを受け取る本コードのポイントとしては、メッセージの識別が非常に重要です。

特にwebhookを利用する場合は送信されたメッセージをすべて受け取って処理することが必至なので、すべての処理を通してしまうと、カレンダー連携以外のメッセージが絶えずエラーを起こしてしまいます。

それを避けるために、本コードでは特定の文言が入っている場合のみ、その後の処理を行うようにしています。

該当のコードがこちらです。

var postData = JSON.parse(e.postData.contents);
var message = postData.webhook_event.body; // この部分は実際のWebhookの形式に合わせて調整が必要
 if (message.indexOf("#カレンダー") !== -1) {
    //処理
 }

これは「#カレンダー」という文字列が含まれていたら、という分岐処理を示します。

お好きな文言に変えることでカスタマイズが可能です。

ただ、本コードはChatwork側からの送信証明ができません。

社内システムなどクローズした空間でのやり取りを基準に考えれば問題ないと思いますが、もし広く取り扱いたい場合は、GASを利用せずお好みのプログラミング言語で実装することを推奨します。

2.カレンダーに書き込むための情報を取得する

次に、カレンダーに書き込むために必要な情報を取得します。

チャットツールからの入力を想定しているため、基本的にユーザーは自由に文字を入力することができます。

自由度を高めた取得方法を選択すると、メッセージの途中でたまたま指定の文字を拾ってしまい、カレンダーに連携されてしまった...といったトラブルも想定できます。

ある程度こちらで書式を決め、そのルールに沿ったメッセージのみ情報を取得します。

今回の例は下記のとおりです。

時間単位でカレンダーと連携したい場合

#カレンダー

タイトル:ノベルティDXテスト

開始:2024/03/20 10:00

終了:2024/03/20 11:00

日単位でカレンダーと連携したい場合

#カレンダー

タイトル:ノベルティDXテスト

終日:2024/04/03

実際のコードは下記のとおりです。

「タイトル:」という形式や「開始:YYYY/MM/DD」の形式にマッチするものだけを取得するようにしています。

var titleMatch = message.match(/タイトル:(.+?)\s/);
var startMatch = message.match(/開始:(\d{4}\/\d{2}\/\d{2} \d{2}:\d{2})\s/);
var endMatch = message.match(/終了:(\d{4}\/\d{2}\/\d{2} \d{2}:\d{2})/);
var allDayEventMatch = message.match(/終日:(\d{4}\/\d{2}\/\d{2})/);
var title = titleMatch[1];

実運用の際は、コピペ元を提供すると迷わず運用できると思います。

3.カレンダーへ書き込む処理をする

カレンダーへ書き込む処理については、こちらの関数を使って実行しています。

終日と日時で分けて運用できるようにしています。

function addEventToCalendar(title, startTime, endTime, allDay = false) {
    var calendar = CalendarApp.getDefaultCalendar();
    if (allDay) {
      calendar.createAllDayEvent(title, startTime);
    }else{
      var title = title;
      var startTime = new Date(startTime);
      var endTime = new Date(endTime);
      calendar.createEvent(title, startTime, endTime);
    }
}

4.結果をチャットツールに応答する

最後に、本処理の結果をチャットツールに連携します。

自分の登録した処理がうまくいったか分からないと不安ですよね。

そこで本例では、下記のコードを使ってチャットワークに送信処理を行っています。

結果メッセージを受信するルームIDは、適切な値に変更ください。権限によりますが、ルームタイトルの右側にある歯車マークの「グループチャットの設定」から確認可能です。

※この送信も送信処理としてカウントされてしまうので、なるべく送信ルームと受信ルームは分けた方がよいと思います

function sendChatworkMessage(message) {
  var roomId = "ルームIDを入力"
  var token = PropertiesService.getScriptProperties().getProperty('CHATWORK_API_TOKEN');
  var endpoint = "https://api.chatwork.com/v2/rooms/" + roomId + "/messages";
  var payload = {
    "body": message
  };
  var options = {
    "method" : "post",
    "headers" : {
      "X-ChatWorkToken": token
    },
    "payload" : payload,
    "muteHttpExceptions": true // HTTP例外をミュートに設定
  };
  var response = UrlFetchApp.fetch(endpoint, options);;
}

これで処理の説明については終了です!

こちらの処理が不要な場合は、最初に提示した全容コードからsendChatworkMessageと記載された行と上記の関数そのものを削除すればOKです。

それではこの処理をアプリケーション化し、URLを取得しましょう。

デプロイについて

書いたコードをアプリケーション化するためには、デプロイという作業が必要です。

さっそく行っていきたいところですが...Chatworkへ送信処理をする場合は、セキュリティに配慮する必要があります。

Chatworkを例にすると、今回のような外部送信処理には秘密鍵情報が必要になります。これをAPIキーといい、非常に大切な機密情報です。

このキーを頼りに送信アクションの信頼性を担保し、メッセージの送信を行う仕組みです。

キーの取得方法は、Chatworkアプリケーションの右上にあるご自身の名前欄をクリックした先にある「サービス連携」から利用可能で、APIトークンから取得ください。

※もし設定できない場合は、Chatwork管理者の方に申請しましょう。

これは非常に機密情報なので、そのままコードに書いてデプロイはしません。

環境変数というセキュリティに守られた空間から取得します。

具体的なコードはこちらです。

var token = PropertiesService.getScriptProperties().getProperty('CHATWORK_API_TOKEN');

サイドメニューの「プロジェクトの設定」下部にある「スクリプト プロパティ」から設定可能です。

プロパティの項目にCHATWORK_API_TOKENを、値のところにキー情報を入力します。

必要に応じてルームIDも登録しましょう。

これでデプロイまでの準備が完了です!

肝心のデプロイ自体は、ヘッダーに常に表示されている「デプロイ」のボタンを利用しましょう。

こちらから「新しいデプロイ」を選択し、種類の選択から「ウェブアプリ」、次のユーザーとして実行は「自分」、そしてアクセスできるユーザーを「全員」とすることで準備は完了です。

最後にURLを取得できるので、これをチャットツール側で利用します。

慣れてしまえば数時間程度で簡単に機能が作れてしまいます。

ここまででGASの設定は完了。

続いて、チャットツール側の設定を行います。

チャットツールの設定でGASアプリと連携する

これはチャットツールごとに異なりますが、利用する仕組みは同一なのでそちらを踏まえて解説します。

まず、利用する仕組みはwebhookと言います。

難しそうな名前ですが、大まかな仕組みは何かしらのアクションに応じて特定のURLにデータ送信する仕組みを指します。

今回の例でいうと「メッセージが送信されたら」というアクションになります。

チャットワークの場合ですと、アプリケーションの右上にあるご自身の名前欄をクリックした先にある「サービス連携」から利用可能です。

次の画面でwebhookを設定できるので、Webhook URLとルームイベントでIDを指定します。

※もし設定できない場合は、Chatwork管理者の方に申請しましょう。

他のチャットツールでも、URLにデータを通信できる類似のサービスがあれば利用可能です。

上記でも触れましたが、下記のコードはチャットワークならではのコードになります。ツールによって送信される中身が違います。

webhookでどのようなデータが送信されるか、については公式のドキュメントを確認し適宜対応しましょう。

var postData = JSON.parse(e.postData.contents); 
var message = postData.webhook_event.body; // この部分は実際のWebhookの形式に合わせて調整が必要

実際に動いているかチェックする

最後に、実際に動くかをチェックします。

チャットツールからメッセージを送信し、きちんとカレンダーへ連携、そしてメッセージが指定のルームに返却されていたら成功です!

回のご紹介では割愛していますが、テスト送信するための関数やログを記録するための関数などを用意しておくと、機能拡張なども簡単に行うことができます。

また、明らかな不具合などが多発した場合は、慌てずチャットツールのwebhookを停止し、原因の特定をしていきましょう。

まとめ

以上でお手軽DXの完了です!

最近はマイクロサービス化が進み、工夫次第で比較的簡単に業務の自動化が可能になりました。

自動化は効率を上げるだけでなく、人それぞれで起こってしまうミスをなくして業務の平準化を可能にします。

ノベルティでは業務DXも積極的にご提案していますので、こんな業務は自動化できないのかな~とお悩みの方も、ぜひ一度ご相談ください!

お問い合わせはこちらから

それではまた!

この記事をシェアする
橋本大地

橋本大地

Engineer

バックエンドを経てフロントエンドの世界へ 持ち前のポジティブさと細やかさでノベルティを救う☆ 元気の源は愛妻弁当! 乾電池を通勤カバンに常備しているのできっと電池で動いています。

Webプロモーション・業務改善は
ノベルティひとつで完結

はじめての依頼にも
全力でサポートさせていただきます

メールでのお問い合わせ

おすすめ記事/ PICKUP

    記事カテゴリー/ CATEGORY

      Webプロモーションや業務改善・DX化

      企業の課題はノベルティひとつで完結

      ホームページ制作などのWeb制作をはじめ、
      システム開発やマーケティング支援などワンストップで対応
      まずはお気軽にお問い合わせください

      お問い合わせ

      お電話またはメールでお気軽にお問い合わせください。