slackapi / bolt-js

A framework to build Slack apps using JavaScript
https://tools.slack.dev/bolt-js/
MIT License
2.74k stars 393 forks source link

Send Message from Installation Callback #682

Closed josephphayden closed 3 years ago

josephphayden commented 3 years ago

Description

After a user has installed my app, I would like to be able to send them a welcome message.

As there is no installation event to respond to, I believe I need to do this in either the storeInstallation method of the installationStore, or the success callback option in the installerOptions. However, there is no client available in either of these callbacks, so I can't simply call client.chat.postMessage.

I understand the the client is also available from the top-level app object, however the storeInstallation and success methods need to be defined in the config that is used when creating the app, before the app object exists.

Sorry if I'm missing something obvious, please let me know how I can proceed. Thanks!

What type of issue is this? (place an x in one of the [ ])

Requirements (place an x in each of the [ ])

mwbrooks commented 3 years ago

Hey @josephphayden, this is a good question and you're not missing anything obvious! I took some time to ask the other maintainers for guidance on best practices and you've hit the main approaches.

Approach 1 - Success callback and app.client:

In this approach, we use the success callback from the OAuth installerOptions to send a DM to the user. Thanks to JavaScript closures, the app object will be available when the callback is triggered, even though it wasn't instantiated when the success callback was declared.

const { App } = require('@slack/bolt');

// Initializes your app with your bot token and signing secret
const app = new App({
  signingSecret: process.env.SLACK_SIGNING_SECRET,
  clientId: process.env.SLACK_CLIENT_ID,
  clientSecret: process.env.SLACK_CLIENT_SECRET,
  stateSecret: 'my-state-secret',
  scopes: ['chat:write'],
  installerOptions: {
    callbackOptions: {
      success: (installation, installOptions, req, res) => {
        // Display a success page or redirect back into Slack
        //
        // Learn how to redirect into Slack:
        // https://github.com/slackapi/node-slack-sdk/blob/main/packages/oauth/src/index.ts#L527-L552
        res.send('successful');

        // Send a welcome message to the user as a DM
        app.client.chat.postMessage({
          token: installation.bot.token,
          channel: installation.user.id,
          text: ':wave: Welcome!'
        });
      }
    }
  }
});

Approach 2 - Success callback and declaring your own WebClient:

Production code isn't always as simple as sample code. Sometimes you may have trouble accessing app after it's been instantiated (maybe Bolt should expose app in these callbacks?) - for example, if you have declared your success callback in a module. In these cases, you can create your own WebClient:

const { App } = require('@slack/bolt');
const { WebClient } = require('@slack/web-api'); // comes bundled with @slack/bolt

// Initializes your app with your bot token and signing secret
const app = new App({
  signingSecret: process.env.SLACK_SIGNING_SECRET,
  clientId: process.env.SLACK_CLIENT_ID,
  clientSecret: process.env.SLACK_CLIENT_SECRET,
  stateSecret: 'my-state-secret',
  scopes: ['chat:write'],
  installerOptions: {
    callbackOptions: {
      success: (installation, installOptions, req, res) => {
        // Display a success page or redirect back into Slack
        //
        // Learn how to redirect into Slack:
        // https://github.com/slackapi/node-slack-sdk/blob/main/packages/oauth/src/index.ts#L527-L552
        res.send('successful');

        // Send a welcome message to the user as a DM
        const client = new WebClient(installation.bot.token);
        client.chat.postMessage({
          token: installation.bot.token,
          channel: installation.user.id,
          text: ':wave: Welcome!'
        });
      }
    }
  }
});

Caveat - Triggered on every successful install, including re-installs:

It's worth mentioning that the success callback is triggered on every successful installation, including re-installs.

You can recreate this experience by visiting the OAuth install route twice. One the second visit, your user/team has been installed and the success callback triggers again.

This can be a good or bad experience, depending on your app. But warmly welcoming a user twice, might be a little weird 😆

Bolt doesn't provide a built-in way of detecting existing users (maybe it should?). To improve this experience, you would need customize your installationStore.fetchInstallation callback to check if a team was successfully fetched. If you'd like an example, I can try to toss one together!

josephphayden commented 3 years ago

Hey @mwbrooks, thanks for your fast and in-depth response! 👍

I've got things working using the separate WebClient within the installationStore methods, and am sending the welcome message only on initial install as you've suggested.

arian0zen commented 1 year ago

hey @josephphayden and @seratch I am trying use that callback, but an error say res.send is not a function! how can i redirect to somewhere after installing the bot?

Or i would really appreciate, if you can let me know how to redirect back to slack. I mean, when i dont use the installerOption > callback then after allowing to install the browser say 'open slack' and this works fine.. I want to do exactly same thing but also the direct welcome message.