妻からの買い物リストの管理をTodoistでやっています。
LINEのMessaging APIを使ってみたかったのと、もっと簡単にタスク作成をしたかったので、Todoistのタスク作成をするLINE BOTを作ってみました。
LINE BOTの準備
準備するもの
- LINE Businessアカウント
- HTTPSに対応したサーバ
LINE Businessアカウント
* 以下から利用登録
https://business.line.me/ja/services/bot
Messaging APIかDeveloper Trialかお好きな方を。
Messaging APIとDeveloper Trialの違い
Developer Trial | Messaging API(Free Plan) | |
---|---|---|
Push API(※1) | 利用できる | 利用できない |
追加可能友だち数 | 50人まで | 制限なし |
プレミアムID | 利用できない | 利用可能 |
API Rate limits | 1,000/分 | 10,000/分 |
- (※1)Push API
Push APIはキャンペーン通知などBOTから任意のイベントでメッセージを送る
LINE BOTの設定
LINE@ MANAGERから設定します。
-
Webhook送信: 利用する
利用しないとサーバにリメッセージが送られない -
Botのグループトーク参加: どちらでも好きな方を
-
自動応答メッセージ: 利用しない
利用するにすると固定メッセージしか返さないので注意
HTTPSに対応したサーバ
HerokuやAWSをつかった記事がよくありますけど、今回はGoogle Apps Script(GAS)で構築します。
GASの実装
- GASの作成
その他から表示されなかったら「アプリを追加」から作成
LINEからのリクエストを受け取る
まずはオウム返しするサンプルを作成します
Messaging APIはPOSTでリクエストしてくるのでdoPost関数を実装します
var CHANNEL_ACCESS_TOKEN = 'LINE Developersから取得'
function doPost(e) {
// 返事用のトークン。一度のみ使うことができる
var replyToken = JSON.parse(e.postData.contents).events[0].replyToken;
// 投稿したメッセージ
var userMessage = JSON.parse(e.postData.contents).events[0].message.text;
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': userMessage, // オウム返しをする
}],
}),
});
return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}
ウェブアプリケーションとして導入
Messaging APIからGASへのリクエストを行うためにGASを公開してURLをLINE側に登録します。
- GASから導入 > ウェブアプリケーションとして導入で公開
- URLをコピってLINE DevelopersのWebhook URLに設定
あとは作成したアカウントを友達登録してメッセージを送信するとオウム返ししてくれます。
Todoistのタスク登録
続いて本題のTodoistのタスク登録を実装します。
TodoistのAPI: https://developer.todoist.com/
まずはTodoistのAPIをたたくためのAPIトークンを取得
そして取得したAPIトークンでTodoistのAPIにリクエスト
var CHANNEL_ACCESS_TOKEN = 'LINE Developersから取得'
function doPost(e) {
// 返事用のトークン。一度のみ使うことができる
var replyToken = JSON.parse(e.postData.contents).events[0].replyToken;
// 投稿したメッセージ
var userMessage = JSON.parse(e.postData.contents).events[0].message.text;
var status = createTask(userMessage);
if (status === 200) {
answerText = userMessage + "を作成した!";
} else {
answerText = "何か失敗した。。。";
}
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': answerText
}],
}),
});
return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}
// タスク登録
function createTask(userMessage) {
var url = "https://todoist.com/API/v7/sync",
uuid = Utilities.getUuid(),
tempId = Utilities.getUuid(),
formData, response;
formData = {
"token": "TODOIST API TOKEN",
"commands": JSON.stringify([{
"type": "item_add",
"temp_id": tempId,
"uuid": uuid,
"args": {
"content": userMessage[0],
"project_id": 000000 // TodoistのプロジェクトのID
}
}])
};
response = UrlFetchApp.fetch(url, {
"method" : "post",
"payload" : formData
});
return response.getResponseCode();
}
これで、何か登録したいタスクをメッセージに投稿すると、Todoistに登録される
Todoistのタスク一覧取得
次に、登録したタスク一覧をTemplate messageのCarouselを使って返すようにしました
コード
注意点として、
- Template messageのCarouselは5件までしか横にスライドできないので、columnの配列の件数を5件にする必要がある
- 5件以上ある場合は複数メッセージ(messages)を返す必要がある
var CHANNEL_ACCESS_TOKEN = 'LINE Developersから取得'
function doPost(e) {
// 返事用のトークン。一度のみ使うことができる
var replyToken = JSON.parse(e.postData.contents).events[0].replyToken;
// 投稿したメッセージ
var userMessage = JSON.parse(e.postData.contents).events[0].message.text;
// > listだとタスク登録しない
if (userMessage.indexOf("> list") === 0) {
var response = getTasks();
messages = createCarousel(response.items));
} else {
var status = createTask(userMessage);
if (status === 200) {
answerText = userMessage + "を作成した!";
} else {
answerText = "何か失敗した。。。";
}
messages = [{
'type': 'text',
'text': answerText
}];
}
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': messages,
}),
});
return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}
// タスク一覧の取得
function getTasks() {
var url = "https://todoist.com/API/v7/projects/get_data",
formData, options, response;
formData = {
"token": "TODOIST API TOKEN",
"project_id": "Todoist Project ID"
};
response = UrlFetchApp.fetch(url, {
"method" : "post",
"payload" : formData
});
return JSON.parse(response.getContentText());
}
// Carousel情報の作成
function createCarousel(items) {
var i, max,
columns = [],
itemsArray = [],
messages = [];
// Template messageのCarouselは5件までしか横にスライドできないので、複数メッセージを返す必要がある
for (i = 0; i < items.length; i += 5) {
itemsArray.push(items.slice(i, i + size));
}
// columnsに5件ずつの複数のメッセージを作成
for (i = 0, max = itemsArray.length; i < max; i++) {
messages.push( {
type: "template",
altText: "一覧",
template: {
type: "carousel",
columns: createColumns(itemsArray[i])
}
} );
}
return messages;
}
function createColumns(items) {
var i, max,
columns = [];
for (i = 0, max = items.length; i < max && i < 5; i++) {
columns.push({
text: items[i].content,
actions: [{ // ボタンの設定
"type": "message",
"label": "完了",
"text": "> finish " + items[i].id
}]
});
}
return columns;
}
これで"> list"と投稿すると一覧を返します
リッチメニューの作成
LINEの公式アカウントを見ているとトークを開いた途端に下から出てくるやつです。(ヤマト運輸とか)
> listと打つのはめんどいのでリッチメニューからタスク一覧をすぐに表示できるようにします。
LINE@ MANAGER > リッチコンテンツ作成 > リッチメニューから作成します。
おまけ
Google Apps Scriptのコード内からセキュアな文字列を使いたいときスクリプトプロパティを使うといい感じです。
var property = PropertiesService.getScriptProperties().getProperty("CHANNEL_ACCESS_TOKEN");