Slack 次世代プラットフォーム機能を少しずつ試す - channel_created イベントトリガー編

こんにちは、Slack の[公式 SDK 開発](https://github.com/slackapi)と日本の Developer Relations を担当している瀬良 (@seratch) と申します :wave:

この記事は [Slack の次世代プラットフォーム機能を少しずつ試しながら、ゆっくりと理解していくシリーズ](https://qiita.com/seratch/items/b1449132add003e61de6)の記事です。

「次世代プラットフォーム機能って何？」という方は、以下の記事で詳しく解説しましたので、まずはそちらをお読みください。

https://qiita.com/seratch/items/ecc16b845483c9d6f9e1

この記事では、[イベントトリガー（Event Trigger）](https://api.slack.com/future/triggers/event)の使い方をご紹介します。イベントトリガーは様々な種類がありますが、今回は新しいチャンネルが作られたときに発生する "channel_created" イベントを使ってワークフローを起動してみましょう。

### ブランクプロジェクトを作成

いつものようにブランクプロジェクトを作成してゼロからコードを足していきましょう。`slack create` コマンドを実行して、選択肢から「Blank Project」を選択してください。作成したプロジェクトの構成は以下の通りです。

```bash
$ tree
.
├── LICENSE
├── README.md
├── assets
│   └── default_new_app_icon.png
├── deno.jsonc
├── import_map.json
├── manifest.ts
└── slack.json
```

今回はトリガーがメインの記事ですので、ワークフローは非常にシンプルなものにしましょう。

### ソースコードでトリガーを作る

以下の内容を `example.ts` として保存してください。

```typescript
// -------------------------
// ワークフロー定義
// -------------------------
import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";

export const workflow = DefineWorkflow({
  callback_id: "example-workflow",
  title: "Example Workflow",
  input_parameters: {
    properties: {
      channel_id: { type: Schema.slack.types.channel_id },
      channel_name: { type: Schema.types.string },
      channel_type: { type: Schema.types.string },
      creator_id: { type: Schema.slack.types.user_id },
      created: { type: Schema.types.string },
    },
    required: [
      "channel_id",
      "channel_name",
      "channel_type",
      "creator_id",
      "created",
    ],
  },
});

workflow.addStep(Schema.slack.functions.SendMessage, {
  channel_id: workflow.inputs.channel_id,
  message:
    `Hi <@${workflow.inputs.creator_id}>, thanks for creating this channel!`,
});

// -------------------------
// トリガー定義
// -------------------------
import { Trigger } from "deno-slack-api/types.ts";

const trigger: Trigger<typeof workflow.definition> = {
  type: "event",
  name: "Trigger the example workflow",
  workflow: `#/workflows/${workflow.definition.callback_id}`,
  event: { event_type: "slack#/events/channel_created" },
  inputs: {
    channel_id: { value: "{{data.channel_id}}" },
    channel_name: { value: "{{data.channel_name}}" },
    channel_type: { value: "{{data.channel_type}}" },
    creator_id: { value: "{{data.creator_id}}" },
    created: { value: "{{data.created}}" },
  },
};

export default trigger;
```

そして `manifest.ts` にこのワークフローを追加します。

```typescript
import { Manifest } from "deno-slack-sdk/mod.ts";
import { workflow as ExampleWorkflow } from "./example.ts";

export default Manifest({
  name: "distracted-bison-253",
  description: "Example workflow",
  icon: "assets/default_new_app_icon.png",
  workflows: [ExampleWorkflow],
  outgoingDomains: [],
  botScopes: [
    "commands", // 最低限一つの bot scope が必要
    "channels:read", // channel_created トリガーに必要
    "chat:write", // メッセージを投稿するための基本的な権限
    "chat:write.public", // public channel に参加することなくメッセージを投稿する権限
  ],
});
```

前回の "reaction_added" イベントのトリガーの記事を読まれた方は、チャンネル ID をコード内に列挙しなければならなかったことを覚えているかもしれません。

https://qiita.com/seratch/items/a4770243f3799b553e9c

イベントトリガーには二種類あり、"reaction_added" は n 個のチャンネルに紐づいて設定されていたのですが、今回の "channel_created" は**ワークスペースレベルでのイベント**となるため、`channel_ids` を指定する必要はありません（・・・というか、まだ作られていないチャンネルなので、そもそも指定できませんよね :sweat_smile:）。

なお、この記事執筆時点でこの次世代プラットフォームはまだベータ版の段階で、イベントトリガーはパブリックチャンネルしかサポートしておりません。正式リリース前にこの記事を読まれている方は、パブリックチャンネルでお試しください。

ということで、今回は特にコードの変更は必要なく、ワークフロー実行の準備が完了しました。

`slack triggers create --trigger-def ./example.ts` を実行します。選択肢から `(dev)` という接尾辞がついている方を選択してください。

```bash
$ slack triggers create --trigger-def ./example.ts
? Choose an app  seratch (dev)  T03E*****
   distracted-bison-253 (dev) A04FNE*****

⚡ Trigger created
   Trigger ID:   Ft04EJ8*****
   Trigger Type: event
   Trigger Name: Trigger the example workflow
```

トリガーが作成されたら、早速 `slack run` を実行してアプリがイベントを受けられるようにしましょう。そして、新しくパブリックチャンネルを一つ作ってみてください。

以下のように Example Workflow の実行ログが出力されて、

```bash
$ slack run
? Choose a workspace  seratch  T03E94MJU
   distracted-bison-253 A04FACHPQ5R

Updating dev app install for workspace "Acme Corp"

⚠️  Outgoing domains
   No allowed outgoing domains are configured
   If your function makes network requests, you will need to allow the outgoing domains
   Learn more about upcoming changes to outgoing domains: https://api.slack.com/future/changelog
✨  seratch of Acme Corp
Connected, awaiting events

2022-12-15 14:10:28 [info] [Fn04FCVD67J8] (Trace=Tr04F4HN8XQW) Function execution started for workflow function 'Example Workflow'
2022-12-15 14:10:29 [info] [Wf04FP576X3K] (Trace=Tr04G0SD63EC) Execution started for workflow 'Example Workflow'
2022-12-15 14:10:29 [info] [Wf04FP576X3K] (Trace=Tr04G0SD63EC) Executing workflow step 1 of 1
2022-12-15 14:10:30 [info] [Fn0102] (Trace=Tr04G0SD63EC) Function execution started for builtin function 'Send a message'
2022-12-15 14:10:31 [info] [Fn0102] (Trace=Tr04G0SD63EC) Function execution completed for function 'Send a message'
2022-12-15 14:10:31 [info] [Wf04FP576X3K] (Trace=Tr04G0SD63EC) Execution completed for workflow step 'Send a message'
2022-12-15 14:10:32 [info] [Fn04FCVD67J8] (Trace=Tr04F4HN8XQW) Function execution completed for function 'Example Workflow'
2022-12-15 14:10:32 [info] [Wf04FP576X3K] (Trace=Tr04G0SD63EC) Execution completed for workflow 'Example Workflow'
```

アプリから以下のようなメッセージが投稿されれば成功です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19163/f0f53255-33a1-1b0a-68e9-dc9331ef56c1.png" width=500 />

もちろん、これではあまり便利とは言えませんが、トリガーの使い方はご理解いただけたのではないかと思います。

### より高度なワークフローを実装するために

より高度なことをしたい場合、もう少し工夫が必要となりますので、簡単にいくつかのポイントを解説しておきます。

#### チャンネル内のより詳細な情報を取得する

チャンネルベースのイベントトリガーの例をご紹介した以下の記事でも触れましたが、

https://qiita.com/seratch/items/a4770243f3799b553e9c

旧来のイベント APIとは異なり、次世代プラットフォームのイベントトリガーは、必ずしもアプリのボットユーザーがそのチャンネルのメンバーであることを要求しません。

上記のような `chat:write.public` scope を使って、パブリックチャンネルへの参加なしにメッセージを投稿するということは簡単にできますが、より高度な処理（例えば、規定のメンバーを自動的に招待する、チャンネルのトピックやブックマークを整備するなど）については、ボットをそのチャンネルに [`conversations.join` API](https://api.slack.com/methods/conversations.join) を使って参加させてから実行する必要がありますので、ご注意ください。

### 終わりに

いかがだったでしょうか？今回はチャンネル ID を指定する必要がないイベントトリガーでしたので、記事内でご紹介したようにソースコードを使って作成するというアプローチで普通のユースケースには対応できるのではないかと思います。

もちろん、description などのメタデータをモーダルを開いてユーザーに入力してもらいたい、といった場合であれば、別途設定用のワークフローを用意して API でトリガーを作成するのもよいでしょう。

現在利用可能なイベントトリガーの一覧については以下のページをご参照ください。

https://api.slack.com/future/triggers/event

それでは！