Slackのコメントにリアクションをつけたらasanaのタスクを作成してほしい
タイトルの通りなのですが、Slackに特定のリアクションをするとAsanaのタスクを作ってくれるbotを作りました。
挙動としてはユーザーがSlack上で特定のリアクションをつけると、それをつけられたSlackコメントがAsanaのタスクになり、担当者が事前に指定したリアクションと紐づくユーザーになる、という仕様です。
なお、このコードは基本的にスレッドを利用しする想定がないので、もしかしたらスレッド内でついた場合、完了のリアクションか、コメントの取得が想定外の挙動をする可能性があります。
Slack
SlackAPIから以下の項目を設定したものを用意してSlackにインストールします。
EventSubscriptions
Subscribe to bot event
OAuth & Permissions
Scopes
Bot Token Scopes
そしてTokenを保存しておきます。
また、後ほどEvent SubscriptionsのRequest URLにGASのウェブアプリURLを入れます。
スプシ
絵文字とユーザーを紐づけるためのシートを作成します。
私は以下の構成にしました
■シート1 紐づけ用シート(ユーザーが追加編集)
A列 絵文字を入れる列
B列 ユーザー名をAsanaの登録名でプルダウンから選択する列
C列 Vlookupを使いB列の値をシート2で調べてAsanaのGidを取得する列
■シート2 ユーザー一覧(GASで追加編集)
A列 Asanaのユーザー名
B列 AsanaのユーザーGid
ユーザー一覧は以下のようなコードでタスクスケジューラに入れてしまえばユーザーが追加されても勝手に追加されていくので便利です。
※このコード、メンバーは増える一方という前提で書いてるので、書き込み前にシートの値を削除する作業はありません。総数が減ったとき、余計なものは残ります。
function getAsanaUsers() {
var options = {
'method': 'get',
'contentType': 'application/json',
'headers': {
'Authorization': 'Bearer ' + 【asanaのアクセストークン】
}
};
var response = UrlFetchApp.fetch('https://app.asana.com/api/1.0/users', options);
var result = JSON.parse(response);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetName = ss.getSheetByName(【ユーザー一覧を入れるシート名】);
if(result.data){
for(var i = 0; i < result.data.length; i++){
sheetName.getRange(i+2,1).setValue('="'+result.data[i]["name"]+'"');
sheetName.getRange(i+2,2).setValue('="'+result.data[i]["gid"]+'"');
sheetName.getRange(i+2,3).setValue('="'+result.data[i]["resource_type"]+'"');
};
};
return;
};
Asana
以下を用意しておきます
アクセストークン
AsanaのワークスペースID
AsanaのプロジェクトID
GAS
※時間がなくてコードを整理整頓してないのでいつもよりたぶんちょっとカオスです。もともときれいではない気もするけど、いつも以上にです。転記のタイミングでちょっとだけ直したけど余裕があったら今度直します
長いので分割して書きます。
Slackから呼び出される部分
doPost(e)で値を受け取っています。
さっそくここで問題が1つ。
コードが完了するまでに一定の時間を要する場合、Slackから「もしかして届いてない?また送るね!」というホスピタリティ溢れる追いデータが届きますので、シンプルに書くと完了までの経過時間に応じてAsanaのチケットがいっぱい作成されます。
そのため、その回避が必要になります。
私はキャッシュで回避する以下のページを参考にキャッシュをして回避をしています。
■参考にしたページ
SlackのEvents APIが複数回叩かれてしまうことがあったのでその対応をした
var ss = SpreadsheetApp.getActiveSpreadsheet();
function doPost(e){
var json = JSON.parse(e.postData.getDataAsString());
var event = json.event;
try{
var channel = event.item.channel;
var ts = event.item.ts;
var cache = CacheService.getScriptCache();
var cacheKey = channel + ':' + ts;
var cached = cache.get(cacheKey);
if (cached != null) {
console.log('do nothing!');
return ContentService.createTextOutput(params.challenge);
};
cache.put(cacheKey, true, 30);
var asanaUserGid="";
if (event.type === "reaction_added") {
asanaUserGid = reactionList(event.reaction);
if (asanaUserGid>0){
asanaTaskCreate(event.item,asanaUserGid);
addReaction(event.item);;
};
};
return ContentService.createTextOutput(params.challenge);
}catch(err){
};
return ContentService.createTextOutput(json.challenge);
};
スプシを見に行く部分
この部分で以下を判別して情報を取得しています。
登録済みの絵文字と一致するか=Asana作成対象か
Asanaの担当者は誰にしたらよいか
function reactionList(reaction){
var sheetName = ss.getSheetByName(【事前に用意した絵文字と担当者の紐づけシート】);
const range = sheetName.getRange(2, 1, sheetName.getLastRow() - 1,3).getValues();
for (i=0;i<sheetName.getLastRow()-1;i++){
if (range[i][0].indexOf(reaction) >= 0){
return range[i][2];
};
};
return 0;
};
Asanaを作成する部分
ここで突然のお知らせです。
私が見間違っていなければリアクションがついたSlackの「コメント部分」は最初の取得時に取れてなさそうでしたので、このタイミングでSlackの該当ポストからコメントを拾う作業を合わせて行っています。
コメント部分の取得
function getMessage(ts,channel){
const url = "https://slack.com/api/conversations.replies"
const slack_app_token = 【Slackのアクセストークン】;
const limit =10;
const options = {
"method" : "get",
"contentType": "application/x-www-form-urlencoded",
"payload" : {
"token": slack_app_token,
"channel": channel,
"ts":ts
}
};
const response = UrlFetchApp.fetch(url, options);
const json = JSON.parse(response);
const text = json.messages[0].text
const date = new Date();
return text;
};
Asana作成部分
■参考にした記事
AsanaのAPIに関しては私が書いたほかのnote記事同様にこちらの記事が参考になりました。ありがとうございました。
function asanaTaskCreate(item,usetGidId){
var today = new Date();
var todayStr = Utilities.formatDate(today, 'JST', 'yyyy-MM-dd');
var todayStr2 = Utilities.formatDate(today, 'JST', 'yyyy-MM-dd H:MM:SS');
const workspaceId = "ワークスペースID"
const projectId = "プロジェクトID";
const name = "[Slack作成]"+todayStr2;
const planText = getMessage(item.ts,item.channel)+"\nhttps://[slack名].slack.com/archives/"+item.channel+"/p"+item.ts
const userId = usetGidId; //IDで指定
const objTask = {
"data": {
"workspace": workspaceId,
"projects": [projectId],
"name": name,
"notes": planText,
"assignee": { "gid": userId, "resource_type": "user" },
"due_on": todayStr
}
};
const asanaManager = new AsanaManager("Asanaアクセストークン");
asanaManager.createTask(objTask)
}
class AsanaManager {
constructor(token) {
this.token = token;
}
createTask(objPayload) {
const url = `https://app.asana.com/api/1.0/tasks`;
const data = this.postAsanaData(url, objPayload);
console.log('createTask', data);
return data;
}
postAsanaData(url, objPayload) {
const token = this.token;
const options = this.getPostOption(token, objPayload);
const response = UrlFetchApp.fetch(url, options);
const jobj = JSON.parse(response);
if (response.getResponseCode() !== 201) {
console.log(jobj);
}
const data = jobj["data"];
return data;
}
getPostOption(token, objPayload) {
const headers = {
"Authorization": "Bearer " + token
};
const payload = this.getJson(objPayload);
const options = {
"method": "post",
"contentType": "application/json",
"Accept": "application/json",
"headers": headers,
"payload": payload,
"muteHttpExceptions": true,
"number_value":"test"
}
return options;
}
getJson(object) {
var json = JSON.stringify(object);
console.log(json);
return json;
}
}
Slackの該当コメントにリアクションをつける部分
function addReaction(item){
var url = 'https://slack.com/api/reactions.add';
var payload = {
"token" : 【Slackのアクセストークン】,
"channel" : item.channel,
'timestamp':item.ts,
'name':'asana_task_create'
};
var options = {
"method" : "post",
"payload" : payload
};
var response = UrlFetchApp.fetch(url, options);
Logger.log(response);
return response;
}
接続!
私、最初のほうに「後ほどEvent SubscriptionsのRequest URLにGASのウェブアプリURLを入れます。」と書きましたね?
書いたコードをデプロイして、出てきたURLをSlack側に入れます。
これで、Slackで気になったコメント、やります!と返事したタスクがあったときに、Asanaのチケットがリアクション一つで作れるようになりました!
あとは、稼働させたいチャンネルに作ったBotを招待すればOKです!
この記事が気に入ったらサポートをしてみませんか?