見出し画像

Apex SDK for Slack触ってみた

はじめに

こんにちは。荒武です。今回はApex SDK for Slackの基本的な使い方ついて説明したいと思います。はじめにApex SDK for Slackの概要について説明した後、スラッシュコマンドでSalesforce上のTodoを表示する簡単なアプリを作りながらSDKの使い方や機能について解説していきます。


Apex SDK for Slackとは

Apex SDK for SlackはApexでSlackアプリを開発するためのソフトウェア開発キットで、Slackアプリ開発のための一連のツールを提供しています。
Apex SDK for Slackを用いたSlackアプリ開発ではYAMLベースのファイルを作成することでSlackアプリのUIの作成を行うことができます。
また、イベント・ショートカット・スラッシュコマンド等を通じてSlackアプリ内でSalesforceデータとのやり取りをすることも可能です。

注)Apex SDK for Slackは現在(記事公開時点)beta機能なので変更対象であることや、予告なしに開発が中断されることがあることに留意してください。

Slackアプリとは

詳細な解説に移る前にそもそもSlackアプリとは何なのかについて説明したいと思います。 SlackアプリとはSlack Platformで開発できる拡張機能の1つで、ユーザーがSlackでより生産的に働くことを助けてくれます。例えば、ZoomのSlackアプリを使えば Slack上でミーティングを作成したり、共有することが可能になります。また、 GoogleカレンダーのSlackアプリを用いればSlack内でGoogleカレンダーの予定を確認・追加することができるようになります。

環境構築

以下ではSlackアプリ開発に必要な環境構築についてApex SDK for SlackのGet Startedに沿って解説していきます。

Dev Hub組織でのSlack機能の有効化と権限の付与

Slack機能の有効化
Apex SDK for Slackは現在Beta版なのでベータ規約に同意する必要があります。以下の手順でベータ規約に同意します。

1. 任意のDev Hub組織にログインします。

2. 設定のクイック検索ボックスに「Slack」と入力し、「Slack の初期設定」を選択します。

3. Slack の初期設定画面で契約条件に同意します。

4. 続けて、クイック検索ボックスに「Slack」と入力し、「Apex で Slack アプリケーションを作成」を選択します。

5.「Apex で Slack アプリケーションを作成」画面でサービス利用規約に同意します。

権限の付与
SalesforceとSlackとの通信を可能にするために特定の権限が必要になります。権限付与の手順を以下で解説します。今回は権限セットを用いて権限付与を行っていきます。

1. クイック検索ボックスに「権限」と入力し、「権限セット」を選択します。

2. 「新規」ボタンをクリックし、表示ラベルとAPI 参照名に任意の値を入力し、「保存」ボタンをクリックします。

3. 2で作成した権限セットをクリックします

4. 権限セットの詳細画面のシステム欄の「システム権限」をクリックします。

5. 「Salesforce を Slack に接続」を有効にします。

6. 管理者ユーザーに対して権限セットを割り当てます。

Slackアプリの作成

Slackアプリ作成を以下の手順で行います。

1. https://api.slack.com/apps を開き「Create an App」をクリックします。

2.「From an app manifest」を選択し、 アプリを開発するためのワークスペースを選択します。

3. yamlのタブを選択し、 以下の内容をコピペします。(詳細についてはこちらを参照してください: https://api.slack.com/reference/manifests

_metadata:
  major_version: 1
  minor_version: 1
display_information:
  name: TODOアプリ
  description: SlackからTODOを管理するアプリです
features:
  app_home:
    home_tab_enabled: false
    messages_tab_enabled: false
    messages_tab_read_only_enabled: false
  bot_user:
    display_name: TODO
    always_online: false
  slash_commands:
    - command: /todo/list
      url: https://slack-apps.salesforce.com:9443/a/<your-app-ID>
      description: 直近のTODOを一覧表示します
      should_escape: false
oauth_config:
  redirect_urls:
    - https://auth.slack-apps.salesforce.com/slack_oauth_callback/<your-app-ID>
  scopes:
    bot:
      - commands
settings:
  event_subscriptions:
    request_url: https://slack-apps.salesforce.com:9443/a/<your-app-ID>
  interactivity:
    is_enabled: true
    request_url: https://slack-apps.salesforce.com:9443/a/<your-app-ID>
    message_menu_options_url: https://slack-apps.salesforce.com:9443/a/<your-app-ID>
  org_deploy_enabled: false
  socket_mode_enabled: false
  token_rotation_enabled: false

4. Nextをクリックします。

5. Createをクリックします。

6. Basic InformationページのInstall your appセクションでInstall to Workspaceをクリックし、任意のワークスペースにインストールします。

7. manifestファイルのoauth_config項目で設定したスコープを許可するか確認する画面が表示されるので、「許可する」をクリックします。

8. Basic Informationページ のApp CredentialsセクションでApp IDをコピーします。

9. App Manifestページを開き<your-app-ID>を8でコピーしたApp IDで書き換えます。

10. Basic Informationページ のApp-Level TokensセクションでGenerate Token and Scopesをクリックします。

11. Token Nameに任意の名前を入れ、connections:write のスコープを追加しGenerateをクリックします。

開発環境の構築

スクラッチ組織を使って開発を行うので以下の手順でスクラッチ組織開発ができるようにします。また、これから作成するSlackアプリのスラッシュコマンド初回実行時にSalesforceユーザーでの認証を求められるので当該スクラッチ組織にログインするユーザーのIDとパスワードを以下の手順の通りメモしておきます。

1. 新規プロジェクトを作成し、Dev Hub認証を行います。(参考

2. config/project-scratch-def.json を開きfeatures にSLACK(ケースセンシティブなので全て大文字で入力してください)を追記します。以下は例になります。

{
  "orgName": "yoshimasaaratake company",
  "edition": "Developer",
  "features": ["EnableSetPasswordInApi", "SLACK"],
  "settings": {
    "lightningExperienceSettings": {
      "enableS1DesktopEnabled": true
    },
    "mobileSettings": {
      "enableS1EncryptedStoragePref2": false
    }
  }
}

3. sfdx-project.json を開き、sourceApiVersion に54.0以降を指定します。以下は例になります。


{
  "packageDirectories": [
    {
      "path": "force-app",
      "default": true
    }
  ],
  "name": "slack-app",
  "namespace": "",
  "sfdcLoginUrl": "",
  "sourceApiVersion": "56.0"
}

4. project-scratch-def.jsonを定義ファイルとして指定し、スクラッチ組織を作成します。CLIで実行する場合のコマンドは以下になります。

sfdx force:org:create -f config/project-scratch-def.json -a MyScratchOrg --setdefaultusername

5. ターミナルから以下のコマンドを実行し生成されたパスワードとIDをメモしておきます。

sfdx force:user:password:generate

6. スクラッチ組織を開き、「Dev Hub組織でのSlack機能の有効化と権限の付与でDevhub組織に対して行った手順と同様にSlackとApex SDK for Slackの有効化とスクラッチ組織ユーザーへの権限付与を行います。

アプリの開発

今回は/todo/listというスラッシュコマンドを実行すると、コマンド実行日が期日で未完了のタスクを表示するようなSlackアプリを作ってみたいと思います。

Viewの作成

以下の手順でview(UI)を作成していきます。はじめに述べたようにApex SDK for SlackではUIの作成を独自のyaml形式のファイルを作成することで行います。viewファイルを定義すればSDKがよしなにSlack上のBlock kitというUI Frameworkのコンポーネントに変換してくれます。


Apex SDK for Slack enables you to build Slack apps that translate into blocks via Block Kit.

https://developer.salesforce.com/docs/platform/salesforce-slack-sdk/guide/build.html

1. force-app/main/defaultフォルダにviewdefinitionsフォルダを作成します。

Define a view in a .view file, which is YAML that describes the components that make up the view.
….
In your SFDX project, a view lives in the force-app/main/default/viewdefinitions

https://developer.salesforce.com/docs/platform/salesforce-slack-sdk/guide/views_create.html

2. force-app/main/default/viewdefinitionsフォルダにtodoList.viewファイルを作成し、以下の内容をコピペします。

description: "直近Todo一覧"
schema:
  properties:
    todos:
      type: list
      required: true
    areAllTasksCompleted: 
      type: boolean
      required: false
components:
  - definition: modal
    properties:
      title: "直近のTodo一覧"
    components:
      - definition: section
        properties:
          text: "直近のTODOはすべて完了しています!"
        visibility: "{!view.properties.areAllTasksCompleted}"
      - definition: iteration
        properties:
          foreach: "{!view.properties.todos}"
          foritem: todo
        components:
          - definition: divider
          - definition: section
            properties:
              text:
                text: "{!todo.subject} *期限:{!todo.activityDate}*"
                type: "mrkdwn"

.viewファイルの各キーの詳細についてはこちらを参照してください。

3. force-app/main/default/viewdefinitionsフォルダにtodoList.view-meta.xmlファイルを作成し、以下の内容をコピペします。

<?xml version="1.0" encoding="UTF-8"?>
<ViewDefinition xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>56.0</apiVersion>
    <isProtected>false</isProtected>
    <masterLabel>TodoList</masterLabel>
    <targetType>slack</targetType>
</ViewDefinition>

メタデータの各フィールドの詳細についてはこちらを参照してください。

Apexクラスの作成

以下の手順でスラッシュコマンドをハンドリングするクラスを作成していきます。

1. force-app/main/default/classesフォルダにTodoListSlashCommandDispatcher.clsファイルを作成し、以下の内容をコピペします。

public with sharing class TodoListSlashCommandDispatcher extends Slack.SlashCommandDispatcher {
    public override Slack.ActionHandler invoke(Slack.SlashCommandParameters parameters, Slack.RequestContext context) {
        return Slack.ActionHandler.modal(new Handler(parameters, context));
    }

    public class Handler implements Slack.ModalHandler {
        Slack.SlashCommandParameters parameters;
        Slack.RequestContext context;

        public Handler(Slack.SlashCommandParameters parameters, Slack.RequestContext context){
            this.parameters = parameters;
            this.context = context;
        }

        public Slack.ModalView call() {
            Slack.ViewReference viewReference = Slack.View.todoList.get();
            Todo[] todos = this.getTodosToBeCompleted();
            viewReference.setParameter('todos', todos);
            viewReference.setParameter('areAllTasksCompleted', todos.size() == 0);
            Slack.ModalView modalView = new Slack.ModalView.builder().viewReference(viewReference).build();
            return modalView;
        }

        private Todo[] getTodosToBeCompleted() {
            Slack.App app = Slack.App.Todo.get();
            String salesforceUserId = app.getConnectedSalesforceUserId(this.context.getTeamId(),context.getUserId());
            Todo[] result = new Todo[]{};
            Task[] tasksToBeCompleted = [SELECT Id, Subject, ActivityDate FROM Task WHERE ActivityDate <= TODAY AND OwnerId = :salesforceUserId AND Status != 'Completed' ORDER BY ActivityDate ASC];
            for (Task task : tasksToBeCompleted) {
                result.add(new Todo(task.Subject, String.format('{0}年{1}月{2}日', new List<Integer>{task.ActivityDate.year(), task.ActivityDate.month(), task.ActivityDate.day()})));
            }
            return result;
        }   
      }
      public class Todo {
        public String subject;
        public String activityDate;
        public Todo(String subject, String activityDate) {
            this.subject = subject;
            this.activityDate = activityDate;
        }
    }
}

Slackのイベントをハンドリングするクラスはハンドリングする内容によってextendするクラスを選択する必要があります。
例えばEvent(アプリのホーム画面を開いた時等)であればSlack.EventDispatcher クラスを、今回のようにスラッシュコマンドであればSlack.SlashCommandDispatcher を継承します。
その他ディスパッチャークラスについてはこちらを参照してください。

ハンドラーの中でやっていることを大まかに解説すると、以下のようになります。

  • Slack.ViewReference viewReference = Slack.View.todoList.get();でviewReferenceを取得。(Slack.View.<viewDifinition名>get()のような形で指定のviewDifinitionが取得できます。)

  • コマンドを実行したSlackユーザーにマッピングされたSalesforceユーザーのtodoを取得

  • viewReference.setParameterで、todoList.viewのschema.propertiesで定義したパラメータに取得したtodoをセット

  • viewReferenceをコンテンツとしたモーダルを返す

2. force-app/main/default/classesフォルダにTodoListSlashCommandDispatcher.cls-meta.xmlファイルを作成し、以下の内容をコピペします。

<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>56.0</apiVersion>
    <status>Active</status>
</ApexClass>

Slackアプリの作成

1. force-app/main/defaultフォルダにslackappsフォルダを作成します。

2. force-app/main/default/slackappsフォルダにTodo.slackappファイルを作成し、以下の内容をコピペします。

description: Todoアプリ
commands:
  /todo/list:
    action:
      definition: apex__action__TodoListSlashCommandDispatcher
    title: Todoを一覧表
    description: 未完了のTodoを一覧表示

コマンドとそれに対応するApexクラスが定義されています。今回はApexクラスの作成のセクションで作成したTodoListSlashCommandDispatcherを指定します。
.slackappファイルの詳細についてはこちらを参照してください。

3. force-app/main/default/slackappsフォルダにTodo.slackapp-meta.xmlファイルを作成し、以下の内容をコピペします。

<?xml version="1.0" encoding="UTF-8"?>
<SlackApp xmlns="http://soap.sforce.com/2006/04/metadata">
    <appKey></appKey>
    <appToken></appToken>
    <botScopes>commands</botScopes>
    <clientKey></clientKey>
    <clientSecret></clientSecret>
    <isProtected>false</isProtected>
    <masterLabel>TODO App</masterLabel>
    <signingSecret></signingSecret>
    <userScopes></userScopes>
</SlackApp>

4. https://api.slack.com/appsから作成したアプリの画面に遷移します

5. Basic InformationページのApp CredentialsセクションのApp IDを
Todo.slackapp-meta.xmlのappKeyにコピペします。

6.「環境構築」 > 「Slackアプリの作成」の11で作成したApp-Level TokenをTodo.slackapp-meta.xmlのappTokenにコピペします。

7. Basic InformationページのApp CredentialsセクションのClient IDをTodo.slackapp-meta.xmlのclientKeyにコピペします。

8. Basic InformationページのApp CredentialsセクションのClient SecretをTodo.slackapp-meta.xmlのclientSecretにコピペします。

9. Basic InformationページのApp CredentialsセクションのSigning SecretをTodo.slackapp-meta.xmlのsigningSecretにコピペします。

Todo.slackapp-meta.xmlの各フィールドの詳細についてはこちらを参照してください。

デプロイ

1. ソースをスクラッチ組織にプッシュします。

2. アプリをインストールしたワークスペースのパブリックチャンネルからで/todo/listコマンドを入力します。

3. プロンプトが表示されるのでConnectをクリックします。

4. ログイン画面のURLがtest.salesforce.com で始まっていなければ「Would you rather connect to a sandbox?」をクリックし、環境構築 > 開発環境の構築の手順5で生成したパスワードとIDでログインします。

5. OAuth画面でSlackを許可します。

6. ログインしたアカウントへのアクセスを確認する画面で「Slack に Salesforce アカウントへのアクセスを許可することに同意します」にチェックを入れ、許可をクリックします。

7. 接続成功メッセージが出てくるのを確認します。

補足)SalesforceユーザーとSlackユーザーのマッピングは個人設定の「Slack > Slack ユーザの対応付け」から確認ができます。

8. 再度同じチャンネルで /todo/listコマンドを実行してモーダルが表示されることを確認します。

まとめ

如何でしたか?意外と簡単にSalesforceと連携するSlackアプリが作れましたね。個人的には面倒な認証などの実装を自分で行う必要がなく、ビジネスロジックに集中できる点が楽でいいなと感じました。また、充実したドキュメントとサンプルコードがあるため、開発がしやすくなっていると思います。ぜひ皆さんも試してみてください。

参考文献リスト