はじめに
2023年4月23日に正式リリースとなったslack次世代プラットフォームの練習として、じゃんけんゲームを作成してみました。
そのソースなどをメモしておきたいと思います
前提条件など
- slack次世代プラットフォーム開発環境が整っている
- slack次世代プラットフォームについてHelloWorld程度の知識がある
参考ページ
https://api.slack.com/automation/quickstart
https://zenn.dev/blendthink/articles/f175b26f94261f
https://qiita.com/seratch/items/8c91bb367bb942dc0ffe
作成するゲームの仕様
- お題: じゃんけんゲーム
- トリガー: ショートカット
- 起動チャンネルID取得
- フロー
- アプリ起動で乱数生成
- 生成した値に対応した手とユーザ3択ボタンをトリガー取得チャンネルに
postMessage
で投稿-
addBlockActionsHandler
でボタンに応じたテキストにupdate
-
- 生成した値に対応した手とユーザ3択ボタンをトリガー取得チャンネルに
- アプリ起動で乱数生成
開発環境
- macOS Ventura 13.4
- apple M2
ソースコード例
-
slack create
でBlank projectを選択
ディレクトリ構成
.
├─ assets
│ └─...
├─ functions
│ └─ game.ts
│ └─ hand_generate.ts
├─ triggers
│ └─ trigger.ts
├─ workflows
│ └─ workflow.ts
└─ manifest.ts
trigger.ts
import { Trigger } from "deno-slack-api/types.ts";
import { workflow } from "../workflows/workflow.ts";
const trigger: Trigger<typeof workflow.definition> = {
type: "shortcut",
name: "test",
workflow: `#/workflows/${workflow.definition.callback_id}`,
inputs: {
user_id: { value: "{{data.user_id}}" },
channel_id: { value: "{{data.channel_id}}" },
},
};
export default trigger;
hand_generate.ts
import { DefineFunction, Schema, SlackFunction } from "deno-slack-sdk/mod.ts";
export const def = DefineFunction({
callback_id: "hand_generate",
title: "Hand Generate",
source_file: "functions/hand_generate.ts",
output_parameters: {
properties: {
hand: { type: Schema.types.number },
},
required: ["hand"],
},
});
export default SlackFunction(def, () => {
const hand = Math.floor(Math.random() * 3);
return { outputs: { hand } };
});
game.ts
import { DefineFunction, Schema, SlackFunction } from "deno-slack-sdk/mod.ts";
import { SlackAPI } from "deno-slack-api/mod.ts";
export const def = DefineFunction({
callback_id: "game",
title: "game",
source_file: "functions/game.ts",
input_parameters: {
properties: {
channel_id: { type: Schema.slack.types.channel_id },
user_id: { type: Schema.slack.types.user_id },
hand_number: { type: Schema.types.number },
},
required: ["channel_id", "user_id", "hand_number"],
},
});
export default SlackFunction(def, async ({
inputs,
token,
}) => {
// 0: グー, 1: チョキ, 2:パー
const hand_number = inputs.hand_number;
let hand = ":raised_hand_with_fingers_splayed:";
if (hand_number === 0) {
hand = ":fist:";
} else if (hand_number === 1) {
hand = ":v:";
}
//トリガーで取得したチャンネルに投稿
const client = SlackAPI(token);
await client.chat.postMessage({
channel: inputs.channel_id,
blocks: [
{
"type": "section",
"text": {
"type": "plain_text",
"text": "じゃんけん",
},
},
{
"type": "section",
"text": {
"type": "plain_text",
"text": hand,
"emoji": true,
},
},
{
"type": "actions",
"block_id": "buttons",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"emoji": true,
"text": ":fist:",
},
"style": "primary",
"action_id": "gu",
},
{
"type": "button",
"text": {
"type": "plain_text",
"emoji": true,
"text": ":v:",
},
"style": "primary",
"action_id": "chi",
},
{
"type": "button",
"text": {
"type": "plain_text",
"emoji": true,
"text": ":raised_hand_with_fingers_splayed:",
},
"style": "primary",
"action_id": "pa",
},
],
},
],
});
return { completed: false };
}).addBlockActionsHandler(
["gu", "chi", "pa"],
({ body, inputs, client, action }) => {
//結果テキスト
let resultText = "ざんねん";
const hand = inputs.hand_number;
switch (action.action_id) {
case "gu":
if (hand === 1) {
resultText = "勝ち!";
}
break;
case "chi":
if (hand === 2) {
resultText = "勝ち!";
}
break;
case "pa":
if (hand === 0) {
resultText = "勝ち!";
}
break;
}
//投稿内容を更新
client.chat.update({
channel: inputs.channel_id,
ts: body.container.message_ts,
"blocks": [
{
"type": "section",
"text": {
"type": "plain_text",
"text": `<@${body.user.name}>` + "さん\n結果: " + resultText,
},
},
],
});
//アプリ完了処理
client.functions.completeSuccess({
function_execution_id: body.function_data.execution_id,
outputs: {},
});
},
);
workflow.ts
import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";
import { def as Game } from "../functions/game.ts";
import { def as HandGenerater } from "../functions/hand_generate.ts";
//トリガーから値を受け取る
export const workflow = DefineWorkflow({
callback_id: "workflow",
title: "workflow",
input_parameters: {
properties: {
user_id: { type: Schema.slack.types.user_id },
channel_id: { type: Schema.slack.types.channel_id },
},
required: ["user_id", "channel_id"],
},
});
const generate = workflow.addStep(HandGenerater, {});
workflow.addStep(Game, {
channel_id: workflow.inputs.channel_id,
user_id: workflow.inputs.user_id,
hand_number: generate.outputs.hand,
});
manifest.ts
import { Manifest } from "deno-slack-sdk/mod.ts";
import { workflow } from "./workflows/workflow.ts";
import { def as Game } from "./functions/game.ts";
import { def as HandGenerater } from "./functions/hand_generate.ts";
export default Manifest({
name: "Rock-Paper-Scissors",
description: "Rock-Paper-Scissors",
icon: "assets/default_new_app_icon.png",
functions: [HandGenerater, Game],
workflows: [workflow],
outgoingDomains: [],
botScopes: [
"commands",
"chat:write",
"chat:write.public",
],
});
簡単になりましたが以上です
疑問点、ご指摘等ありましたらお気軽にコメントください
よろしくお願いいたします