[GAS]GoogleSpreadSheetとLineBotでTODO管理

## 経緯
社会人サークルとかで、エンジニア以外の人がいるような環境だと「TODO管理はしたいけど、Slackとかよくわからない」ということは多いと思います。
そんなときにLineのグループからTODO登録できたら便利だなーという発想のもと、
覚えたてのGASでLineからSpreadSheetにTODOを飛ばすBotを作ったので紹介です。

## コード

```
// LINE Developers > Basic Information > Channel Access Token から取得
var channel_access_token = "your line bot token"; 

function doPost(e) {
  var posted_json = JSON.parse(e.postData.contents);
  var events = posted_json.events;
  events.forEach(function(event) {
    // コマンド書式判定
    if (event.message.type != "text" || isCommand(event.message.text) == false) {
      return;
    }
        
    var message = doTask(event.message.text);
    
    var postData = {
      "replyToken" : event.replyToken,
      "messages" : [
        {
          "type" : "text",
          "text" : message
        }
      ]
    };
    
    var options = {
      "method" : "post",
      "headers" : {
        "Content-Type" : "application/json",
        "Authorization" : "Bearer " + channel_access_token
      },
      "payload" : JSON.stringify(postData)
    };
    
    var reply = UrlFetchApp.fetch("https://api.line.me/v2/bot/message/reply", options);
  });
};


// コマンド書式判定
function isCommand(text) {
  var isCommnadText = false;
  var reg =/^bot:[cuh]:/i;
  
  if (text.match(reg)) {
    isCommnadText = true;
  }

  return isCommnadText;
}

// TODOリストドキュメントの操作
function doTask(command) {
  var spreadsheet = SpreadsheetApp.openByUrl("your todo list url");
  var sheets = spreadsheet.getSheets();
  for ( var i in sheets ){
    if ( sheets[i].getSheetName() == "TODO" ) {
      return orderTask(command, sheets[i])
    }
    return;
  }
}

// 命令判定と実行
function orderTask(command, sheet) {
  var message = "";
  var order = command.split(":");
  switch(order[1]) {
    case "h":
      message = showHelp();
      break;
    case "c":
      if (order.length != 6) {
        message = "書式に誤りがあります。\n[bot:c:担当者:期限:TODO:状態]の形式で入力してください。";
      } else {
        message = addRow(order[2], order[3], order[4], order[5], sheet);
      }
      break;
    case "u":
       if (order.length != 4) {
        message = "書式に誤りがあります。\n[bot:u:ID:状態]の形式で入力してください。";
       } else {
         message = updateRow(order[2], order[3], sheet);
      }
      break;
    default:
      message = "書式に誤りがあります。\nbot:c:担当者:期限:TODO:状態\nbot:u:ID:状態\nの形式で入力してください。";
      break;
  }
  
  return message;
}

// 新規追加
function addRow(person, limit, todo, state, sheetObj) {
  var lastRow = sheetObj.getLastRow();
  var lastRowId = sheetObj.getRange(lastRow, 1).getValue();
  
  if (lastRowId == "id") {
    lastRowId = 0;
  }
  
  sheetObj.getRange(lastRow+1, 1).setValue(lastRowId + 1); // id
  sheetObj.getRange(lastRow+1, 2).setValue(person); // 担当者
  sheetObj.getRange(lastRow+1, 3).setValue(limit); // 期限
  sheetObj.getRange(lastRow+1, 4).setValue(todo); // TODO
  sheetObj.getRange(lastRow+1, 5).setValue(state); // 状態
  
  return "ID:" + (lastRowId+1) + "にタスクを追加しました。";
}

// ステータス更新
function updateRow(id, state, sheetObj) {
  var lastRow = sheetObj.getLastRow();
  var lastRowId = sheetObj.getRange(lastRow, 1).getValue();
  if (id > lastRowId) {
    return "タスクリストに存在しないIDです。\nID:" + lastRowId + "が最大です。";
  }
  
  idNum = Number(id);
  sheetObj.getRange(idNum+1, 5).setValue(state); // 状態
  
  return "ID:"　 + id + "の状態を「" + state + "」に更新しました。";
}

// ヘルプ
function showHelp() {
  return "bot:c:担当者:期限:TODO:状態\nbot:u:ID:状態";
}

```

## 感想
- これだとスマホ(特にフリック入力)から入力しづらいので、コマンドは再考の余地あり。

## 参考
先人の知恵に感謝:pray:

[LINE Botをサーバーレスで開発！Google Apps ScriptとLINE Messaging APIを使ってチャットボットを作ってみた](http://inside.pixiv.net/entry/2016/11/14/150000)
[初心者がGASでSlack Botをつくってみた](https://tech.camph.net/slack-bot-with-gas/)