Start building admin tools on Slack without going into complex slack syntax and flows.

Overview

Slackmin

npm version

Slackmin helps in easy integration with slack to use slash commands, interactive components, format and send messages, design and use modals. One use case of Slackmin is to implement admin functionality over slack.

Why Slackmin?

  • Slackmin provides Message and Modal wrappers that help in easy formatting & sending of messages, sending system alerts and creating modals.
  • Slackmin's multiple slack app support helps in overcoming the 25 slash commands limitation in slack apps. Also, you can create applications to manage content management systems, user management systems, order management systems, and many more.
  • The block actions payload and view submission payload are validated and parsed.

Additionally, Slackmin provides following built-in security features:

  • Sanitize unwanted HTML tags from parameters obtained in request body, query, headers. HTML sanitization is recommended by Open Web Application Security Project (OWASP)
  • Signature / signed secret verification is provided as a middleware ready to be plugged in and used for all the requests coming from slack. This guide gives a detailed description of signature verification.
  • Slack app id is validated against whitelisted app ids. This validation is also provided via middleware.
  • Slack channel validation is done to only allow requests from whitelisted slack channels. For example, there can be one admin channel, in which we add all the admins and they can execute slash commands from there. Requests coming from other channels will be outright rejected. This validation is also provided via middleware.
  • User authentication helps in validating whether the user has admin rights or not. We validate the slack id of the user against whitelisted slack ids. This validation is also provided via middleware.
  • Slack app’s workspace domain validation is also exposed as a middleware.

Thus Slackmin helps in integrating with slack involving minimum efforts (hence the name, Slackmin).

Demo

Let's first see some quick demos of the functionality which can be easily implemented using Slackmin.

Slash Command

In the following, you can see a working slash command which is used to fetch user info from the server.

Slash Command Demo

Open Modal

Along with the user information which is fetch by the above slash command, the message also has a button for "Update Phone". In the following demo, we can see that a confirmation popup comes on pressing the button. When we confirm, a modal with input for the new phone number opens. User enters the new phone numner and submits the modal. After the updation, a success message is sent.

Interactive Component Demo

Prerequisites

Express.js routing knowledge is required.

Slack app setup

First, we need to setup a slack app as mentioned in this guide. Following are the major steps involved:

Keep a note of your App ID and Signing Secret from "Basic Information" section of your app. Also note the Bot User OAuth Token from "OAuth & Permissions" section of your app. These will be required in further steps.

Install NPM

npm install @plgworks/slackmin --save

Initialize

While using the package, create a singleton object of Slackmin and then use it across the application. Example snippet for the Slackmin singleton object is given below.

const Slackmin = require('@plgworks/slackmin');

const appConfigs = [
  {
    id: '<slack_app_id>',
    secret: '<slack_signing_secret>',
    slack_bot_user_oauth_token: '<slack_bot_user_oauth_token>'
  }
];

const whiteListedChannels = ['<slack_channel_id>', '<slack_channel_id>', '<slack_channel_id>'];

const slackDomain = '<your_slack_domain>';

const whitelistedUsers = ['<slack_member_id>', '<slack_member_id>', '<slack_member_id>'];

const slackmin = new Slackmin(
  appConfigs,
  whiteListedChannels,
  slackDomain,
  whitelistedUsers
);

module.exports = slackmin;

Initialization Params

1. appConfigs is an array of app config objects allowing Slackmin to support multiple apps. Each app config consists of id, secret and token.

  • id: This is your slack app id.
  • secret: Your app's signing secret. This is used to do request signature verification.
  • slack_bot_user_oauth_token: This is the Bot User OAuth Token.

2. whiteListedChannels is an array of whitelisted channel ids. Only whitelisted users are allowed to execute slash commands in the whitelisted channels.


3. slackDomain is your slack app's workspace domain. It could be a team workspace or individual workspace.


4. whitelistedUsers is an array of whitelisted slack member ids. Only whitelisted users are allowed to execute slash commands in the whitelisted channels.

Middlewares

Slackmin middlewares are used with slash commands as well as with interactive routes. These middlewares format and preprocess the Slack payload, and sanitize unwanted HTML tags from parameters obtained in the request body, query and headers. Slackmin has a built-in security layer for request verification, app id validation, channel id validation, and slack member id validation.

Interactive Component Middlewares

const express = require('express');
const slackmin = require('path-to-your-slackmin-singletone-provider');
const router = express.Router();

// common middlewares
// This set of middlewares can be used with slash commands as well as with interactive routes.
router.use(
  slackmin.commonMiddlewares
);

//  interactive-endpoint middlewares
// This set of middlewares can be used with interactive routes.
router.use(
  slackmin.interactiveEndpointMiddlewares
);

// Example interactive endpoint
router.post(
  '/interactive-endpoint',
  async function(req, res, next) {
     // your business logic
    // req.decodedParams contains sanitized parameters and must be used to read data for further business logic.
   console.log(req.decodedParams);  }
);

Slash Command Middlewares

const express = require('express');
const slackmin = require('path-to-your-slackmin-singletone-provider');
const router = express.Router();

// common middlewares
// This set of middlewares can be used with slash commands as well as with interactive routes.
router.use(
  slackmin.commonMiddlewares
);

// slash ('/') command middlewares
// This set of middlewares can be used with Slash commands.
router.use(
  slackmin.slashCommandMiddlewares
);

// Write all routes specific to slash commands below.
// Example slash command endpoint
router.post(
  '/slash-command',
  async function(req, res, next) {
     // your business logic
    // req.decodedParams contains sanitized parameters and must be used to read data for further business logic.
   console.log(req.decodedParams);
  }
);

Important Note: req.decodedParams contains sanitized parameters and must be used to read data for further business logic.

Interactive Components

Slack provides a range of visual components, called Block Kit, used to layout complex information. Each block is represented in slack APIs as a JSON object. You can include up to 50 blocks in a message and 100 blocks in modals. You can find the Block Kit reference here.

Message Wrapper

Slackmin Message wrapper provides simple methods to create and format complex message layouts thus simplifies the creation of block elements.

Methods

  • addSection
    • Parameters: text (string)
    • Description: Adds a section block with the provided text. Supports mrkdwn.
  • addSectionWithTextFields
    • Parameters: texts (array of strings)
    • Description: Adds a section block with two columns layout to display provided texts. Supports mrkdwn.
  • addButton
    • Parameters: labelText (string), buttonText (string), value (string)
    • Description: Adds a section block to render a button. labelText is the section text, buttonText is the button label text and value is the button value.
  • addButtonElements
    • Parameters: buttonDetails (array of objects with keys - buttonText, value, confirmText)
    • Description: Adds an action block with multiple button elements. Each button element comes with a confirmation popup. buttonText is the button label text, value is the button value and confirmText is the confirmation pop up message. If you don't want to have a confirmation pop up, don't pass confirmText.
  • addDivider
    • Parameters: null
    • Description: Adds divider block.
  • addCustomHeader
    • Parameters: text (string)
    • Description: Adds a divider and a section block with the provided text. Supports mrkdwn.
  • sendUsingResponseUrl
  • sendMessageToChannel
    • Parameters: postMessageParams (object with keys - channel, text)
    • Description: Utilizes slack's Web API method chat.postMessage to send message to channel. channel is the channel id or your slack channel name. text is the message title text.

Example 1 - Sync Message / System Alert

When responding to a slash command or any other interaction, we have 2 choices - synchronous response and asynchronous response. If the generation of the message body is simple, then the response can be sent synchronously. Following is an example of the same.

const text = 'TITLE TEXT';

const slackMessageParams = {};
slackMessageParams.text = text;
slackMessageParams.channel = 'CHANNEL ID OR CHANNEL NAME HERE';

const message = new slackmin.interactiveElements.Message();
message.addDivider();
message.addSection(`*${text}*`);
message.addSection('Another section.');

message.sendMessageToChannel(slackMessageParams);

Output of above code is shown in the screenshot below.

Sync Message / System Alert

Example 2 - Async Message

In the following example, we are sending asynchronous response. While sending asynchronous response, we have to use the response url on which the message can be sent within 30 minutes of initial slack interaction.

const responseUrl = 'Response URL HERE';
const message = new slackmin.interactiveElements.Message();

message.addCustomHeader('Message *title* `text` here.');

const texts = [
  '2 Column Support.',
  '`mrkdwn` is supported too.',
  'Row 2, Column 1.',
  'Row 2, Column 2.'
 ];

message.addSectionWithTextFields(texts);
const actionButtons = [];

// as a convention, we have value as a JSON string with keys action and hiddenParams.
// action specifies the next method call to be performed for interactive endpoint i.e call to testModal1Open opens the test modal 1
// hiddenParams in value are internal params that need to be forwarded
const testButton1 = {
      buttonText: 'Test Button 1',
      confirmText: 'Do you want to really click the test button 1?',
      value:
        "{\"action\":\"testModal1Open\",\"hiddenParams\":{\"user_id\":\"123\"}}"
    };

actionButtons.push(testButton1);

const testButton2 = {
      buttonText: 'Test Button 2',
      confirmText: 'Do you want to really click the test button 2?',
      value:
        "{\"action\":\"testModal2Open\",\"hiddenParams\":{\"user_id\":\"123\"}}"
    };

actionButtons.push(testButton2);

message.addButtonElements(actionButtons);
message.sendUsingResponseUrl(responseUrl);

Output of above code is shown in the screenshot below. On clicking of the buttons a confirmation popup comes, as configured.

Message wrapper async example

Modal Wrapper

Slackmin Modal wrapper provides simple methods to create and format complex modal layouts thus simplifies the creation of block elements.

Methods

  • addSubmitAndCancel
    • Parameters: submitText (string), cancelText (string)
    • Description: Add submit and cancel button to the modal. submitText is the submit button label text. cancelText is the cancel button label text.
  • addPlainTextSection
    • Parameters: text (string)
    • Description: Adds a section block with the provided text.
  • addMarkdownTextContext
    • Parameters: text (string)
    • Description: Adds a context block with the provided text. Supports mrkdwn.
  • addDivider
    • Parameters: null
    • Description: Adds divider block.
  • addTextbox
    • Parameters: labelText (string), multiline (boolean), isOptional (boolean), initialText (string), placeHolderText (string)
    • Description: Adds a input block with an element type plain-text. labelText is the input block label text. multiline indicates whether the input will be a single line (false) or a larger textarea (true), defaults set to true. isOptional is a boolean that indicates whether the input element may be empty when a user submits the modal, defaults to false. initialText is the initial value, defaults to empty. placeHolderText is the placeholder or help text, defaults to 'Write Something'.
  • addCheckBoxes
    • Parameters: labelText (string), options (Array of objects, each object with keys text, value), initialOptions (Array of objects, each object with keys text, value)
    • Description: Adds a input block with an element type checkboxes. labelText is the input block label text. text is the individual checkbox option label text. value is a unique string that specifies the value of the checkbox option.
  • addRadioButtons
    • Parameters: labelText (string), optionsArray (Array of objects, each object with keys text, value), initialOption (object with keys text and value)
    • Description: Adds a input block with an element type radio buttons. labelText is the input block label text. text is the radio button label text. value is a unique string value that will be passed to your app when any option is chosen. You can set initial_option in the element for selecting radio button option by default.
  • addParamsMeta
  • addHiddenParamsMeta
    • Parameters: hiddenParamsMeta (object)
    • Description: To pass on internal parameters on modal submit. hiddenParamsMeta contains hidden parameters which has to pass for next modal action. hiddenParamsMeta is sent in private_metadata in modal submissions.
  • addAction
    • Parameters: actionName (string)
    • Description: You can provide the next action method/route to be executed on modal submit. As all the interactive component interactions are sent to a single request URL, this actionName helps in deciding what needs to be done. actionName is sent in private_metadata in modal submissions.
  • open
    • Parameters: triggerId (string)
    • Description: Opens modal using the trigger id, which expires in 3 seconds. triggerId is obtained from interaction payload.

Example

const triggerId = req.decodedParams.trigger_id; // Our middleware layer sets the trigger_id in req.decodedParams
const apiAppId = '<slack_app_id>'; // slack app id
const modal = new slackmin.interactiveElements.Modal(apiAppId, 'Give your vote');

// These are the parameter names for the subsequent textboxes.
const paramsMeta = ['name', 'member_id', 'designation', 'projects'];
modal.addParamsMeta(paramsMeta);

const hiddenParamsMeta = {param1: "value1"};
modal.addHiddenParamsMeta(hiddenParamsMeta);

modal.addAction('submitForm');

modal.addMarkdownTextContext('`Hello` *World!*');

modal.addPlainTextSection('Hello World!');

modal.addDivider();

modal.addTextbox('Name', false);
modal.addTextbox('Member Id', false);

modal.addRadioButtons(
 'Designation',
  [
    { text: 'Front End Developer', value: 'FE' },
    { text: 'Back End Developer', value: 'BE' },
    { text: 'Quality Assurance Engineer', value: 'QA' }
  ],
  { text: 'Front End Developer', value: 'FE' }
);

modal.addCheckBoxes('Projects', [
  { text: 'Fab', value: '1' },
  { text: 'Moxie', value: '2'},
  { text: 'Hem', value: '3' }
]);

modal.addSubmitAndCancel();

modal.open(triggerId);

Output of above code is shown in the screenshot below.

Modal wrapper example

Journey of Hidden Parameters

In this section, we will go through an example of our convention if handling hidden parameters. Hidden parameters have the contextual information needed for the CRUD operations like entity id, etc.

Following are the different parts of our example:

Part 1

A slash command which sends a message with interactive buttons in it (refer Message Wrapper documentation for creating of message UI). The hidden parameters (user_id in our example) must be present in the value of the button element as shown in the following snippet.

// hiddenParams in value are internal params that need to be forwarded
const testButton1 = {
      buttonText: 'Test Button 1',
      confirmText: 'Do you want to really click the test button 1?',
      value:
        "{\"action\":\"testModal1Open\",\"hiddenParams\":{\"user_id\":\"123\"}}"
    };

// Refer the snippet given in section "Example 1 - Async Message" for the complete idea.
actionButtons.push(testButton1);

Part 2

When the button in the message is clicked, a confirmation popup is shown. On confirmation, a POST API call comes from slack to the interactive request URL (which was set in "Slack app setup" section above). The block submission payload which comes from slack is converted to api parameters and assigned to req.decodedParams by our Interactive Component Middlewares.

Part 3

A modal UI is created and opened using our Modal wrapper. Hidden parameters are forwarded to the modal view using addHiddenParamsMeta method of the Modal wrapper (refer documentation above).

Part 4

On submission of the modal, the hidden parameters are obtained in the view submission payload, which is parsed and parameters are assigned to req.decodedParams by our Interactive Component Middlewares.

Contributors

You might also like...

The self-building, hot-reloading subgraph. The quickest way to start indexing your shit.

npx autographed The self-building, hot-reloading subgraph. The quickest way to start indexing your shit. 🚀 getting started Okay, so there's a lot tha

Aug 21, 2022

FormGear is a framework engine for dynamic form creation and complex form processing and validation for data collection.

FormGear is a framework engine for dynamic form creation and complex form processing and validation for data collection.

FormGear is a framework engine for dynamic form creation and complex form processing and validation for data collection. It is designed to work across

Dec 27, 2022

Deploy a multi-account cloud foundation to support highly-regulated workloads and complex compliance requirements.

Landing Zone Accelerator on AWS The Landing Zone Accelerator on AWS solution helps you quickly deploy a secure, resilient, scalable, and fully automat

Dec 29, 2022

A Javascript lib about complex

RealComplex.js 一个关于复数的Javascript库 A Javascript lib about complex How to use it? 使用教程 导入与实例化 import { Complex } from './Complex.js'; let x = new Comple

Feb 9, 2022

high performance、complex interaction table

功能描述 1、高性能、满足复杂交互的编辑表格 2、基于: antd4(https://ant.design/index-cn) ag-grid(https://www.ag-grid.com/) 3、基于原生ag-grid 的API进行封装 一、主要功能 将按下列顺序逐步迭代 1、通用编辑功能 🚧

Feb 15, 2022

🐻 Trying out the bear necessities for complex state management.

🐻 Zustand Demos My practice repository for the Zustand library--the bear necessities for complex state management. You can find some examples of how

Jul 2, 2022

A tiny foundation that providing nested state-based routing for complex web application.

StateMan stateman: A tiny foundation that provides nested state-based routing for complex web applications. stateman is highly inspired by ui-router;

Dec 20, 2022

This package support to build a complex application with domain driven design.

This package support to build a complex application with domain driven design.

The library implement Domain Driven Design for Nodejs base on Typescript. Description This package support to build a complex application with th doma

Nov 7, 2022

🛠 Solana Web3 Tools - A set of tools to improve the user experience on Web3 Solana Frontends.

🛠 Solana Web3 Tools - A set of tools to improve the user experience on Web3 Solana Frontends.

May 21, 2022
Comments
  • Readme, Middleware and Logging changes

    Readme, Middleware and Logging changes

    • Readme changed to include Business and Developer benefit sections.
    • Middleware for reading request raw body added in common middlewares.
    • Removed un-necessary logs.
    opened by kedarchandrayan 0
  • Readme, Middleware and Logging changes

    Readme, Middleware and Logging changes

    • Readme changed to include Business and Developer benefit sections.
    • Middleware for reading request raw body added in common middlewares.
    • Removed un-necessary logs.
    opened by kedarchandrayan 0
  • Readme updates (#9)

    Readme updates (#9)

    Slackmin v2.0.0

    • whitelistedChannels Map was changed to whitelistedChannelIds Array in the constructor of Slackmin.
    • Readme file was refactored with much more explanation and examples.
    opened by ajinkyac03 0
Releases(v3.0)
  • v3.0(Aug 25, 2022)

    • Multi-workspace support added. Now the slack apps can be from different slack workspaces / domains.
    • Validators functions exposed for easy integration with non Express frameworks like Koa, Fastify, etc.
    • Whitelisted channels validation made optional. Pass whiteListedChannels as an empty array when initializing Slackmin to skip this validation.
    • Whitelisted users validation made optional. Pass whitelistedUsers as an empty array when initializing Slackmin to skip this validation.
    Source code(tar.gz)
    Source code(zip)
  • v2.0(Jun 6, 2022)

    Slackmin v2.0.0

    • whitelistedChannels Map was changed to whitelistedChannelIds Array in the constructor of Slackmin.
    • Readme file was refactored with much more explanation and examples.
    Source code(tar.gz)
    Source code(zip)
  • v1.0(May 26, 2022)

    Slackmin v1.0.0

    • This is the very first release of this package.
    • Middleware functions needed for implementation of slash commands and interactive endpoints are exposed.
    • Message and Modal helper wrappers exposed.
    Source code(tar.gz)
    Source code(zip)
Owner
PLG Works
We design, build and deliver highly scalable and secure web and mobile applications using React, Next.js, React Native, Web3.js, Node.js, Ruby On Rails.
PLG Works
slack-friends Make it easy to send to Slack from your application

slack-friends Make it easy to send to Slack from your application Installation ?? npm install slack-friends How to get bot token https://api.slack.com

Taein Kang 9 Aug 23, 2022
An example implementation of the slack-gpt starter which ingests confluence pages to create a helpful slack bot

Slack-GPT (HR bot example implementation) Table of Contents Introduction Prerequisites Creating and installing the application Configuration Starting

Martin Hunt 17 Jul 31, 2023
This is the FARM Stack course, where you are going to learn how to build an application from scratch using FASTAPI, React and mongoDB

FARM-Stack-Course This is the FARM Stack course, where you are going to learn how to build an application from scratch using FASTAPI, React and mongoD

Bek Brace 121 Jan 2, 2023
For this workshop, we're going to learn more about cloud computing by exploring how to use Pulumi to build, configure, and deploy a real-life, modern application using Docker

For this workshop, we're going to learn more about cloud computing by exploring how to use Pulumi to build, configure, and deploy a real-life, modern application using Docker. We will create a frontend, a backend, and a database to deploy the Pulumipus Boba Tea Shop. Along the way, we'll learn more about how Pulumi works.

Kat Cosgrove 9 Dec 29, 2022
A project for experimenting with Server Sent Events (SSE), a way of communication going from server to client.

A project for experimenting with Server Sent Events (SSE), a way of communication going from server to client.

Italo Menezes 4 May 16, 2022
Nepkit Connector – Build Dashboards & Admin Tools in minutes

Nepkit Connector Use Nepkit Connector to connect Nepkit Dashboard Builder to the database on your server or local machine. Supported databases: Postgr

Nepkit 3 Jun 3, 2022
💻 A simple Create Next App template to start your projects with Next.js, TypeScript, ESLint, Prettier and other tools.

⚡ Next Typescript Template ⚡ A simple Create Next App template to start your projects with Next.js, TypeScript, ESLint, Prettier and other tools. Quic

João Gabriel 13 Nov 23, 2022
Unfurl links into rich cards, as seen in places like Slack and Twitter

eleventy-plugin-unfurl Turn URLs into rich cards. Show a preview image, page title, description and other meta information all inside a neatly present

David Darnes 38 Dec 16, 2022
Small library to create classes without using class syntax.

Clazz.js Small library to create classes without using class syntax. Compatibility For internet explorer 11 or higher. Example <script src="Clazz.js">

Emanuel R. Vásquez 1 Dec 25, 2021
Starting template for building a Remix site with CloudFlare Workers (ES Modules Syntax)

Starting template for building a Remix site with CloudFlare Workers (ES Modules Syntax)

null 12 May 20, 2022