Skip to content

The NestJS module for building the listeners and handlers of Slack events and interactivities.

License

Notifications You must be signed in to change notification settings

hanchchch/nestjs-slack-listener

Repository files navigation

NestJS Slack Listeners and Handlers

πŸ₯° Any kinds of contributions are welcome! πŸ₯°


Features

  • Class decorator @SlackEventListener
    • Decorate the class to use it as a Slack event listener, just like decorating HTTP listeners with @Controller.
  • Method decorator @SlackEventHandler
    • Decorate the method to use it as a Slack event handler, just like decorating HTTP handlers with @Get, @Post, etc.
    • You can filter events by event type, or your custom filtering function.
  • Slack Web API Client
    • Inject the Slack Web API client to your service class with @InjectSlackClient decorator.
    • You can use the client to send messages to Slack, or whatever you want to do.

Installation

yarn add nestjs-slack-listener

Usage

Please refer to the example for more details.

Settings

Import SlackModule

Import the module at your app module.

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    SlackModule.forRootAsync({
      useFactory: async (config: ConfigService<EnvVars>) => ({
        botToken: config.get('SLACK_BOT_TOKEN'),
      }),
      inject: [ConfigService],
    }),
  ],
  controllers: [AppController],
  providers: [],
})
export class AppModule {}

Event and Interactivity Subscription

You need to set event and interactivity subscriptions URL of your slack app so that the app can receive events and interactivity from slack.

Decorators

Slack Event

Decorate the controller to use it as slack event listener.

@Controller('on-boarding')
@SlackEventListener()
export class OnBoardingController {}

Decorate the method of the controller to use it as slack event handler.

@Controller('on-boarding')
@SlackEventListener()
export class OnBoardingController {
  constructor(private readonly onboardingService: OnBoardingService) {}

  @SlackEventHandler('team_join')
  async onTeamJoin({ event: { user } }: IncomingSlackEvent<TeamJoinEvent>) {
    this.onboardingService.startOnBoarding({ user });
  }
}

Slack Interactivity

You can also decorate the listeners and handlers for slack-interactivity.

@Controller('on-boarding')
@SlackEventListener()
@SlackInteractivityListener()
export class OnBoardingController {
  constructor(private readonly onboardingService: OnBoardingService) {}

  @SlackEventHandler('team_join')
  async onTeamJoin({ event: { user } }: IncomingSlackEvent<TeamJoinEvent>) {
    this.onboardingService.startOnBoarding({ user });
  }

  @SlackInteractivityHandler(ACTION_ID.COMPLETE_QUEST)
  async completeOnBoarding({
    user: { id: userSlackId },
    actions: [{ value }],
  }: IncomingSlackInteractivity) {
    return this.onboardingService.completeOnBoarding({ userSlackId, value });
  }
}

Filters

Filter the events with function argument filter and string argument eventType of the decorator SlackEventHandler.

@Controller('memo')
@SlackEventListener()
export class MemoController {
  constructor(private readonly memoService: MemoService) {}

  @SlackEventHandler({
    eventType: 'message',
    filter: ({ event }) => event.text.includes('write this down!'),
  })
  async takeMemo({ event: { message } }: IncomingSlackEvent<MessageEvent>) {
    this.memoService.takeMemo({ message });
  }
}

You can also filter the events at the decorator SlackEventListener

@Controller('memo')
@SlackEventListener(({ event }) => event.channel === MEMO_CHANNEL)
export class OnBoardingController {
  constructor(private readonly memoService: MemoService) {}

  @SlackEventHandler({
    eventType: 'message',
    filter: ({ event }) => event.text.includes('write this down!'),
  })
  async onTeamJoin({ event: { user } }: IncomingSlackEvent<MessageEvent>) {
    this.memoService.takeMemo({ message });
  }
}

Slack Client

Use InjectSlackClient to use the slack web api client.

@Injectable()
export class OnBoardingService {
  constructor(
    private readonly userRepository: UserRepository,
    @InjectSlackClient()
    private readonly slack: SlackClient,
  ) {}
  ...
}

The injected SlackClient is identical to the official Slack Web API Client

await this.slack.chat.postMessage({
  channel: user.id,
  text: 'Hi there! πŸ‘‹πŸ»',
  blocks: [
    {
      type: 'header',
      text: {
        type: 'plain_text',
        text: 'Hi there! πŸ‘‹πŸ»',
      },
    },
    {
      type: 'section',
      text: {
        type: 'mrkdwn',
        text: `Hello! Nice to meet you, ${user.name}! I'm *hanch*, a slack bot that helps you with onboarding process.`,
      },
    },
  ],
});

About

The NestJS module for building the listeners and handlers of Slack events and interactivities.

Resources

License

Stars

Watchers

Forks

Packages

No packages published