0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

slack次世代プラットフォームでじゃんけんアプリを作ってみた

Last updated at Posted at 2023-06-22

はじめに

2023年4月23日に正式リリースとなったslack次世代プラットフォームの練習として、じゃんけんゲームを作成してみました。
そのソースなどをメモしておきたいと思います

slackapp_1.png

前提条件など

  • 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

開発環境

  • 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",
  ],
});

簡単になりましたが以上です
疑問点、ご指摘等ありましたらお気軽にコメントください
よろしくお願いいたします

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?