chore: add files
commit
aad59e55b0
|
@ -0,0 +1,4 @@
|
||||||
|
HITPHONE_DESKTOP_SERVER_ORIGINS="http://172.31.187.195:4000"
|
||||||
|
API_KEY="ASDASDASDASD"
|
||||||
|
ENCRYPTION_KEY="abc123"
|
||||||
|
ENVIRONMENT="DEV"
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"node": true,
|
||||||
|
"jest": true
|
||||||
|
},
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"parserOptions": {
|
||||||
|
"project": "tsconfig.json",
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": ["@typescript-eslint"],
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
"standard-with-typescript"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"@typescript-eslint/prefer-nullish-coalescing": "off",
|
||||||
|
"@typescript-eslint/strict-boolean-expressions": "off",
|
||||||
|
"@typescript-eslint/explicit-function-return-type": "off",
|
||||||
|
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
|
||||||
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
|
"semi": ["error", "never"],
|
||||||
|
"comma-dangle": ["error", "never"]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
# compiled output
|
||||||
|
/dist
|
||||||
|
/node_modules
|
||||||
|
/build
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
/coverage
|
||||||
|
/.nyc_output
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
/.idea
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# IDE - VSCode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# temp directory
|
||||||
|
.temp
|
||||||
|
.tmp
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
cert-hitphone.key
|
||||||
|
cert-hitphone.pem
|
||||||
|
localhost-key.pem
|
||||||
|
localhost.pem
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "all"
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Variáveis de ambiente necessárias
|
||||||
|
|
||||||
|
- `HITPHONE_DESKTOP_SERVER_ORIGINS`: Campo do cors utilizado pelo servidor electron criado no desktop do cliente Hitphone
|
||||||
|
- `API_KEY`: Chave de API utilizada pelo client.
|
||||||
|
|
||||||
|
# Arquivos necessários
|
||||||
|
|
||||||
|
- Arquivo `cert-hitphone.key` na raiz do projeto: Chave privada do certificado SSL
|
||||||
|
- Arquivo `cert-hitphone.pem` na raiz do projeto: Certificado público do certificado SSL
|
|
@ -0,0 +1,47 @@
|
||||||
|
# Objetivo
|
||||||
|
|
||||||
|
- Implementar uma Inbox de API que tem suporte para o provedor de SMS InfoBIP
|
||||||
|
|
||||||
|
## Chatwoot -> HIT-SMS-API
|
||||||
|
|
||||||
|
- [ ] Rota de envio dos eventos oriundos do Chatwoot
|
||||||
|
- [ ] POST https://hit-sms-api.omnihit.app.br/api/chatwoot/webhook/sms/:provider_infobip/:apikey/:inbox_123
|
||||||
|
- [ ] Evento: message_created
|
||||||
|
- Parâmetros Requisição:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"content": "This is a incoming message from API Channel",
|
||||||
|
"created_at": "2020-08-30T15:43:04.000Z",
|
||||||
|
"message_type": "incoming",
|
||||||
|
"content_type": null,
|
||||||
|
"content_attributes": {},
|
||||||
|
"source_id": null,
|
||||||
|
"sender": {
|
||||||
|
"id": 0,
|
||||||
|
"name": "contact-name",
|
||||||
|
"avatar": "",
|
||||||
|
"type": "contact"
|
||||||
|
},
|
||||||
|
"inbox": {
|
||||||
|
"id": 0,
|
||||||
|
"name": "API Channel"
|
||||||
|
},
|
||||||
|
"conversation": {
|
||||||
|
"additional_attributes": null,
|
||||||
|
"channel": "Channel::Api",
|
||||||
|
"id": 0,
|
||||||
|
"inbox_id": 0,
|
||||||
|
"status": "open",
|
||||||
|
"agent_last_seen_at": 0,
|
||||||
|
"contact_last_seen_at": 0,
|
||||||
|
"timestamp": 0
|
||||||
|
},
|
||||||
|
"account": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "API testing"
|
||||||
|
},
|
||||||
|
"event": "message_created"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
-
|
|
@ -0,0 +1,4 @@
|
||||||
|
### Requisição para obter a configuração do servidor
|
||||||
|
GET http://localhost:3435/api/hub/config
|
||||||
|
Content-Type: application/json
|
||||||
|
X-API-KEY: ASDASDASDASD
|
|
@ -0,0 +1,25 @@
|
||||||
|
services:
|
||||||
|
redis-sms-api:
|
||||||
|
container_name: redis-sms-api
|
||||||
|
hostname: redis-sms-api
|
||||||
|
image: redis
|
||||||
|
ports:
|
||||||
|
- "6389:6379"
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- redis-data:/data
|
||||||
|
|
||||||
|
redis-commander-sms-api:
|
||||||
|
container_name: redis-commander-sms-api
|
||||||
|
hostname: redis-commander-sms-api
|
||||||
|
image: ghcr.io/joeferner/redis-commander:latest
|
||||||
|
#build: .
|
||||||
|
environment:
|
||||||
|
- REDIS_HOSTS=local:redis-sms-api:6379
|
||||||
|
ports:
|
||||||
|
- "8095:8081"
|
||||||
|
depends_on:
|
||||||
|
- redis-sms-api
|
||||||
|
volumes:
|
||||||
|
redis-data:
|
||||||
|
driver: local
|
|
@ -0,0 +1,14 @@
|
||||||
|
module.exports = {
|
||||||
|
apps: [
|
||||||
|
{
|
||||||
|
name: 'hitphone-hub',
|
||||||
|
script: 'dist/main.js',
|
||||||
|
instances: 'max',
|
||||||
|
exec_mode: 'cluster',
|
||||||
|
env: {
|
||||||
|
NODE_ENV: 'production'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/nest-cli",
|
||||||
|
"collection": "@nestjs/schematics",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"compilerOptions": {
|
||||||
|
"deleteOutDir": true
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,75 @@
|
||||||
|
{
|
||||||
|
"name": "hitphone-hub",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "",
|
||||||
|
"author": "",
|
||||||
|
"private": true,
|
||||||
|
"license": "UNLICENSED",
|
||||||
|
"scripts": {
|
||||||
|
"start": "nest start",
|
||||||
|
"start:dev": "nest start --watch",
|
||||||
|
"start:debug": "nest start --debug --watch",
|
||||||
|
"start:prod": "npm run build && pm2 start ecosystem.config.js && pm2 reload hitphone-hub && pm2 save",
|
||||||
|
"build": "nest build",
|
||||||
|
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||||
|
"lint": "eslint 'src/**/*.{ts,js}'",
|
||||||
|
"lint:fix": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@infobip-api/sdk": "^0.3.2",
|
||||||
|
"@nestjs/common": "^10.4.4",
|
||||||
|
"@nestjs/config": "^3.2.3",
|
||||||
|
"@nestjs/core": "^10.0.0",
|
||||||
|
"@nestjs/mapped-types": "*",
|
||||||
|
"@nestjs/platform-express": "^10.0.0",
|
||||||
|
"crypto-js": "^4.2.0",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
|
"morgan": "^1.10.0",
|
||||||
|
"reflect-metadata": "^0.2.0",
|
||||||
|
"rxjs": "^7.8.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@nestjs/cli": "^10.0.0",
|
||||||
|
"@nestjs/schematics": "^10.0.0",
|
||||||
|
"@nestjs/testing": "^10.0.0",
|
||||||
|
"@types/crypto-js": "^4.2.2",
|
||||||
|
"@types/express": "^4.17.17",
|
||||||
|
"@types/jest": "^29.5.2",
|
||||||
|
"@types/morgan": "^1.9.9",
|
||||||
|
"@types/node": "^20.3.1",
|
||||||
|
"@types/supertest": "^6.0.0",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||||
|
"@typescript-eslint/parser": "^7.18.0",
|
||||||
|
"eslint": "^8.57.1",
|
||||||
|
"eslint-config-prettier": "^9.0.0",
|
||||||
|
"eslint-config-standard-with-typescript": "^43.0.1",
|
||||||
|
"eslint-plugin-prettier": "^5.0.0",
|
||||||
|
"jest": "^29.5.0",
|
||||||
|
"prettier": "^3.0.0",
|
||||||
|
"source-map-support": "^0.5.21",
|
||||||
|
"standard": "^17.1.2",
|
||||||
|
"supertest": "^7.0.0",
|
||||||
|
"ts-jest": "^29.1.0",
|
||||||
|
"ts-loader": "^9.4.3",
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
|
"tsconfig-paths": "^4.2.0",
|
||||||
|
"typescript": "^5.1.3"
|
||||||
|
},
|
||||||
|
"jest": {
|
||||||
|
"moduleFileExtensions": [
|
||||||
|
"js",
|
||||||
|
"json",
|
||||||
|
"ts"
|
||||||
|
],
|
||||||
|
"rootDir": "src",
|
||||||
|
"testRegex": ".*\\.spec\\.ts$",
|
||||||
|
"transform": {
|
||||||
|
"^.+\\.(t|j)s$": "ts-jest"
|
||||||
|
},
|
||||||
|
"collectCoverageFrom": [
|
||||||
|
"**/*.(t|j)s"
|
||||||
|
],
|
||||||
|
"coverageDirectory": "../coverage",
|
||||||
|
"testEnvironment": "node"
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,24 @@
|
||||||
|
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common'
|
||||||
|
import { ConfigModule } from '@nestjs/config'
|
||||||
|
import { HubModule } from './hub/hub.module'
|
||||||
|
import { LoggerMiddleware } from './middlewares/logger.middleware'
|
||||||
|
import { SmsModule } from './sms/sms.module';
|
||||||
|
import { ChatwootModule } from './chatwoot/chatwoot.module';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
ConfigModule.forRoot({
|
||||||
|
isGlobal: true
|
||||||
|
}),
|
||||||
|
HubModule,
|
||||||
|
SmsModule,
|
||||||
|
ChatwootModule
|
||||||
|
],
|
||||||
|
providers: [HubModule]
|
||||||
|
})
|
||||||
|
export class AppModule implements NestModule {
|
||||||
|
configure (consumer: MiddlewareConsumer) {
|
||||||
|
consumer.apply(LoggerMiddleware)
|
||||||
|
.forRoutes('*')
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'
|
||||||
|
import { ChatwootService } from './chatwoot.service'
|
||||||
|
|
||||||
|
@Controller('chatwoot')
|
||||||
|
export class ChatwootController {
|
||||||
|
constructor (private readonly chatwootService: ChatwootService) {}
|
||||||
|
|
||||||
|
@Post('/webhook/:sms/:provider/:apikey/:inbox')
|
||||||
|
create (
|
||||||
|
@Param() params: { sms: string, provider: 'infobip', apikey: string, inbox: string }
|
||||||
|
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
findAll () {
|
||||||
|
return this.chatwootService.findAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get(':id')
|
||||||
|
findOne (@Param('id') id: string) {
|
||||||
|
return this.chatwootService.findOne(+id)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Patch(':id')
|
||||||
|
update (@Param('id') id: string, @Body() updateChatwootDto: UpdateChatwootDto) {
|
||||||
|
return this.chatwootService.update(+id, updateChatwootDto)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete(':id')
|
||||||
|
remove (@Param('id') id: string) {
|
||||||
|
return this.chatwootService.remove(+id)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { ChatwootService } from './chatwoot.service';
|
||||||
|
import { ChatwootController } from './chatwoot.controller';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
controllers: [ChatwootController],
|
||||||
|
providers: [ChatwootService],
|
||||||
|
})
|
||||||
|
export class ChatwootModule {}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { ChatwootService } from './chatwoot.service';
|
||||||
|
|
||||||
|
describe('ChatwootService', () => {
|
||||||
|
let service: ChatwootService;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [ChatwootService],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
service = module.get<ChatwootService>(ChatwootService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { CreateChatwootDto } from './dto/create-chatwoot.dto';
|
||||||
|
import { UpdateChatwootDto } from './dto/update-chatwoot.dto';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ChatwootService {
|
||||||
|
create(createChatwootDto: CreateChatwootDto) {
|
||||||
|
return 'This action adds a new chatwoot';
|
||||||
|
}
|
||||||
|
|
||||||
|
findAll() {
|
||||||
|
return `This action returns all chatwoot`;
|
||||||
|
}
|
||||||
|
|
||||||
|
findOne(id: number) {
|
||||||
|
return `This action returns a #${id} chatwoot`;
|
||||||
|
}
|
||||||
|
|
||||||
|
update(id: number, updateChatwootDto: UpdateChatwootDto) {
|
||||||
|
return `This action updates a #${id} chatwoot`;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(id: number) {
|
||||||
|
return `This action removes a #${id} chatwoot`;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common'
|
||||||
|
import { Request } from 'express'
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ApiKeyGuard implements CanActivate {
|
||||||
|
canActivate (context: ExecutionContext): boolean {
|
||||||
|
const request = context.switchToHttp().getRequest<Request>()
|
||||||
|
const apiKey = request.headers['x-api-key']
|
||||||
|
|
||||||
|
const validApiKey = process.env.API_KEY
|
||||||
|
|
||||||
|
if (apiKey && apiKey === validApiKey) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnauthorizedException('API key is invalid or missing')
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { Controller, Get, InternalServerErrorException, Logger, UseGuards } from '@nestjs/common'
|
||||||
|
import { HubService } from './hub.service'
|
||||||
|
import { ApiKeyGuard } from 'src/guards/api-key.guard'
|
||||||
|
|
||||||
|
@Controller('hub')
|
||||||
|
@UseGuards(ApiKeyGuard)
|
||||||
|
export class HubController {
|
||||||
|
constructor (private readonly hubService: HubService) { }
|
||||||
|
|
||||||
|
@Get('/config')
|
||||||
|
async findHitphoneDesktopServerConfig () {
|
||||||
|
try {
|
||||||
|
const hitphoneDesktopServerConfig = await this.hubService.findHitphoneDesktopServerConfig()
|
||||||
|
return {
|
||||||
|
...hitphoneDesktopServerConfig
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
Logger.error(`Error reading certificate or key file: ${error.message}`)
|
||||||
|
throw new InternalServerErrorException({
|
||||||
|
message: 'Error reading config informations'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { Module } from '@nestjs/common'
|
||||||
|
import { HubService } from './hub.service'
|
||||||
|
import { HubController } from './hub.controller'
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
controllers: [HubController],
|
||||||
|
providers: [HubService]
|
||||||
|
})
|
||||||
|
export class HubModule {}
|
|
@ -0,0 +1,47 @@
|
||||||
|
import { Injectable } from '@nestjs/common'
|
||||||
|
import { ConfigService } from '@nestjs/config'
|
||||||
|
import * as fs from 'fs/promises'
|
||||||
|
import * as path from 'path'
|
||||||
|
|
||||||
|
import encrypt from 'src/utils/encrypt'
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class HubService {
|
||||||
|
constructor (private readonly configService: ConfigService) { }
|
||||||
|
|
||||||
|
async findHitphoneDesktopServerConfig () {
|
||||||
|
try {
|
||||||
|
const ENCRYPTION_KEY = this.configService.get<string>('ENCRYPTION_KEY')
|
||||||
|
|
||||||
|
const origin = this.configService.get<string>('HITPHONE_DESKTOP_SERVER_ORIGINS')
|
||||||
|
const certificatePem = await fs.readFile(path.join(__dirname, '../../cert-hitphone.pem'), 'utf8')
|
||||||
|
const certificateKey = await fs.readFile(path.join(__dirname, '../../cert-hitphone.key'), 'utf8')
|
||||||
|
|
||||||
|
if (!origin || !certificatePem || !certificateKey || !ENCRYPTION_KEY) {
|
||||||
|
throw new Error("ENCRYPTION_KEY, HITPHONE_DESKTOP_SERVER_ORIGINS, cert-hitphone.pem or cert-hitphone.key doesn't exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
const originSplit = origin.split(',')
|
||||||
|
|
||||||
|
// return keys
|
||||||
|
const encryptedOriginReturnKey = encrypt('origin', ENCRYPTION_KEY)
|
||||||
|
const encryptedCertificateKeyReturnKey = encrypt('certificateKey', ENCRYPTION_KEY)
|
||||||
|
const encryptedCertificatePemReturnKey = encrypt('certificatePem', ENCRYPTION_KEY)
|
||||||
|
|
||||||
|
// return values
|
||||||
|
const originEncrypted = originSplit.map((origin) => {
|
||||||
|
return encrypt(origin, ENCRYPTION_KEY)
|
||||||
|
})
|
||||||
|
const encryptedCertificateKey = encrypt(certificateKey, ENCRYPTION_KEY)
|
||||||
|
const encryptedCertificatePem = encrypt(certificatePem, ENCRYPTION_KEY)
|
||||||
|
|
||||||
|
return {
|
||||||
|
[encryptedOriginReturnKey]: originEncrypted,
|
||||||
|
[encryptedCertificateKeyReturnKey]: encryptedCertificateKey,
|
||||||
|
[encryptedCertificatePemReturnKey]: encryptedCertificatePem
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error('Error reading certificate or key file: ' + error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { NestFactory } from '@nestjs/core'
|
||||||
|
import { AppModule } from './app.module'
|
||||||
|
|
||||||
|
async function bootstrap () {
|
||||||
|
const app = await NestFactory.create(AppModule)
|
||||||
|
|
||||||
|
app.setGlobalPrefix('api')
|
||||||
|
app.enableCors({
|
||||||
|
origin: '*'
|
||||||
|
})
|
||||||
|
|
||||||
|
await app.listen(3435)
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
|
bootstrap()
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { Injectable, NestMiddleware } from '@nestjs/common'
|
||||||
|
import * as morgan from 'morgan'
|
||||||
|
import { IncomingMessage, ServerResponse } from 'http'
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class LoggerMiddleware implements NestMiddleware {
|
||||||
|
private readonly morganMiddleware: any
|
||||||
|
|
||||||
|
constructor () {
|
||||||
|
// Define os tokens personalizados
|
||||||
|
morgan.token('timestamp', () => {
|
||||||
|
const date = new Date()
|
||||||
|
return date.toLocaleString('pt-BR', {
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit',
|
||||||
|
day: '2-digit',
|
||||||
|
month: '2-digit',
|
||||||
|
year: 'numeric',
|
||||||
|
hour12: false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
morgan.token('statusColor', (req: IncomingMessage, res: ServerResponse) => {
|
||||||
|
const status = res.headersSent ? res.statusCode : undefined
|
||||||
|
const color = status !== undefined
|
||||||
|
? (
|
||||||
|
status >= 500
|
||||||
|
? 31
|
||||||
|
: status >= 400
|
||||||
|
? 33
|
||||||
|
: status >= 300
|
||||||
|
? 36
|
||||||
|
: status >= 200
|
||||||
|
? 32
|
||||||
|
: 0
|
||||||
|
)
|
||||||
|
: 0
|
||||||
|
|
||||||
|
return `\x1b[${color}m${status}\x1b[0m`
|
||||||
|
})
|
||||||
|
|
||||||
|
this.morganMiddleware = morgan(':timestamp - :method :url :statusColor :response-time ms - :res[content-length]')
|
||||||
|
}
|
||||||
|
|
||||||
|
use (req: IncomingMessage, res: ServerResponse, next: () => void) {
|
||||||
|
this.morganMiddleware(req, res, next)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export class CreateSmDto {}
|
|
@ -0,0 +1,4 @@
|
||||||
|
import { PartialType } from '@nestjs/mapped-types';
|
||||||
|
import { CreateSmDto } from './create-sm.dto';
|
||||||
|
|
||||||
|
export class UpdateSmDto extends PartialType(CreateSmDto) {}
|
|
@ -0,0 +1 @@
|
||||||
|
export class Sm {}
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { Controller, Get, Post, Body, Patch, Param, Delete, InternalServerErrorException, Logger } from '@nestjs/common'
|
||||||
|
import { SmsService } from './sms.service'
|
||||||
|
import { CreateSmDto } from './dto/create-sm.dto'
|
||||||
|
import { UpdateSmDto } from './dto/update-sm.dto'
|
||||||
|
|
||||||
|
@Controller('sms')
|
||||||
|
export class SmsController {
|
||||||
|
constructor (private readonly smsService: SmsService) {}
|
||||||
|
|
||||||
|
@Post('/:provider')
|
||||||
|
createSmsMessage (@Body() smsMessage: CreateSmDto) {
|
||||||
|
try {
|
||||||
|
const hitphoneDesktopServerConfig = await this.hubService.findHitphoneDesktopServerConfig()
|
||||||
|
return {
|
||||||
|
...hitphoneDesktopServerConfig
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
Logger.error(`Error reading certificate or key file: ${error.message}`)
|
||||||
|
throw new InternalServerErrorException({
|
||||||
|
message: 'Error reading config informations'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// return this.smsService.create(createSmDto)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
findAll () {
|
||||||
|
return this.smsService.findAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get(':id')
|
||||||
|
findOne (@Param('id') id: string) {
|
||||||
|
return this.smsService.findOne(+id)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Patch(':id')
|
||||||
|
update (@Param('id') id: string, @Body() updateSmDto: UpdateSmDto) {
|
||||||
|
return this.smsService.update(+id, updateSmDto)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete(':id')
|
||||||
|
remove (@Param('id') id: string) {
|
||||||
|
return this.smsService.remove(+id)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { Module } from '@nestjs/common'
|
||||||
|
import { SmsService } from './sms.service'
|
||||||
|
import { SmsController } from './sms.controller'
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
controllers: [SmsController],
|
||||||
|
providers: [SmsService]
|
||||||
|
})
|
||||||
|
export class SmsModule {}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { Test, type TestingModule } from '@nestjs/testing'
|
||||||
|
import { SmsService } from './sms.service'
|
||||||
|
|
||||||
|
describe('SmsService', () => {
|
||||||
|
let service: SmsService
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [SmsService]
|
||||||
|
}).compile()
|
||||||
|
|
||||||
|
service = module.get<SmsService>(SmsService)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(service).toBeDefined()
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { Injectable } from '@nestjs/common'
|
||||||
|
import { CreateSmDto } from './dto/create-sm.dto'
|
||||||
|
import { UpdateSmDto } from './dto/update-sm.dto'
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class SmsService {
|
||||||
|
create (createSmDto: CreateSmDto) {
|
||||||
|
return 'This action adds a new sm'
|
||||||
|
}
|
||||||
|
|
||||||
|
findAll () {
|
||||||
|
return 'This action returns all sms'
|
||||||
|
}
|
||||||
|
|
||||||
|
findOne (id: number) {
|
||||||
|
return `This action returns a #${id} sm`
|
||||||
|
}
|
||||||
|
|
||||||
|
update (id: number, updateSmDto: UpdateSmDto) {
|
||||||
|
return `This action updates a #${id} sm`
|
||||||
|
}
|
||||||
|
|
||||||
|
remove (id: number) {
|
||||||
|
return `This action removes a #${id} sm`
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import * as CryptoJS from 'crypto-js'
|
||||||
|
|
||||||
|
function encrypt (string: string, ENCRYPTION_KEY: string): string {
|
||||||
|
const encryptedText = CryptoJS.AES.encrypt(string, ENCRYPTION_KEY)
|
||||||
|
const ciphertext = encryptedText.toString()
|
||||||
|
|
||||||
|
return ciphertext
|
||||||
|
}
|
||||||
|
|
||||||
|
export default encrypt
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"declaration": true,
|
||||||
|
"removeComments": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"target": "ES2021",
|
||||||
|
"sourceMap": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"baseUrl": "./",
|
||||||
|
"incremental": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"strictBindCallApply": false,
|
||||||
|
"forceConsistentCasingInFileNames": false,
|
||||||
|
"noFallthroughCasesInSwitch": false,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue