LoginSignup
99
83

More than 3 years have passed since last update.

slackで「投稿ルールが守られない問題」を自作のスラッシュコマンドで解決する(GASコード解説編)

Last updated at Posted at 2019-06-15

前置き

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() という処理を最後に入れましょう。

コード解説は以上となります。ありがとうございました。

99
83
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
99
83