Skip to content

Commit

Permalink
feat: slack client
Browse files Browse the repository at this point in the history
  • Loading branch information
hanchchch committed Oct 15, 2022
1 parent 3880cfa commit 1dd55e4
Show file tree
Hide file tree
Showing 25 changed files with 211 additions and 65 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@
</a>
</div>

<p align="center">🥰 Any kinds of contributions are welcome! 🥰</p>

# Installation

```
yarn add nestjs-slack-listener
```

# Usage

## Settings
Expand All @@ -24,7 +32,7 @@ Import the module at your app module.
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
SlackHandlerModule.forRootAsync({
SlackModule.forRootAsync({
useFactory: async (config: ConfigService<EnvVars>) => ({
botToken: config.get('SLACK_BOT_TOKEN'),
}),
Expand Down
23 changes: 18 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nestjs-slack-listener",
"version": "1.0.2",
"version": "1.0.4",
"description": "NestJS Slack listeners and handlers",
"author": "Chung Hwan Han <[email protected]>",
"license": "MIT",
Expand Down Expand Up @@ -74,25 +74,38 @@
"pre-commit": "^1.2.2",
"prettier": "2.6.1",
"reflect-metadata": "^0.1.13",
"supertest": "6.2.2",
"supertest": "^6.3.0",
"ts-jest": "27.1.4",
"ts-node": "10.7.0",
"tsc-watch": "5.0.3",
"tsconfig-paths": "3.14.1",
"typescript": "4.6.3"
},
"jest": {
"moduleDirectories": [
"node_modules",
"src"
],
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".spec.ts$",
"roots": [
"src"
],
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
"testEnvironment": "node",
"moduleNameMapper": {
"gaxios": "gaxios",
"src/(.*)": "<rootDir>/src/$1"
}
}
}
3 changes: 0 additions & 3 deletions src/handler/index.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './handler';
export * from './slack';
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const SLACK_CONFIG_OPTIONS = 'SLACK_CONFIG_OPTIONS';
export const SLACK_INTERACTIVITY_HANDLER = 'SLACK_INTERACTIVITY_HANDLER';
export const SLACK_EVENT_HANDLER = 'SLACK_EVENT_HANDLER';
export const SLACK_CLIENT = 'SLACK_CLIENT';
4 changes: 4 additions & 0 deletions src/slack/decorators/client.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { Inject } from '@nestjs/common';
import { SLACK_CLIENT } from '../constant/symbol';

export const InjectSlackClient = () => Inject(SLACK_CLIENT);
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './command.decorator';
export * from './handler.decorator';
export * from './client.decorator';
File renamed without changes.
4 changes: 4 additions & 0 deletions src/slack/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './decorators';
export * from './interfaces';
export * from './types/client';
export * from './slack.module';
File renamed without changes.
File renamed without changes.
File renamed without changes.
13 changes: 13 additions & 0 deletions src/slack/slack-client.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Inject, Injectable } from '@nestjs/common';
import { WebClient } from '@slack/web-api';
import { SLACK_CONFIG_OPTIONS } from './constant/symbol';
import { SlackModuleOptions } from './interfaces';

@Injectable()
export class SlackClientService {
public readonly client: WebClient;

constructor(@Inject(SLACK_CONFIG_OPTIONS) options: SlackModuleOptions) {
this.client = new WebClient(options.botToken);
}
}
File renamed without changes.
File renamed without changes.
27 changes: 20 additions & 7 deletions src/handler/slack-handler.module.ts → src/slack/slack.module.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,44 @@
import { DynamicModule, Module, OnModuleInit, Provider } from '@nestjs/common';
import { MetadataScanner } from '@nestjs/core';
import { SLACK_CONFIG_OPTIONS } from './constant/symbol';
import { SLACK_CLIENT, SLACK_CONFIG_OPTIONS } from './constant/symbol';
import { SlackHandlerExplorer } from './handler.explorer';
import { SlackModuleAsyncOptions, SlackModuleOptions } from './interfaces';
import { SlackClientService } from './slack-client.service';
import { SlackEventsController } from './slack-handler.controller';
import { SlackHandler } from './slack-handler.service';

@Module({
providers: [MetadataScanner, SlackHandlerExplorer],
})
export class SlackHandlerModule implements OnModuleInit {
export class SlackModule implements OnModuleInit {
static forRoot(options: SlackModuleOptions): DynamicModule {
const slackServiceProvider = this.createSlackServiceProvider();
const slackClientProvider = this.createSlackClientProvider();
return {
module: SlackHandlerModule,
module: SlackModule,
controllers: [SlackEventsController],
providers: [
{
provide: SLACK_CONFIG_OPTIONS,
useValue: options,
},
slackServiceProvider,
slackClientProvider,
],
exports: [SlackHandler],
exports: [SlackHandler, SLACK_CLIENT],
};
}

static forRootAsync(options: SlackModuleAsyncOptions): DynamicModule {
const slackServiceProvider = this.createSlackServiceProvider();
const slackClientProvider = this.createSlackClientProvider();
const asyncProviders = this.createAsyncProviders(options);
return {
module: SlackHandlerModule,
module: SlackModule,
controllers: [SlackEventsController],
imports: options.imports || [],
providers: [...asyncProviders, slackServiceProvider],
exports: [SlackHandler],
providers: [...asyncProviders, slackServiceProvider, slackClientProvider],
exports: [SlackHandler, SLACK_CLIENT],
};
}

Expand All @@ -46,6 +50,15 @@ export class SlackHandlerModule implements OnModuleInit {
};
}

private static createSlackClientProvider(): Provider {
return {
provide: SLACK_CLIENT,
useFactory: (options: SlackModuleOptions) =>
new SlackClientService(options).client,
inject: [SLACK_CONFIG_OPTIONS],
};
}

private static createAsyncProviders(
options: SlackModuleAsyncOptions,
): Provider[] {
Expand Down
3 changes: 3 additions & 0 deletions src/slack/types/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { WebClient } from '@slack/web-api';

export type SlackClient = WebClient;
File renamed without changes.
12 changes: 0 additions & 12 deletions src/test/slack-handler.module.spec.ts

This file was deleted.

111 changes: 111 additions & 0 deletions src/test/slack.module.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { Controller, Get, Injectable, Module } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { SlackClient, SlackEventListener, SlackModule } from 'src/slack';
import { InjectSlackClient } from 'src/slack/decorators';
import * as request from 'supertest';

describe('Slack Module Initialization', () => {
describe('forRoot', () => {
it('should compile only with botToken option', async () => {
@Controller()
@SlackEventListener()
class TestController {
@Get()
get() {
return '';
}
}
@Module({
imports: [SlackModule.forRoot({ botToken: 'test' })],
controllers: [TestController],
})
class TestModule {}

const app = await NestFactory.create(TestModule);
const server = app.getHttpServer();

await app.init();
await request(server).get('/').expect(200);
await app.close();
});
it('should compile including slack client', async () => {
@Injectable()
class TestService {
constructor(@InjectSlackClient() slack: SlackClient) {
expect(slack).toBeDefined();
}
getBotToken() {
return 'test';
}
}
@Module({
imports: [
SlackModule.forRoot({
botToken: 'test',
}),
],
providers: [TestService],
})
class TestModule {}

const app = await NestFactory.create(TestModule);

await app.init();
await app.close();
});
});
describe('forRootAsync', () => {
it('should compile only with botToken option', async () => {
@Controller()
@SlackEventListener()
class TestController {
@Get()
get() {
return '';
}
}
@Module({
imports: [
SlackModule.forRootAsync({
useFactory: () => ({ botToken: 'test' }),
}),
],
controllers: [TestController],
})
class TestModule {}

const app = await NestFactory.create(TestModule);
const server = app.getHttpServer();

await app.init();
await request(server).get('/').expect(200);
await app.close();
});

it('should compile including slack client', async () => {
@Injectable()
class TestService {
constructor(@InjectSlackClient() slack: SlackClient) {
expect(slack).toBeDefined();
}
getBotToken() {
return 'test';
}
}
@Module({
imports: [
SlackModule.forRootAsync({
useFactory: () => ({ botToken: 'test' }),
}),
],
providers: [TestService],
})
class TestModule {}

const app = await NestFactory.create(TestModule);

await app.init();
await app.close();
});
});
});
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@
"noLib": false
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules"]
"exclude": ["node_modules", "example"]
}
Loading

0 comments on commit 1dd55e4

Please sign in to comment.