54
57

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LINE BOTからGoogleカレンダーに予定の追加&一週間の予定の確認を行う

Last updated at Posted at 2021-03-09

はじめに

この記事はプログラミングほぼ未経験だった僕が、プログラミングを学び、アウトプットとして作ったLINEBOTに関するものです。

初めての投稿なので、改善点やアドバイス、感想などあればコメントお願いします。

目次

1.作ろうと思った経緯
2.機能説明
3.予定追加・一週間の予定確認の実際のトーク画面
4.ソースコード
5.今後の改善点
6.参考にした記事

1.作ろうと思った経緯

就職活動がかなり忙しくなってきたときに、
使用頻度が高いLINEで予定追加と確認ができれば楽だな、と思ったからです。
また、inteeリアルカレッジのポートフォリオとして作成しました!

2.機能説明

リッチメニューの「予定追加」を押すと予定を追加。
「一週間の予定確認」を押すと、Googleカレンダーに記入されている一週間の予定を日付・時間帯・予定名でリスト化して返す。
「最初からやり直し」を押すと、予定追加を中断し、最初からやり直せる。

3.予定追加・一週間の予定確認の実際のトーク画面

##予定追加
###予定日→開始時刻→終了時刻→予定名→確認 の順に登録する。

ポートフォリオ1.jpg
ポートフォリオ2.jpg

一週間の予定確認

Inkedポートフォリオ用LINE画像_LI.jpg

4.ソースコード

チャネルアクセストークン、スプレッドシートのID、Googleアカウントはご自身の物を使用されてください!

var CHANNEL_ACCESS_TOKEN = "チャネルアクセストークン";
var ERROR_SHEET_ID = "スプレッドシートのID";

//日付、時刻のフォーマット設定
var dateExp = /(\d{2})\/(\d{2})\s(\d{2}):(\d{2})/;
var dayExp = /(\d+)[\/](\d+)/;
var hourMinExp = /(\d+)[:時](\d+)*/;


function doPost(e) {
  try {
    handleMessage(e);
  } catch(error) {
    logging("ToCalendarFromLineBot");
    logging(JSON.stringify(e));
    logging(JSON.stringify(error));
    var replyToken = JSON.parse(e.postData.contents).events[0].replyToken;
    reply(replyToken, error.message);
  }
}


function logging(str) {
  var sheet = SpreadsheetApp.openById("スプレッドシートのID").getActiveSheet();
  var ts = new Date().toLocaleString("japanese", {timeZone: "Asia/Osaka"});
  sheet.appendRow([ts, str]);
}

function handleMessage(e) {
  var replyToken = JSON.parse(e.postData.contents).events[0].replyToken;
  var lineType = JSON.parse(e.postData.contents).events[0].type
  if (typeof replyToken === "undefined" || lineType === "follow") {
    return;
  }
  var userMessage = JSON.parse(e.postData.contents).events[0].message.text;
  var cache = CacheService.getScriptCache();
  var type = cache.get("type");

  if (type === null) {
    if (userMessage === "予定追加") {
      cache.put("type", 1);
      reply(replyToken, "予定日を教えてください!\n「06/17, 6月17日」などの形式なら大丈夫です!");
    } else if (userMessage === "一週間の予定確認") {
      reply(replyToken, getEventss());
    } else {
      reply(replyToken, "リッチメニューの「予定追加」で予定追加を、「一週間の予定確認」で一週間の予定参照ができるので気軽に話しかけてくださいね!");
    }
  } else {
    if (userMessage === "キャンセル") {
      cache.remove("type");
      reply(replyToken, "キャンセルしました!");
      return;
    }

    switch(type) {
      case "1":
        // 予定日
        var [matched, month, day] = userMessage.match(dayExp); //dayexpの型に合う文字列を取り出す。
        cache.put("type", 2);
        cache.put("month", month);
        cache.put("day", day);
        reply(replyToken, month + "/" + day + "ですね! 次に開始時刻を教えてください。「13:00, 13時, 13:20, 13時20分」などの形式なら大丈夫です!");
        break;

      case "2":
        // 開始時刻
        var [matched, startHour, startMin] = userMessage.match(hourMinExp);
        cache.put("type", 3);
        cache.put("start_hour", startHour);
        if (startMin == null) startMin = "00";
        cache.put("start_min", startMin);
        reply(replyToken, startHour + ":" + startMin + "ですね! 次に終了時刻を教えてください。");
        break;
        
      case "3":
        // 終了時刻
        var [matched, endHour, endMin] = userMessage.match(hourMinExp);
        cache.put("type", 4);
        cache.put("end_hour", endHour);
        if (endMin == null) endMin = "00";
        cache.put("end_min", endMin);
        reply(replyToken, endHour + ":" + endMin + "ですね! 最後に予定名を教えてください!");
        break;

      case "4":
        // 予定名
        cache.put("type", 5);
        cache.put("title", userMessage);
        var [title, startDate, endDate] = createEventData(cache);
        reply(replyToken, toEventFormat(title, startDate, endDate) + "\nで間違いないでしょうか? よろしければ「はい」をやり直す場合は「いいえ」をお願いいたします!");
        break;

      case "5":
        // 確認の回答がはい or いいえ
        cache.remove("type");
        if (userMessage === "はい") {
          var [title, startDate, endDate] = createEventData(cache);
          CalendarApp.getDefaultCalendar().createEvent(title, startDate, endDate);
          reply(replyToken, "追加しました!\nお疲れ様でした!");
        } else {
          reply(replyToken, "お手数ですがもう一度お願いいたします!");
        }
        break;
      default:
        reply(replyToken, "申し訳ありません。\n形式に誤りがないか確認してみて、なければ「キャンセル」で予定入力をキャンセルすることができるので、そちらを試していただけますか?");
        break;
    }
  }
}

function createEventData(cache) {
  var year = new Date().getFullYear();
  var title = cache.get("title");
  var startDate = new Date(year, cache.get("month") - 1, cache.get("day"), cache.get("start_hour"), cache.get("start_min"));
  var endDate = new Date(year, cache.get("month") - 1, cache.get("day"), cache.get("end_hour"), cache.get("end_min"));
  return [title, startDate, endDate];
}

function toEventFormat(title, startDate, endDate) {
  var start = Utilities.formatDate(startDate, "JST", "MM/dd HH:mm");
  var end = Utilities.formatDate(endDate, "JST", "MM/dd HH:mm");
  var str = title + ": " + start + " ~ " + end;
  return str;
}

function reply(replyToken, message) {
  var url = "https://api.line.me/v2/bot/message/reply";
  UrlFetchApp.fetch(url, {
    "headers": {
      "Content-Type": "application/json; charset=UTF-8",
      "Authorization": "Bearer " + CHANNEL_ACCESS_TOKEN,
    },
    "method": "post",
    "payload": JSON.stringify({
      "replyToken": replyToken,
      "messages": [{
        "type": "text",
        "text": message,
      }],
    }),
  });
  return ContentService.createTextOutput(JSON.stringify({"content": "post ok"})).setMimeType(ContentService.MimeType.JSON);
}

function get_Calendar() {
  var arrCals=[];
  arrCals.push(CalendarApp.getCalendarById('使いたいGoogleカレンダーのアカウントのメールアドレス'));
  return arrCals;
}

//1週間の予定を取得するメインの関数
function get_Week_Schedule(){
  var arrCals = get_Calendar();
  var dateNow = new Date();
  var date = new Date();
  var strBody ='';
  var tmpBody ='';
  var strIntro = "おつかれさまです。\n1週間の予定です。\n" ;
  for (var j = 1; j < 7 ; j++ ){
    date.setDate(dateNow.getDate()+j);
    for (var i = 0 ; i < arrCals.length ; i++){
      tmpBody = tmpBody + getEvents(arrCals[i],date);
    }
    if (tmpBody){
      strBody = strBody + date.getDate() + '\n' + tmpBody;
    }
    tmpBody = '';
  }
  return (strIntro + strBody);
}

//予定を取得する関数
function getEvents(Cals,getDate){
  var arrEvents = Cals.getEventsForDay(getDate);//カレンダーの予定取得
  var strEvents ='';
  for (var i=0; i<arrEvents.length; i++){
    var strTitle = arrEvents[i].getTitle();
    var strStart = _HHmm(arrEvents[i].getStartTime());
    var strEnd = _HHmm(arrEvents[i].getEndTime());
    if (strStart == strEnd){
      strEvents = strEvents + '終日イベント:' + strTitle +  '\n';
    }else{
      strEvents = strEvents + strStart + '' + strEnd+ ''  + strTitle  + '\n';
    }
  }
  return strEvents;
}

//予定確認時の関数
function getEventss() {
  var events = CalendarApp.getDefaultCalendar().getEventsForDay(new Date());
  var body;

  if (events.length === 0) {
    body = "今週の予定はありません!";
    return body;
  } else {
    body = get_Week_Schedule();
    return body;
  }
}

function toHHmm(date){
  return Utilities.formatDate(date, "JST", "HH:mm");
}

function _HHmm(str){
  return Utilities.formatDate(str,'JST','HH:mm');
}

5.今後の改善点

  • ソースコードに書いたアカウントでしかGoogleカレンダーと連携できない。
    →LINEトーク画面でアカウント切り替え・追加できるようにすればよいかも?
    →また、個人で使うほかに、組織内共通のアカウントで使うとよいかもしれない。

  • 一週間の予定確認をする際に、月を表示できるようにしたら見やすい。

  • 予定追加の際、開始・終了時刻が24:00を超えた場合の処理
    →入力し直せるようにする。

  • 予定を削除する機能を付ける。

  • 前日の夜や当日の朝に予定を連絡するリマインド機能を付ける。

  • 今年の予定しか登録できない。

6.参考にした記事

①GAS上で一週間の予定確認する関数について書かれた記事
https://cyuraharuto.com/gas-googlecalender-week-get/

②Googleカレンダーと連携して予定追加・一日の予定確認をするLINEBOTの記事
https://qiita.com/gawawa124/items/384496ac31fac531f1f9

③リッチメニュー作成について書かれた記事
https://qiita.com/bow_arrow/items/32ac5d2b4c67bd0c1dc2

④タイムゾーン変更方法について
https://stabucky.com/wp/archives/13825

④については、自分が躓いたので、載せてます。

54
57
1

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
54
57

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?