前置き
slackで「投稿ルールが守られない問題」を自作のスラッシュコマンドで解決する(設定編)からの続きになります。
コード全文はgithubリンクをご確認ください。
処理の流れ(再掲)
slack上でスラッシュコマンドを投稿
→slackAppの「コマンドごとに設定されたURL」にPOST
→GoogleAppsScript(サーバー)が受けてダイアログを返す
→slack上にダイアログが表示され、各項目を入力して投稿をする。
→slackAppの「InteractiveComponentsに設定されたURL」にPOST
→GoogleAppsScript(サーバー)が受けて、入力内容を整形してslackに投稿
GASで処理が行われるのは
- ①GoogleAppsScript(サーバー)が受けてダイアログを返す
- ②GoogleAppsScript(サーバー)が受けて、入力内容を整形してslackに投稿
の2つになりますので、①②それぞれ解説します。
①②共通処理
function doPost(e) {
//GASのプロパティストアに登録したVerification Token
var verified_token = PropertiesService.getScriptProperties().getProperty('verified_token');
var verificationToken = e.parameter.token || JSON.parse(e.parameter.payload).token || null;
if (verificationToken !== verified_token) { // AppのVerification
console.log(e);
return ContentService.createTextOutput();
}
トークンによる認証を入れています。
①と②でslackから送られるデータ構造がだいぶ違う(片方はJSON.parse必要)ことに注意しましょう。
今回のbotの機能とは直接関係ないですが、無職やめ太郎さんのJSの記事を読んで、
var verificationToken = e.parameter.token ? e.parameter.token : ((e.parameter.payload && JSON.parse(e.parameter.payload).token) ? JSON.parse(e.parameter.payload).token : null);
と書いていたのを、
var verificationToken = e.parameter.token || JSON.parse(e.parameter.payload).token || null;
とリファクタ出来ました。非常に勉強になりました。
①GoogleAppsScript(サーバー)が受けてダイアログを返す
if (e.parameter.command === '/bihin' && e.parameter.channel_name !== channelName) {
console.log(e);
//response_typeをephemeralにすることで実行ユーザーにだけ通知される。
var rtnjson = {"response_type": "ephemeral","text": "/bihinコマンドは備品管理チャンネルでのみ使用可能です"};
return ContentService.createTextOutput(JSON.stringify(rtnjson)).setMimeType(ContentService.MimeType.JSON);
期待しているチャンネル以外でコマンドが実行された際にエラー文言を表示する処理です。
コード内にコメントで書いていますが ephemeal
のオプションをつけることで「投稿者だけが見えるメッセージ」をslack上に表示させる事ができます。
} else if (e.parameter.command === '/bihin') {
var createdDialog = createDialog(e);
var options = {
'method' : 'POST',
'payload' : createdDialog,
};
var slackUrl = "https://slack.com/api/dialog.open";
var response = UrlFetchApp.fetch(slackUrl, options);
return ContentService.createTextOutput();
正しいチャンネルでコマンドが実行された場合に createDialog(e)
でダイアログを生成してslackに返します。
(私は dialog.open
を実行する際にメソッドを POST
にするのを忘れてハマったのでご注意下さい。。。)
function createDialog(e){
var trigger_id = e.parameter.trigger_id;
var token = PropertiesService.getScriptProperties().getProperty('OAuth_token');
var dialog = {
"token": token, // OAuth_token
"trigger_id": trigger_id,
"dialog": JSON.stringify({
"callback_id": "irai_dialog",
"title": "備品購入依頼依頼フォーム",
"submit_label": "依頼する",
"elements": [
{
"type": "text",
"label": "品名",
"name": "name"
},
{
"type": "text",
"subtype": "url",
"label": "購入希望品URL",
"name": "url",
},
{
"type": "select",
"label": "購入承諾者(上長)",
"name": "approver",
"options": [
{
"label": "A部長",
"value": "A部長"
},
{
"label": "B課長",
"value": "B課長"
}]
},
{
"type": "text",
"label": "納品希望日(※希望日無ければ↓は編集しなくてokです)",
"name": "date",
"value": "2019/XX/XX"
},
{
"type": "textarea",
"label": "備考欄",
"name": "freeText",
"optional": true, //この指定がないとrequiredになる
"placeholder": "備考欄のみ入力必須ではありません"
},
]
})
};
return dialog;
}
slack公式のダイアログの説明がかなり充実しているので、そちらを参考にすると良いと思います。
少しだけ役立つかもしれない情報を箇条書きで記しておきます。
- elementsとして配置できる要素の数に上限がある(10個。つい最近まで5個だったような・・・)
- どの入力欄もデフォルトで入力必須(
"optional": true
で必須解除) - ユーザーに見せずに情報を保持させるためのプロパティとして
state
がある -
subtype
を使うとスマホ経由での入力が楽になる(例:"subtype":"tel"
とすれば数字入力が自動で選ばれる)
②GoogleAppsScript(サーバー)が受けて、入力内容を整形してslackに投稿
} else {
var p = JSON.parse(e.parameter.payload)
var postChannel = p.channel.id;
var s = p.submission;
var free = s.freeText || "なし"
var test = slackApp.postMessage(postChannel,
"購入依頼by <@" + p.user.id + ">\n【購入品名】 :" + s.name
+"\n【購入URL】 :" + s.url +"\n【購入承諾者】:" + s.approver
+ "\n【納品希望日】:" + s.date +"\n【備考】 :" + free,
{"username" : "備品依頼bot", "icon_emoji" : ":hammer_and_wrench:"});
return ContentService.createTextOutput();//←これが無いとslackのダイアログが閉じない。
}
ここで実行される処理は、整形してslackに投稿するだけです。
コメントで書いていますが postMessage()
をしただけではダイアログ自体が閉じないので、 ContentService.createTextOutput()
という処理を最後に入れましょう。
コード解説は以上となります。ありがとうございました。