├── .gitignore
├── app
├── .eslintrc.js
├── .gitignore
├── .prettierrc
├── README.md
├── docker-compose.yml
├── nest-cli.json
├── package.json
├── src
│ ├── app.controller.spec.ts
│ ├── app.controller.ts
│ ├── app.module.ts
│ ├── app.service.ts
│ ├── main.ts
│ ├── notification
│ │ ├── dtos
│ │ │ ├── email.dto.ts
│ │ │ └── phone.dto.ts
│ │ ├── notification.controller.spec.ts
│ │ ├── notification.controller.ts
│ │ └── notification.module.ts
│ └── users
│ │ ├── dtos
│ │ └── user.dto.ts
│ │ ├── interfaces
│ │ └── user.interface.ts
│ │ ├── users.controller.spec.ts
│ │ ├── users.controller.ts
│ │ └── users.module.ts
├── test
│ ├── app.e2e-spec.ts
│ └── jest-e2e.json
├── tsconfig.build.json
└── tsconfig.json
├── notification-engine
├── .env
├── .eslintrc.js
├── .gitignore
├── .prettierrc
├── README.md
├── nest-cli.json
├── package.json
├── src
│ ├── app.controller.spec.ts
│ ├── app.controller.ts
│ ├── app.module.ts
│ ├── app.service.ts
│ ├── dtos
│ │ └── notification.dto.ts
│ ├── interfaces
│ │ ├── notification.interface.ts
│ │ └── notification.schema.ts
│ └── main.ts
├── test
│ ├── app.e2e-spec.ts
│ └── jest-e2e.json
├── tsconfig.build.json
└── tsconfig.json
└── user-engine
├── .eslintrc.js
├── .gitignore
├── .prettierrc
├── README.md
├── nest-cli.json
├── package.json
├── src
├── app.controller.spec.ts
├── app.controller.ts
├── app.module.ts
├── app.service.ts
├── database
│ └── database.module.ts
├── interfaces
│ ├── user.entity.ts
│ └── user.interface.ts
└── main.ts
├── test
├── app.e2e-spec.ts
└── jest-e2e.json
├── tsconfig.build.json
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # compiled output
2 | /dist
3 | /node_modules
4 |
5 | # Logs
6 | logs
7 | *.log
8 | npm-debug.log*
9 | yarn-debug.log*
10 | yarn-error.log*
11 | lerna-debug.log*
12 |
13 | # OS
14 | .DS_Store
15 |
16 | # Tests
17 | /coverage
18 | /.nyc_output
19 |
20 | # IDEs and editors
21 | /.idea
22 | .project
23 | .classpath
24 | .c9/
25 | *.launch
26 | .settings/
27 | *.sublime-workspace
28 |
29 | # IDE - VSCode
30 | .vscode/*
31 | !.vscode/settings.json
32 | !.vscode/tasks.json
33 | !.vscode/launch.json
34 | !.vscode/extensions.json
--------------------------------------------------------------------------------
/app/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: '@typescript-eslint/parser',
3 | parserOptions: {
4 | project: 'tsconfig.json',
5 | sourceType: 'module',
6 | },
7 | plugins: ['@typescript-eslint/eslint-plugin'],
8 | extends: [
9 | 'plugin:@typescript-eslint/eslint-recommended',
10 | 'plugin:@typescript-eslint/recommended',
11 | 'prettier',
12 | 'prettier/@typescript-eslint',
13 | ],
14 | root: true,
15 | env: {
16 | node: true,
17 | jest: true,
18 | },
19 | rules: {
20 | '@typescript-eslint/interface-name-prefix': 'off',
21 | '@typescript-eslint/explicit-function-return-type': 'off',
22 | '@typescript-eslint/explicit-module-boundary-types': 'off',
23 | '@typescript-eslint/no-explicit-any': 'off',
24 | },
25 | };
26 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | # compiled output
2 | /dist
3 | /node_modules
4 |
5 | # Logs
6 | logs
7 | *.log
8 | npm-debug.log*
9 | yarn-debug.log*
10 | yarn-error.log*
11 | lerna-debug.log*
12 |
13 | # OS
14 | .DS_Store
15 |
16 | # Tests
17 | /coverage
18 | /.nyc_output
19 |
20 | # IDEs and editors
21 | /.idea
22 | .project
23 | .classpath
24 | .c9/
25 | *.launch
26 | .settings/
27 | *.sublime-workspace
28 |
29 | # IDE - VSCode
30 | .vscode/*
31 | !.vscode/settings.json
32 | !.vscode/tasks.json
33 | !.vscode/launch.json
34 | !.vscode/extensions.json
--------------------------------------------------------------------------------
/app/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all"
4 | }
--------------------------------------------------------------------------------
/app/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | [travis-image]: https://api.travis-ci.org/nestjs/nest.svg?branch=master
6 | [travis-url]: https://travis-ci.org/nestjs/nest
7 | [linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux
8 | [linux-url]: https://travis-ci.org/nestjs/nest
9 |
10 | A progressive Node.js framework for building efficient and scalable server-side applications, heavily inspired by Angular.
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
26 |
27 | ## Description
28 |
29 | [Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
30 |
31 | ## Installation
32 |
33 | ```bash
34 | $ npm install
35 | ```
36 |
37 | ## Running the app
38 |
39 | ```bash
40 | # development
41 | $ npm run start
42 |
43 | # watch mode
44 | $ npm run start:dev
45 |
46 | # production mode
47 | $ npm run start:prod
48 | ```
49 |
50 | ## Test
51 |
52 | ```bash
53 | # unit tests
54 | $ npm run test
55 |
56 | # e2e tests
57 | $ npm run test:e2e
58 |
59 | # test coverage
60 | $ npm run test:cov
61 | ```
62 |
63 | ## Support
64 |
65 | Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
66 |
67 | ## Stay in touch
68 |
69 | - Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
70 | - Website - [https://nestjs.com](https://nestjs.com/)
71 | - Twitter - [@nestframework](https://twitter.com/nestframework)
72 |
73 | ## License
74 |
75 | Nest is [MIT licensed](LICENSE).
76 |
--------------------------------------------------------------------------------
/app/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 | services:
3 | zookeeper:
4 | image: wurstmeister/zookeeper:latest
5 | ports:
6 | - "2181:2181"
7 | kafka:
8 | image: wurstmeister/kafka:2.11-1.1.0
9 | ports:
10 | - "9092:9092"
11 | environment:
12 | KAFKA_ADVERTISED_HOST_NAME: localhost
13 | KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
14 | KAFKA_CREATE_TOPICS: "create-user:1:1, find-all-user:1:1"
15 | volumes:
16 | - /var/run/docker.sock:/var/run/docker.sock
--------------------------------------------------------------------------------
/app/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "collection": "@nestjs/schematics",
3 | "sourceRoot": "src"
4 | }
5 |
--------------------------------------------------------------------------------
/app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "version": "0.0.1",
4 | "description": "",
5 | "author": "",
6 | "private": true,
7 | "license": "UNLICENSED",
8 | "scripts": {
9 | "prebuild": "rimraf dist",
10 | "build": "nest build",
11 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
12 | "start": "nest start",
13 | "start:dev": "nest start --watch",
14 | "start:debug": "nest start --debug --watch",
15 | "start:prod": "node dist/main",
16 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
17 | "test": "jest",
18 | "test:watch": "jest --watch",
19 | "test:cov": "jest --coverage",
20 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
21 | "test:e2e": "jest --config ./test/jest-e2e.json"
22 | },
23 | "dependencies": {
24 | "@nestjs/common": "^7.0.0",
25 | "@nestjs/core": "^7.0.0",
26 | "@nestjs/microservices": "^7.4.4",
27 | "@nestjs/platform-express": "^7.0.0",
28 | "@nestjs/swagger": "^4.6.1",
29 | "kafkajs": "^1.14.0",
30 | "reflect-metadata": "^0.1.13",
31 | "rimraf": "^3.0.2",
32 | "rxjs": "^6.5.4",
33 | "sqlite3": "^5.0.0",
34 | "swagger-ui-express": "^4.1.4"
35 | },
36 | "devDependencies": {
37 | "@nestjs/cli": "^7.0.0",
38 | "@nestjs/schematics": "^7.0.0",
39 | "@nestjs/testing": "^7.0.0",
40 | "@types/express": "^4.17.3",
41 | "@types/jest": "26.0.10",
42 | "@types/node": "^13.9.1",
43 | "@types/supertest": "^2.0.8",
44 | "@typescript-eslint/eslint-plugin": "3.9.1",
45 | "@typescript-eslint/parser": "3.9.1",
46 | "eslint": "7.7.0",
47 | "eslint-config-prettier": "^6.10.0",
48 | "eslint-plugin-import": "^2.20.1",
49 | "jest": "26.4.2",
50 | "prettier": "^1.19.1",
51 | "supertest": "^4.0.2",
52 | "ts-jest": "26.2.0",
53 | "ts-loader": "^6.2.1",
54 | "ts-node": "9.0.0",
55 | "tsconfig-paths": "^3.9.0",
56 | "typescript": "^3.7.4"
57 | },
58 | "jest": {
59 | "moduleFileExtensions": [
60 | "js",
61 | "json",
62 | "ts"
63 | ],
64 | "rootDir": "src",
65 | "testRegex": ".spec.ts$",
66 | "transform": {
67 | "^.+\\.(t|j)s$": "ts-jest"
68 | },
69 | "coverageDirectory": "../coverage",
70 | "testEnvironment": "node"
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/app.controller.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { AppController } from './app.controller';
3 | import { AppService } from './app.service';
4 |
5 | describe('AppController', () => {
6 | let appController: AppController;
7 |
8 | beforeEach(async () => {
9 | const app: TestingModule = await Test.createTestingModule({
10 | controllers: [AppController],
11 | providers: [AppService],
12 | }).compile();
13 |
14 | appController = app.get(AppController);
15 | });
16 |
17 | describe('root', () => {
18 | it('should return "Hello World!"', () => {
19 | expect(appController.getHello()).toBe('Hello World!');
20 | });
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/app/src/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller, Get } from '@nestjs/common';
2 | import { AppService } from './app.service';
3 |
4 | @Controller()
5 | export class AppController {
6 | constructor(private readonly appService: AppService) {}
7 |
8 | @Get()
9 | getHello(): string {
10 | return this.appService.getHello();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/app.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { AppController } from './app.controller';
3 | import { AppService } from './app.service';
4 | import { UsersModule } from './users/users.module';
5 | import { NotificationModule } from './notification/notification.module';
6 |
7 | @Module({
8 | imports: [
9 | UsersModule,
10 | NotificationModule,
11 | ],
12 | controllers: [AppController],
13 | providers: [AppService],
14 | })
15 | export class AppModule {}
16 |
--------------------------------------------------------------------------------
/app/src/app.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 |
3 | @Injectable()
4 | export class AppService {
5 | getHello(): string {
6 | return 'Hello World!';
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main.ts:
--------------------------------------------------------------------------------
1 | import { NestFactory } from '@nestjs/core';
2 | import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
3 | import { AppModule } from './app.module';
4 |
5 | async function bootstrap() {
6 | const app = await NestFactory.create(AppModule);
7 |
8 | const options = new DocumentBuilder()
9 | .setTitle('App example')
10 | .setDescription('The app API description')
11 | .setVersion('1.0')
12 | .addTag('app')
13 | .build();
14 | const document = SwaggerModule.createDocument(app, options);
15 | SwaggerModule.setup('api', app, document);
16 |
17 | await app.listen(8000);
18 | }
19 | bootstrap();
20 |
--------------------------------------------------------------------------------
/app/src/notification/dtos/email.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from "@nestjs/swagger";
2 |
3 | export class EmailDto {
4 | @ApiProperty()
5 | id: number;
6 |
7 | @ApiProperty()
8 | name: string;
9 |
10 | @ApiProperty()
11 | phone: string;
12 |
13 | }
--------------------------------------------------------------------------------
/app/src/notification/dtos/phone.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from "@nestjs/swagger";
2 |
3 | export class PhoneDto {
4 | @ApiProperty()
5 | id: number;
6 |
7 | @ApiProperty()
8 | name: string;
9 |
10 | @ApiProperty()
11 | phone: string;
12 |
13 | }
--------------------------------------------------------------------------------
/app/src/notification/notification.controller.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { NotificationController } from './notification.controller';
3 |
4 | describe('NotificationController', () => {
5 | let controller: NotificationController;
6 |
7 | beforeEach(async () => {
8 | const module: TestingModule = await Test.createTestingModule({
9 | controllers: [NotificationController],
10 | }).compile();
11 |
12 | controller = module.get(NotificationController);
13 | });
14 |
15 | it('should be defined', () => {
16 | expect(controller).toBeDefined();
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/app/src/notification/notification.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller, Post, Body } from '@nestjs/common';
2 | import { Client, ClientKafka, Transport } from '@nestjs/microservices';
3 | import { EmailDto } from './dtos/email.dto';
4 | import { PhoneDto } from './dtos/phone.dto';
5 |
6 | @Controller('notifications')
7 | export class NotificationController {
8 | @Client({
9 | transport: Transport.KAFKA,
10 | options: {
11 | client: {
12 | clientId: 'notification',
13 | brokers: ['localhost:9092'],
14 | },
15 | consumer: {
16 | groupId: 'notification-consumer',
17 | allowAutoTopicCreation: true
18 | }
19 | }
20 | })
21 |
22 | private client: ClientKafka;
23 |
24 | @Post('email')
25 | sendEmail(@Body() data: EmailDto) {
26 | return this.client.emit('notification-email', data);
27 | }
28 |
29 | @Post('sms')
30 | sendPhone(@Body() data: PhoneDto) {
31 | return this.client.emit('notification-sms', data);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/notification/notification.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { NotificationController } from './notification.controller';
3 |
4 | @Module({
5 | controllers: [NotificationController]
6 | })
7 | export class NotificationModule {}
8 |
--------------------------------------------------------------------------------
/app/src/users/dtos/user.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from "@nestjs/swagger";
2 |
3 | export class UserDto {
4 |
5 | @ApiProperty()
6 | name: string;
7 |
8 | @ApiProperty()
9 | email: string;
10 |
11 | @ApiProperty()
12 | phone: string;
13 |
14 | @ApiProperty()
15 | password: string;
16 | }
--------------------------------------------------------------------------------
/app/src/users/interfaces/user.interface.ts:
--------------------------------------------------------------------------------
1 | export interface User {
2 | id: number;
3 | name: string;
4 | email: string;
5 | phone: string;
6 | password: string;
7 | status?: 'ACTIVATE' | 'INACTIVATE';
8 | }
--------------------------------------------------------------------------------
/app/src/users/users.controller.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { UsersController } from './users.controller';
3 |
4 | describe('UsersController', () => {
5 | let controller: UsersController;
6 |
7 | beforeEach(async () => {
8 | const module: TestingModule = await Test.createTestingModule({
9 | controllers: [UsersController],
10 | }).compile();
11 |
12 | controller = module.get(UsersController);
13 | });
14 |
15 | it('should be defined', () => {
16 | expect(controller).toBeDefined();
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/app/src/users/users.controller.ts:
--------------------------------------------------------------------------------
1 | import { Body, Controller, Delete, Get, OnModuleInit, Param, Patch, Post, Put } from '@nestjs/common';
2 | import { Client, ClientKafka, Transport } from '@nestjs/microservices';
3 | import { ApiBody } from '@nestjs/swagger';
4 | import { Observable } from 'rxjs';
5 | import { UserDto } from './dtos/user.dto';
6 | import { User } from './interfaces/user.interface';
7 |
8 | @Controller('users')
9 | export class UsersController implements OnModuleInit {
10 | @Client({
11 | transport: Transport.KAFKA,
12 | options: {
13 | client: {
14 | clientId: 'user',
15 | brokers: ['localhost:9092'],
16 | },
17 | consumer: {
18 | groupId: 'user-consumer',
19 | allowAutoTopicCreation: true
20 | }
21 | }
22 | })
23 |
24 | private client: ClientKafka;
25 |
26 | async onModuleInit() {
27 | const requestPatters = ['find-all-user', 'find-user', 'create-user'];
28 |
29 | requestPatters.forEach(async pattern => {
30 | this.client.subscribeToResponseOf(pattern);
31 | await this.client.connect();
32 | });
33 | }
34 |
35 | @Get()
36 | index(): Observable {
37 | return this.client.send('find-all-user', {});
38 | }
39 |
40 | @Get(':id')
41 | find(@Param('id') id: number): Observable {
42 | return this.client.send('find-user', {id})
43 | }
44 |
45 | @Post()
46 | @ApiBody({ type: UserDto })
47 | create(@Body() user: UserDto): Observable {
48 | return this.client.send('create-user', user);
49 | }
50 |
51 | @Put(':id')
52 | @ApiBody({ type: UserDto })
53 | update(@Param('id') id: number, @Body() { name, email, phone, password }: UserDto) {
54 | const payload = {
55 | id,
56 | name,
57 | email,
58 | phone,
59 | password,
60 | };
61 |
62 | return this.client.emit('update-user', payload);
63 | }
64 |
65 | @Delete(':id')
66 | remove(@Param('id') id: number) {
67 | return this.client.emit('delete-user', {id})
68 | }
69 |
70 | @Patch(':id/activate')
71 | activate(@Param('id') id: number) {
72 | return this.client.emit('activate-user', {id});
73 | }
74 |
75 | @Patch(':id/inactivate')
76 | inactivate(@Param('id') id: number) {
77 | return this.client.emit('inactivate-user', {id});
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/users/users.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { UsersController } from './users.controller';
3 |
4 | @Module({
5 | imports: [],
6 | controllers: [UsersController],
7 | providers: []
8 | })
9 | export class UsersModule {}
10 |
--------------------------------------------------------------------------------
/app/test/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { INestApplication } from '@nestjs/common';
3 | import * as request from 'supertest';
4 | import { AppModule } from './../src/app.module';
5 |
6 | describe('AppController (e2e)', () => {
7 | let app: INestApplication;
8 |
9 | beforeEach(async () => {
10 | const moduleFixture: TestingModule = await Test.createTestingModule({
11 | imports: [AppModule],
12 | }).compile();
13 |
14 | app = moduleFixture.createNestApplication();
15 | await app.init();
16 | });
17 |
18 | it('/ (GET)', () => {
19 | return request(app.getHttpServer())
20 | .get('/')
21 | .expect(200)
22 | .expect('Hello World!');
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/app/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": ".",
4 | "testEnvironment": "node",
5 | "testRegex": ".e2e-spec.ts$",
6 | "transform": {
7 | "^.+\\.(t|j)s$": "ts-jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/app/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "declaration": true,
5 | "removeComments": true,
6 | "emitDecoratorMetadata": true,
7 | "experimentalDecorators": true,
8 | "allowSyntheticDefaultImports": true,
9 | "target": "es2017",
10 | "sourceMap": true,
11 | "outDir": "./dist",
12 | "baseUrl": "./",
13 | "incremental": true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/notification-engine/.env:
--------------------------------------------------------------------------------
1 | SEND_GRID_ACCESS_KEY=
2 | FROM_EMAIL=
3 | KEYWORD=
4 | ZENVIA_TOKEN=
5 |
--------------------------------------------------------------------------------
/notification-engine/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: '@typescript-eslint/parser',
3 | parserOptions: {
4 | project: 'tsconfig.json',
5 | sourceType: 'module',
6 | },
7 | plugins: ['@typescript-eslint/eslint-plugin'],
8 | extends: [
9 | 'plugin:@typescript-eslint/eslint-recommended',
10 | 'plugin:@typescript-eslint/recommended',
11 | 'prettier',
12 | 'prettier/@typescript-eslint',
13 | ],
14 | root: true,
15 | env: {
16 | node: true,
17 | jest: true,
18 | },
19 | rules: {
20 | '@typescript-eslint/interface-name-prefix': 'off',
21 | '@typescript-eslint/explicit-function-return-type': 'off',
22 | '@typescript-eslint/explicit-module-boundary-types': 'off',
23 | '@typescript-eslint/no-explicit-any': 'off',
24 | },
25 | };
26 |
--------------------------------------------------------------------------------
/notification-engine/.gitignore:
--------------------------------------------------------------------------------
1 | # compiled output
2 | /dist
3 | /node_modules
4 |
5 | # Logs
6 | logs
7 | *.log
8 | npm-debug.log*
9 | yarn-debug.log*
10 | yarn-error.log*
11 | lerna-debug.log*
12 |
13 | # OS
14 | .DS_Store
15 |
16 | # Tests
17 | /coverage
18 | /.nyc_output
19 |
20 | # IDEs and editors
21 | /.idea
22 | .project
23 | .classpath
24 | .c9/
25 | *.launch
26 | .settings/
27 | *.sublime-workspace
28 |
29 | # IDE - VSCode
30 | .vscode/*
31 | !.vscode/settings.json
32 | !.vscode/tasks.json
33 | !.vscode/launch.json
34 | !.vscode/extensions.json
--------------------------------------------------------------------------------
/notification-engine/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all"
4 | }
--------------------------------------------------------------------------------
/notification-engine/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | [travis-image]: https://api.travis-ci.org/nestjs/nest.svg?branch=master
6 | [travis-url]: https://travis-ci.org/nestjs/nest
7 | [linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux
8 | [linux-url]: https://travis-ci.org/nestjs/nest
9 |
10 | A progressive Node.js framework for building efficient and scalable server-side applications, heavily inspired by Angular.
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
26 |
27 | ## Description
28 |
29 | [Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
30 |
31 | ## Installation
32 |
33 | ```bash
34 | $ npm install
35 | ```
36 |
37 | ## Running the app
38 |
39 | ```bash
40 | # development
41 | $ npm run start
42 |
43 | # watch mode
44 | $ npm run start:dev
45 |
46 | # production mode
47 | $ npm run start:prod
48 | ```
49 |
50 | ## Test
51 |
52 | ```bash
53 | # unit tests
54 | $ npm run test
55 |
56 | # e2e tests
57 | $ npm run test:e2e
58 |
59 | # test coverage
60 | $ npm run test:cov
61 | ```
62 |
63 | ## Support
64 |
65 | Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
66 |
67 | ## Stay in touch
68 |
69 | - Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
70 | - Website - [https://nestjs.com](https://nestjs.com/)
71 | - Twitter - [@nestframework](https://twitter.com/nestframework)
72 |
73 | ## License
74 |
75 | Nest is [MIT licensed](LICENSE).
76 |
--------------------------------------------------------------------------------
/notification-engine/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "collection": "@nestjs/schematics",
3 | "sourceRoot": "src"
4 | }
5 |
--------------------------------------------------------------------------------
/notification-engine/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "notification-engine",
3 | "version": "0.0.1",
4 | "description": "",
5 | "author": "",
6 | "private": true,
7 | "license": "UNLICENSED",
8 | "scripts": {
9 | "prebuild": "rimraf dist",
10 | "build": "nest build",
11 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
12 | "start": "nest start",
13 | "start:dev": "nest start --watch",
14 | "start:debug": "nest start --debug --watch",
15 | "start:prod": "node dist/main",
16 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
17 | "test": "jest",
18 | "test:watch": "jest --watch",
19 | "test:cov": "jest --coverage",
20 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
21 | "test:e2e": "jest --config ./test/jest-e2e.json"
22 | },
23 | "dependencies": {
24 | "@anchan828/nest-sendgrid": "^0.3.25",
25 | "@nestjs/common": "^7.0.0",
26 | "@nestjs/config": "^0.5.0",
27 | "@nestjs/core": "^7.0.0",
28 | "@nestjs/microservices": "^7.4.4",
29 | "@nestjs/mongoose": "^7.0.2",
30 | "@nestjs/platform-express": "^7.0.0",
31 | "@zenvia/sdk": "^1.4.0",
32 | "kafkajs": "^1.14.0",
33 | "mongoose": "^5.10.8",
34 | "reflect-metadata": "^0.1.13",
35 | "rimraf": "^3.0.2",
36 | "rxjs": "^6.5.4"
37 | },
38 | "devDependencies": {
39 | "@nestjs/cli": "^7.0.0",
40 | "@nestjs/schematics": "^7.0.0",
41 | "@nestjs/testing": "^7.0.0",
42 | "@types/express": "^4.17.3",
43 | "@types/jest": "26.0.10",
44 | "@types/mongoose": "^5.7.36",
45 | "@types/node": "^13.9.1",
46 | "@types/supertest": "^2.0.8",
47 | "@typescript-eslint/eslint-plugin": "3.9.1",
48 | "@typescript-eslint/parser": "3.9.1",
49 | "eslint": "7.7.0",
50 | "eslint-config-prettier": "^6.10.0",
51 | "eslint-plugin-import": "^2.20.1",
52 | "jest": "26.4.2",
53 | "prettier": "^1.19.1",
54 | "supertest": "^4.0.2",
55 | "ts-jest": "26.2.0",
56 | "ts-loader": "^6.2.1",
57 | "ts-node": "9.0.0",
58 | "tsconfig-paths": "^3.9.0",
59 | "typescript": "^3.7.4"
60 | },
61 | "jest": {
62 | "moduleFileExtensions": [
63 | "js",
64 | "json",
65 | "ts"
66 | ],
67 | "rootDir": "src",
68 | "testRegex": ".spec.ts$",
69 | "transform": {
70 | "^.+\\.(t|j)s$": "ts-jest"
71 | },
72 | "coverageDirectory": "../coverage",
73 | "testEnvironment": "node"
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/notification-engine/src/app.controller.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { AppController } from './app.controller';
3 | import { AppService } from './app.service';
4 |
5 | describe('AppController', () => {
6 | let appController: AppController;
7 |
8 | beforeEach(async () => {
9 | const app: TestingModule = await Test.createTestingModule({
10 | controllers: [AppController],
11 | providers: [AppService],
12 | }).compile();
13 |
14 | appController = app.get(AppController);
15 | });
16 |
17 | describe('root', () => {
18 | it('should return "Hello World!"', () => {
19 | expect(appController.getHello()).toBe('Hello World!');
20 | });
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/notification-engine/src/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller } from '@nestjs/common';
2 | import { MessagePattern, Payload } from '@nestjs/microservices';
3 | import { AppService } from './app.service';
4 |
5 | @Controller()
6 | export class AppController {
7 | constructor(private readonly appService: AppService) {}
8 |
9 | @MessagePattern('notification-email')
10 | async sendEmail(@Payload() data: any): Promise {
11 | await this.appService.sendEmail(Number(data.value.id), data.value.email, data.value.name);
12 | }
13 |
14 | @MessagePattern('notification-sms')
15 | async sendSMS(@Payload() data: any): Promise {
16 | await this.appService.sendSMS(Number(data.value.id), data.value.phone, data.value.name);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/notification-engine/src/app.module.ts:
--------------------------------------------------------------------------------
1 | import { SendGridModule } from '@anchan828/nest-sendgrid';
2 | import { Module } from '@nestjs/common';
3 | import { ConfigModule } from '@nestjs/config';
4 | import { MongooseModule } from '@nestjs/mongoose';
5 | import { AppController } from './app.controller';
6 | import { AppService } from './app.service';
7 | import { NotificationSchema } from './interfaces/notification.schema';
8 |
9 | @Module({
10 | imports: [
11 | ConfigModule.forRoot(), SendGridModule.forRoot({
12 | apikey: process.env.SEND_GRID_ACCESS_KEY,
13 | }),
14 | MongooseModule.forRoot('mongodb://localhost/notification'),
15 | MongooseModule.forFeature([{ name: 'Notification', schema: NotificationSchema }]),
16 |
17 | ],
18 | controllers: [AppController],
19 | providers: [AppService],
20 | })
21 | export class AppModule {}
22 |
--------------------------------------------------------------------------------
/notification-engine/src/app.service.ts:
--------------------------------------------------------------------------------
1 | import { SendGridService } from '@anchan828/nest-sendgrid';
2 | import { Injectable } from '@nestjs/common';
3 | import { InjectModel } from '@nestjs/mongoose';
4 | import { Client, TextContent, IMessage } from '@zenvia/sdk';
5 | import { Model } from 'mongoose';
6 | import { NotificationDto } from './dtos/notification.dto';
7 | import { Notification } from './interfaces/notification.interface';
8 |
9 | @Injectable()
10 | export class AppService {
11 | constructor(
12 | private readonly sendGrid: SendGridService,
13 | @InjectModel('Notification') private readonly notificationModel: Model,
14 | ) {}
15 |
16 | private client = new Client(process.env.ZENVIA_TOKEN);
17 |
18 | async sendEmail(userId: number, email: string, name: string): Promise {
19 | await this.sendGrid.send({
20 | to: email,
21 | from: process.env.FROM_EMAIL,
22 | subject: "User Created",
23 | text: `Hello ${name}, your user created with success!`,
24 | html: `Hello ${name}, your user created with success!`,
25 | }).then(async response => {
26 | await this.createMongoNotification(userId, 'email', response, 'SUCCESS');
27 | }).catch(async error => {
28 | await this.createMongoNotification(userId, 'email', error, 'ERROR');
29 | });
30 | }
31 |
32 | async sendSMS(userId: number, phone: string, name: string): Promise {
33 | const sms = this.client.getChannel('sms');
34 | const content = new TextContent(`Hello ${name}, your user created with success!`);
35 |
36 | await sms.sendMessage(process.env.KEYWORD, phone, content)
37 | .then(async ({channel, contents, from, to, direction, id: messageId}: IMessage) => {
38 | const response: any = {
39 | channel,
40 | contents,
41 | from,
42 | to,
43 | direction,
44 | messageId,
45 | };
46 |
47 | await this.createMongoNotification(userId, 'sms', response, 'SUCCESS');
48 | }).catch(async error => {
49 | await this.createMongoNotification(userId, 'sms', error, 'ERROR');
50 | });
51 | }
52 |
53 | private async createMongoNotification(userId: number, type: 'sms' | 'email', response: any, status: 'SUCCESS' | 'ERROR'): Promise {
54 | const notification: NotificationDto ={
55 | userId,
56 | type,
57 | response,
58 | status,
59 | };
60 |
61 | const createNotification = new this.notificationModel(notification);
62 | await createNotification.save();
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/notification-engine/src/dtos/notification.dto.ts:
--------------------------------------------------------------------------------
1 | export class NotificationDto {
2 | userId: number;
3 | type: 'email' | 'sms';
4 | response: any;
5 | status: 'SUCCESS' | 'ERROR';
6 | }
--------------------------------------------------------------------------------
/notification-engine/src/interfaces/notification.interface.ts:
--------------------------------------------------------------------------------
1 | import { Document } from "mongoose";
2 |
3 | export interface Notification extends Document {
4 | userId: number;
5 | type: 'email' | 'sms';
6 | response: any;
7 | status: 'SUCCESS' | 'ERROR';
8 | }
--------------------------------------------------------------------------------
/notification-engine/src/interfaces/notification.schema.ts:
--------------------------------------------------------------------------------
1 |
2 | import * as mongoose from "mongoose";
3 |
4 | export const NotificationSchema = new mongoose.Schema({
5 | userId: Number,
6 | type: String,
7 | response: Object,
8 | status: String,
9 | }, { timestamps: true, collection: 'notifications' });
--------------------------------------------------------------------------------
/notification-engine/src/main.ts:
--------------------------------------------------------------------------------
1 | import { Logger } from '@nestjs/common';
2 | import { NestFactory } from '@nestjs/core';
3 | import { MicroserviceOptions, Transport } from '@nestjs/microservices';
4 | import { AppModule } from './app.module';
5 |
6 | const logger = new Logger('Main')
7 |
8 | async function bootstrap() {
9 | const app = await NestFactory.createMicroservice(AppModule, {
10 | transport: Transport.KAFKA,
11 | options: {
12 | client: {
13 | clientId: 'notification',
14 | brokers: ['localhost:9092'],
15 | },
16 | consumer: {
17 | groupId: 'notification-consumer',
18 | allowAutoTopicCreation: true
19 | }
20 | }
21 | });
22 | await app.listen(() => logger.log('notification-engine is running'));
23 | }
24 | bootstrap();
25 |
--------------------------------------------------------------------------------
/notification-engine/test/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { INestApplication } from '@nestjs/common';
3 | import * as request from 'supertest';
4 | import { AppModule } from './../src/app.module';
5 |
6 | describe('AppController (e2e)', () => {
7 | let app: INestApplication;
8 |
9 | beforeEach(async () => {
10 | const moduleFixture: TestingModule = await Test.createTestingModule({
11 | imports: [AppModule],
12 | }).compile();
13 |
14 | app = moduleFixture.createNestApplication();
15 | await app.init();
16 | });
17 |
18 | it('/ (GET)', () => {
19 | return request(app.getHttpServer())
20 | .get('/')
21 | .expect(200)
22 | .expect('Hello World!');
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/notification-engine/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": ".",
4 | "testEnvironment": "node",
5 | "testRegex": ".e2e-spec.ts$",
6 | "transform": {
7 | "^.+\\.(t|j)s$": "ts-jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/notification-engine/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/notification-engine/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "declaration": true,
5 | "removeComments": true,
6 | "emitDecoratorMetadata": true,
7 | "experimentalDecorators": true,
8 | "allowSyntheticDefaultImports": true,
9 | "target": "es2017",
10 | "sourceMap": true,
11 | "outDir": "./dist",
12 | "baseUrl": "./",
13 | "incremental": true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/user-engine/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: '@typescript-eslint/parser',
3 | parserOptions: {
4 | project: 'tsconfig.json',
5 | sourceType: 'module',
6 | },
7 | plugins: ['@typescript-eslint/eslint-plugin'],
8 | extends: [
9 | 'plugin:@typescript-eslint/eslint-recommended',
10 | 'plugin:@typescript-eslint/recommended',
11 | 'prettier',
12 | 'prettier/@typescript-eslint',
13 | ],
14 | root: true,
15 | env: {
16 | node: true,
17 | jest: true,
18 | },
19 | rules: {
20 | '@typescript-eslint/interface-name-prefix': 'off',
21 | '@typescript-eslint/explicit-function-return-type': 'off',
22 | '@typescript-eslint/explicit-module-boundary-types': 'off',
23 | '@typescript-eslint/no-explicit-any': 'off',
24 | },
25 | };
26 |
--------------------------------------------------------------------------------
/user-engine/.gitignore:
--------------------------------------------------------------------------------
1 | # compiled output
2 | /dist
3 | /node_modules
4 |
5 | # Logs
6 | logs
7 | *.log
8 | npm-debug.log*
9 | yarn-debug.log*
10 | yarn-error.log*
11 | lerna-debug.log*
12 |
13 | # OS
14 | .DS_Store
15 |
16 | # Tests
17 | /coverage
18 | /.nyc_output
19 |
20 | # IDEs and editors
21 | /.idea
22 | .project
23 | .classpath
24 | .c9/
25 | *.launch
26 | .settings/
27 | *.sublime-workspace
28 |
29 | # IDE - VSCode
30 | .vscode/*
31 | !.vscode/settings.json
32 | !.vscode/tasks.json
33 | !.vscode/launch.json
34 | !.vscode/extensions.json
--------------------------------------------------------------------------------
/user-engine/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all"
4 | }
--------------------------------------------------------------------------------
/user-engine/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | [travis-image]: https://api.travis-ci.org/nestjs/nest.svg?branch=master
6 | [travis-url]: https://travis-ci.org/nestjs/nest
7 | [linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux
8 | [linux-url]: https://travis-ci.org/nestjs/nest
9 |
10 | A progressive Node.js framework for building efficient and scalable server-side applications, heavily inspired by Angular.
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
26 |
27 | ## Description
28 |
29 | [Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
30 |
31 | ## Installation
32 |
33 | ```bash
34 | $ npm install
35 | ```
36 |
37 | ## Running the app
38 |
39 | ```bash
40 | # development
41 | $ npm run start
42 |
43 | # watch mode
44 | $ npm run start:dev
45 |
46 | # production mode
47 | $ npm run start:prod
48 | ```
49 |
50 | ## Test
51 |
52 | ```bash
53 | # unit tests
54 | $ npm run test
55 |
56 | # e2e tests
57 | $ npm run test:e2e
58 |
59 | # test coverage
60 | $ npm run test:cov
61 | ```
62 |
63 | ## Support
64 |
65 | Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
66 |
67 | ## Stay in touch
68 |
69 | - Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
70 | - Website - [https://nestjs.com](https://nestjs.com/)
71 | - Twitter - [@nestframework](https://twitter.com/nestframework)
72 |
73 | ## License
74 |
75 | Nest is [MIT licensed](LICENSE).
76 |
--------------------------------------------------------------------------------
/user-engine/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "collection": "@nestjs/schematics",
3 | "sourceRoot": "src"
4 | }
5 |
--------------------------------------------------------------------------------
/user-engine/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "user-engine",
3 | "version": "0.0.1",
4 | "description": "",
5 | "author": "",
6 | "private": true,
7 | "license": "UNLICENSED",
8 | "scripts": {
9 | "prebuild": "rimraf dist",
10 | "build": "nest build",
11 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
12 | "start": "nest start",
13 | "start:dev": "nest start --watch",
14 | "start:debug": "nest start --debug --watch",
15 | "start:prod": "node dist/main",
16 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
17 | "test": "jest",
18 | "test:watch": "jest --watch",
19 | "test:cov": "jest --coverage",
20 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
21 | "test:e2e": "jest --config ./test/jest-e2e.json"
22 | },
23 | "dependencies": {
24 | "@nestjs/common": "^7.0.0",
25 | "@nestjs/core": "^7.0.0",
26 | "@nestjs/microservices": "^7.4.4",
27 | "@nestjs/platform-express": "^7.0.0",
28 | "@nestjs/typeorm": "^7.1.4",
29 | "kafkajs": "^1.14.0",
30 | "pg": "^8.3.3",
31 | "reflect-metadata": "^0.1.13",
32 | "rimraf": "^3.0.2",
33 | "rxjs": "^6.5.4",
34 | "typeorm": "^0.2.28"
35 | },
36 | "devDependencies": {
37 | "@nestjs/cli": "^7.0.0",
38 | "@nestjs/schematics": "^7.0.0",
39 | "@nestjs/testing": "^7.0.0",
40 | "@types/express": "^4.17.3",
41 | "@types/jest": "26.0.10",
42 | "@types/node": "^13.9.1",
43 | "@types/supertest": "^2.0.8",
44 | "@typescript-eslint/eslint-plugin": "3.9.1",
45 | "@typescript-eslint/parser": "3.9.1",
46 | "eslint": "7.7.0",
47 | "eslint-config-prettier": "^6.10.0",
48 | "eslint-plugin-import": "^2.20.1",
49 | "jest": "26.4.2",
50 | "prettier": "^1.19.1",
51 | "supertest": "^4.0.2",
52 | "ts-jest": "26.2.0",
53 | "ts-loader": "^6.2.1",
54 | "ts-node": "9.0.0",
55 | "tsconfig-paths": "^3.9.0",
56 | "typescript": "^3.7.4"
57 | },
58 | "jest": {
59 | "moduleFileExtensions": [
60 | "js",
61 | "json",
62 | "ts"
63 | ],
64 | "rootDir": "src",
65 | "testRegex": ".spec.ts$",
66 | "transform": {
67 | "^.+\\.(t|j)s$": "ts-jest"
68 | },
69 | "coverageDirectory": "../coverage",
70 | "testEnvironment": "node"
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/user-engine/src/app.controller.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { AppController } from './app.controller';
3 | import { AppService } from './app.service';
4 |
5 | describe('AppController', () => {
6 | let appController: AppController;
7 |
8 | beforeEach(async () => {
9 | const app: TestingModule = await Test.createTestingModule({
10 | controllers: [AppController],
11 | providers: [AppService],
12 | }).compile();
13 |
14 | appController = app.get(AppController);
15 | });
16 |
17 | describe('root', () => {
18 | it('should return "Hello World!"', () => {
19 | expect(appController.getHello()).toBe('Hello World!');
20 | });
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/user-engine/src/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller, Logger } from '@nestjs/common';
2 | import { MessagePattern, Payload } from '@nestjs/microservices';
3 | import { AppService } from './app.service';
4 | import { UserEntity } from './interfaces/user.entity';
5 | import { User } from './interfaces/user.interface';
6 |
7 | @Controller()
8 | export class AppController {
9 | constructor(private readonly appService: AppService) {}
10 |
11 | private readonly logger = new Logger(AppController.name);
12 |
13 | @MessagePattern('find-all-user')
14 | async index(): Promise {
15 | return this.appService.findAll();
16 | }
17 |
18 | @MessagePattern('find-user')
19 | async find(@Payload() data: any): Promise {
20 | return this.appService.find(Number(data.value.id));
21 | }
22 |
23 | @MessagePattern('create-user')
24 | async create(@Payload() data: any): Promise {
25 | this.logger.log(`User: ${JSON.stringify(data)}`);
26 |
27 | return await this.appService.create(data.value);
28 | }
29 |
30 | @MessagePattern('update-user')
31 | async update(@Payload() data: any): Promise {
32 | this.logger.log(`User: ${JSON.stringify(data)}`);
33 |
34 | await this.appService.update(data.value);
35 | }
36 |
37 | @MessagePattern('delete-user')
38 | async remove(@Payload() data: any): Promise {
39 | return this.appService.delete(Number(data.value.id));
40 | }
41 |
42 | @MessagePattern('activate-user')
43 | async activate(@Payload() data: any): Promise {
44 | return this.appService.activate(Number(data.value.id));
45 | }
46 |
47 | @MessagePattern('inactivate-user')
48 | async inactivate(@Payload() data: any): Promise {
49 | return this.appService.inactivate(Number(data.value.id));
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/user-engine/src/app.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { TypeOrmModule } from '@nestjs/typeorm';
3 | import { AppController } from './app.controller';
4 | import { AppService } from './app.service';
5 | import { DatabaseModule } from './database/database.module';
6 | import { UserEntity } from './interfaces/user.entity';
7 |
8 | @Module({
9 | imports: [DatabaseModule, TypeOrmModule.forFeature([UserEntity])],
10 | controllers: [AppController],
11 | providers: [AppService],
12 | })
13 | export class AppModule {}
14 |
--------------------------------------------------------------------------------
/user-engine/src/app.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 | import { InjectRepository } from '@nestjs/typeorm';
3 | import { Repository } from 'typeorm';
4 | import { UserEntity } from './interfaces/user.entity';
5 | import { User } from './interfaces/user.interface';
6 |
7 | @Injectable()
8 | export class AppService {
9 | constructor(@InjectRepository(UserEntity) private userRepository: Repository) {}
10 |
11 | async findAll(): Promise {
12 | return await this.userRepository.find({ where: { status: 'ACTIVATE' }});
13 | }
14 |
15 | async find(userId: number): Promise {
16 | const {id, name,email, password, phone, status } = await this.userRepository.findOne(userId);
17 |
18 | if(!id) {
19 | throw new Error();
20 | }
21 |
22 | const response: User = {
23 | id,
24 | name,
25 | email,
26 | phone,
27 | password,
28 | status,
29 | };
30 |
31 | return response;
32 | }
33 |
34 | async create(user: User): Promise {
35 | return await this.userRepository.save(user);
36 | }
37 |
38 | async update(userData: UserEntity): Promise {
39 | const { id, name, email, phone, password } = userData;
40 | const user = await this.find(id);
41 |
42 | user.name = name ? name : user.name;
43 | user.email = email ? email : user.email;
44 | user.phone = phone ? phone : user.phone;
45 | user.password = password ? password : user.password;
46 |
47 | await this.userRepository.save(user);
48 | }
49 |
50 | async delete(id: number): Promise {
51 | await this.userRepository.delete({id});
52 | }
53 |
54 | async activate(id: number): Promise {
55 | await this.userRepository.update(id, { status: 'ACTIVATE' });
56 | }
57 |
58 | async inactivate(id: number): Promise {
59 | await this.userRepository.update(id, { status: 'INACTIVATE' });
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/user-engine/src/database/database.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { TypeOrmModule } from '@nestjs/typeorm';
3 | import { UserEntity } from '../interfaces/user.entity';
4 |
5 | @Module({
6 | imports: [TypeOrmModule.forRoot({
7 | type: 'postgres',
8 | host: 'localhost',
9 | username: 'postgres',
10 | password: 'docker',
11 | database: 'user',
12 | entities: [UserEntity],
13 | synchronize: true,
14 | }),]
15 | })
16 | export class DatabaseModule {}
--------------------------------------------------------------------------------
/user-engine/src/interfaces/user.entity.ts:
--------------------------------------------------------------------------------
1 | import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from "typeorm";
2 |
3 | @Entity()
4 | export class UserEntity extends BaseEntity {
5 | @PrimaryGeneratedColumn()
6 | id: number;
7 |
8 | @Column()
9 | name: string;
10 |
11 | @Column()
12 | email: string;
13 |
14 | @Column()
15 | phone: string;
16 |
17 | @Column()
18 | password: string;
19 |
20 | @Column({ default: 'ACTIVATE' })
21 | status: 'ACTIVATE' | 'INACTIVATE';
22 | }
--------------------------------------------------------------------------------
/user-engine/src/interfaces/user.interface.ts:
--------------------------------------------------------------------------------
1 | export interface User {
2 | id?: number;
3 | name: string;
4 | email: string;
5 | phone: string;
6 | password: string;
7 | status?: 'ACTIVATE' | 'INACTIVATE';
8 | }
--------------------------------------------------------------------------------
/user-engine/src/main.ts:
--------------------------------------------------------------------------------
1 | import { Logger } from '@nestjs/common';
2 | import { NestFactory } from '@nestjs/core';
3 | import { MicroserviceOptions, Transport } from '@nestjs/microservices';
4 | import { AppModule } from './app.module';
5 |
6 | const logger = new Logger('Main')
7 |
8 | async function bootstrap() {
9 | const app = await NestFactory.createMicroservice(AppModule, {
10 | transport: Transport.KAFKA,
11 | options: {
12 | client: {
13 | clientId: 'user',
14 | brokers: ['localhost:9092'],
15 | },
16 | consumer: {
17 | groupId: 'user-consumer',
18 | allowAutoTopicCreation: true
19 | }
20 | }
21 | });
22 | await app.listen(() => logger.log('user-engine is running'));
23 | }
24 | bootstrap();
25 |
--------------------------------------------------------------------------------
/user-engine/test/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { INestApplication } from '@nestjs/common';
3 | import * as request from 'supertest';
4 | import { AppModule } from './../src/app.module';
5 |
6 | describe('AppController (e2e)', () => {
7 | let app: INestApplication;
8 |
9 | beforeEach(async () => {
10 | const moduleFixture: TestingModule = await Test.createTestingModule({
11 | imports: [AppModule],
12 | }).compile();
13 |
14 | app = moduleFixture.createNestApplication();
15 | await app.init();
16 | });
17 |
18 | it('/ (GET)', () => {
19 | return request(app.getHttpServer())
20 | .get('/')
21 | .expect(200)
22 | .expect('Hello World!');
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/user-engine/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": ".",
4 | "testEnvironment": "node",
5 | "testRegex": ".e2e-spec.ts$",
6 | "transform": {
7 | "^.+\\.(t|j)s$": "ts-jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/user-engine/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/user-engine/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "declaration": true,
5 | "removeComments": true,
6 | "emitDecoratorMetadata": true,
7 | "experimentalDecorators": true,
8 | "allowSyntheticDefaultImports": true,
9 | "target": "es2017",
10 | "sourceMap": true,
11 | "outDir": "./dist",
12 | "baseUrl": "./",
13 | "incremental": true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------