DEV Community

Cover image for Post Message,Trigger Modals on Slack with Firebase Cloud Functions and Slack API
Pavani K
Pavani K

Posted on

Post Message,Trigger Modals on Slack with Firebase Cloud Functions and Slack API

The Slack API offers various methods to interact with your workspace, giving you plenty of options.

To create a Slack app, follow these steps:

  1. Visit https://api.slack.com/apps to start creating your app.
  2. Name your app and select the workspace.
  3. Once your app is created, you'll be taken to the app's environment.
  4. In the left side menu, select "Basic Information" to access your app credentials. That's it! You're all set to start building your Slack app.

To obtain a bot token for posting messages, follow these steps:

  • Click on the "OAuth & Permissions" option from the left side
  • Scroll up to the top of the OAuth & Permissions pages and click the green "Install App to Workspace" button.
  • click on allow and come back to the page OAuth & Permissions menu scroll down to section scopes and add scopes.
  • To generate a bot token, you need to specify the bot scopes. For our implementation, select the following scopes: "chat:write," "users:read," "channels:read," and "commands."

once you add bot scopes automatically generates bot token.

Project:

Create any project with Firebase setup (react-firebase)or your wish
Configure firebase to the project and add firebase cloud functions setup to it..

In the terminal, run the command npm i @slack/web-api to install package. This package allows you to interact with the Slack workspace and perform actions such as sending messages, trigger modals!!.

const { WebClient } = require("@slack/web-api");
const botToken="xoxb-565644"//paste your bot token
const web = new WebClient(botToken);
Enter fullscreen mode Exit fullscreen mode

configured web, now we can use it to post message, trigger modals,get users/channels etc....

To get all the channels of your slack workspace:

exports.channelsList = functions.https.onCall(async (data, context) => {
  try {
    const response = await web.conversations.list();
    const channels = response.channels;
    return channels; //return channel list & info
  } catch (error) {
    console.error("Error:", error);
    return error.message;
  }
});

Enter fullscreen mode Exit fullscreen mode

run firebase emulators:start --only functions to get local url you can run the local url on postman & check response
dont forget to add {data:{}} in the body

To get all the users of your slack workspace:

exports.usersList = functions.https.onCall(async (data, context) => {
  try {
    const response = await web.users.list();
    const users = response.members;
    return users;//returns users of workspace with user related info
  } catch (error) {
    console.error("Error:", error);
  }
});
Enter fullscreen mode Exit fullscreen mode

To Post a message to the channel of your slack workspace:

exports.sendMessageToChannel = functions.https.onCall(
  async (data, context) => {
    try {
    //we can get channelid in two ways
    //1. go to slack click on channel now on top click on channel name now scroll down you can see id
    //2.run the above channelsList endpoint copy the channelid from response
      await web.chat.postMessage({
        channel: channelId, //paste channel id
        text: message,
      });
      return "Message sent successfully.";
    } catch (error) {
      console.error("Error:", error);
      return "Error while posting message to channel";
    }
  }
);

Enter fullscreen mode Exit fullscreen mode

you can post message to all the users,and channels, by maping the obtained list

To Trigger a modal with shortcut on slack, follow these steps:

REMEMBER NEED TO CREATE AN HTTPS END POINT URL
which triggers request payload for any interaction on slack!!!!!
Here, we are utilizing Firebase Cloud Functions to deploy and retrieve the deployed URL.

  • From the left side menu, select "Interactivity & Shortcuts" and enable interactivity.
  • Under "Shortcuts," click on "Create New Shortcut" and fill in the required details to create a global shortcut. Once done, create the shortcut.
  • In any Slack channel, navigate to the message input area and enter a slash ('/') character. You will now see the name of the shortcut you created.
  • To receive requests containing payloads, add the URL of your deployed endpoint under "Interactivity Request URL."
  • By completing these steps, you can enable interactivity, create a global shortcut, and configure the endpoint URL to receive requests with payloads.
  • Here we are creating one endpoint to trigger modal & get response from modal back

Example

Designed a modal which shows two meetings with rating selection option

Get back the selected rating of meeting from user and post a message to channel

Modal Preview

exports.handleMeetingsShortcut = functions.https.onRequest(async (req, res) => {
  try {
    const payload = JSON.parse(req.body.payload);
    const trigger_id = payload?.trigger_id;

    const view = { //to design custom blocks to show on modal
      type: "modal",
      callback_id: "meetings_rating",//created shortcut id
      title: {
        type: "plain_text",
        text: "Modal Title",
      },
      blocks: [
        {
          type: "section",
          text: {
            type: "mrkdwn",
            text: "*Meeting 1*\nTopic: Project Updates\nTime: 10:00 AM - 11:00 AM",
          },
          accessory: {
            type: "static_select",
            action_id: "meeting1_rating_select",
            placeholder: {
              type: "plain_text",
              text: "Rate this meeting",
            },
            options: [
              {
                text: {
                  type: "plain_text",
                  text: "⭐️⭐️⭐️⭐️⭐️",
                },
                value: "5",
              },
              {
                text: {
                  type: "plain_text",
                  text: "⭐️⭐️⭐️⭐️",
                },
                value: "4",
              },
              {
                text: {
                  type: "plain_text",
                  text: "⭐️⭐️⭐️",
                },
                value: "3",
              },
              {
                text: {
                  type: "plain_text",
                  text: "⭐️⭐️",
                },
                value: "2",
              },
              {
                text: {
                  type: "plain_text",
                  text: "⭐️",
                },
                value: "1",
              },
            ],
          },
        },
        {
          type: "section",
          text: {
            type: "mrkdwn",
            text: "*Meeting 2*\nTopic: Sales Strategy\nTime: 2:00 PM - 3:00 PM",
          },
          accessory: {
            type: "static_select",
            action_id: "meeting2_rating_select",
            placeholder: {
              type: "plain_text",
              text: "Rate this meeting",
            },
            options: [
              {
                text: {
                  type: "plain_text",
                  text: "⭐️⭐️⭐️⭐️⭐️",
                },
                value: "5",
              },
              {
                text: {
                  type: "plain_text",
                  text: "⭐️⭐️⭐️⭐️",
                },
                value: "4",
              },
              {
                text: {
                  type: "plain_text",
                  text: "⭐️⭐️⭐️",
                },
                value: "3",
              },
              {
                text: {
                  type: "plain_text",
                  text: "⭐️⭐️",
                },
                value: "2",
              },
              {
                text: {
                  type: "plain_text",
                  text: "⭐️",
                },
                value: "1",
              },
            ],
          },
        },
      ],
      submit: {
        type: "plain_text",
        text: "Submit",
      },
    };
    if (payload.type === "shortcut") {//triggered shortcut
      const response = await web.views.open({
        trigger_id,
        view,
      });
      if (response.ok) {
        res.sendStatus(200);
      } else {
        throw new Error(response.error || "Failed to open modal.");
      }
    } else if (
      //on click submit aftr selecting rating
      payload.type === "view_submission" && 
      payload.view.callback_id === "meetings_rating"
    ) {
      const user = payload.user.username;
      const values = payload.view.state.values;
      let meeting1Rating, meeting2Rating;
     //get the selected ratings, based on action_id
      for (const key of Object.keys(values)) {
        const obj = values[key];
        if (obj && obj.meeting1_rating_select) {
          meeting1Rating = obj.meeting1_rating_select.selected_option.value;
          break;
        }
      }

      for (const key of Object.keys(values)) {
        const obj = values[key];
        if (obj && obj.meeting2_rating_select) {
          meeting2Rating = obj.meeting2_rating_select.selected_option.value;
          break;
        }
      }

      const messageText = `*Meeting Ratings*\n\n${user} has rated the meetings:\n\nMeeting 1: ${meeting1Rating}\nMeeting 2: ${meeting2Rating}`;
//post message to channel with username & selected ratings
      const result = await web.chat.postMessage({
        channel: "C05788W6A",
        text: messageText,
      });

      if (result.ok) {
        res.send();
      } else {
        console.error(result.error || "Failed to post message to channel.");
        res.status(500).send("Failed to post message to channel.");
      }
    } else {
      console.error("Failed load payload");
      res.sendStatus(200);
    }
  } catch (err) {
    console.error(err, "error");
    res.sendStatus(500);
  }
});
Enter fullscreen mode Exit fullscreen mode
  • Deploy the function using firebase deploy function:handleMeetingsShortcut
  • check the deployed url on your firebase project
  • Paste the url under interactivity reaquest url

Here payload holds everything

  • if you trigger shortcut it returns type shortcut in payload
  • if you click on submit on modal triggers payload with type view submission. Additionally, you can utilize blocks to create custom designs and enhance the user experience in your Slack app.

Docs:
https://api.slack.com/block-kit/interactivity -- design blocks
https://firebase.google.com/docs/functions/get-started?gen=1st -- to setup firebase

Conclusion:

As a beginner tried to explore the slack api. How we can interact with slack via code "Excited me".....
Slack api Documentation provides more information regarding
posting messages to slack as a text,blocks, and trigger modals.

Thanks for your Read hope it helps...😍

Top comments (0)