diff --git a/app/apps/onebox/Dockerfile b/app/apps/onebox/Dockerfile deleted file mode 100644 index 915ac86..0000000 --- a/app/apps/onebox/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -FROM node:18-alpine As development - -WORKDIR /usr/src/app - -COPY package.json yarn.lock ./ - -RUN yarn - -COPY . . - -CMD ["yarn", "start:dev"] - -FROM node:18-alpine as production - -ARG NODE_ENV=production -ENV NODE_ENV=${NODE_ENV} - -WORKDIR /usr/src/app - -COPY package*.json yarn.lock ./ - -RUN yarn install --production - -COPY ./dist/apps/onebox ./dist/apps/onebox - -COPY ./resources ./resources - -CMD ["node", "dist/apps/onebox/main.js"] \ No newline at end of file diff --git a/app/apps/onebox/src/main.module.ts b/app/apps/onebox/src/main.module.ts deleted file mode 100644 index f70c079..0000000 --- a/app/apps/onebox/src/main.module.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { GlobalModule, GlobalService } from '@app/global'; -import { Module } from '@nestjs/common'; -import { ConfigModule } from '@nestjs/config'; -import { ScheduleModule } from '@nestjs/schedule'; -import { SwaggerModule } from '@nestjs/swagger'; -import { MonitorAddressModule } from './modules/address/address.module'; -import { ApiV1Module } from './modules/api/v1/apiv1.module'; -import { ApiKeyModule } from './modules/apikey/apikey.module'; -import { AuthModule } from './modules/auth/auth.module'; -import { BlockSyncModule } from './modules/blocksync/blocksync.module'; -import { DeliveryModule } from './modules/delivery/delivery.module'; -import { EventHistoryModule } from './modules/event_history/event_history.module'; -import { MonitorModule } from './modules/monitor/monitor.module'; -import { ProjectModule } from './modules/project/project.module'; -import { QuickStartModule } from './modules/quickstart/quickstart.module'; -import { UsersModule } from './modules/users/users.module'; -import { PollingBlockModule } from './modules/polling.block/polling.block.module'; - -@Module({ - imports: [ - ConfigModule.forRoot({ - isGlobal: true, - envFilePath: [`${process.env.NODE_ENV}.env`, '.env'], - expandVariables: true, - }), - UsersModule, - AuthModule, - GlobalModule, - SwaggerModule, - ScheduleModule.forRoot(), - ProjectModule, - BlockSyncModule, - MonitorModule, - MonitorAddressModule, - DeliveryModule, - EventHistoryModule, - QuickStartModule, - ApiKeyModule, - ApiV1Module, - PollingBlockModule, - ], - providers: [GlobalService], -}) -export class MainModule {} diff --git a/app/apps/onebox/src/main.ts b/app/apps/onebox/src/main.ts deleted file mode 100644 index 093bccd..0000000 --- a/app/apps/onebox/src/main.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { AllExceptionsFilter } from '@app/global/global.exception'; -import { ResponseInterceptor } from '@app/global/global.interceptor'; -import { LogLevel, ValidationPipe } from '@nestjs/common'; -import { HttpAdapterHost, NestFactory } from '@nestjs/core'; -import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; -import * as expressBasicAuth from 'express-basic-auth'; -import { MainModule } from './main.module'; - -async function bootstrap() { - // setting up nestjs - const app = await NestFactory.create(MainModule, { - logger: - process.env.LOGS !== undefined - ? (process.env.LOGS.split(',') as LogLevel[]) - : ['error', 'warn', 'log', 'fatal', 'debug', 'verbose'], - }); - - if (process.env.CORS && process.env.CORS != '') { - // setting up cors - app.enableCors({ origin: process.env.CORS.split(',') }); - } - - if (process.env.SWAGGER_ENABLE === 'true') { - // HTTP Basic Auth for Swagger Docs - app.use( - '/docs/*', - expressBasicAuth({ - challenge: true, - users: { - [process.env.SWAGGER_USER]: process.env.SWAGGER_PASSWORD, - }, - }), - ); - - // setting up swagger - const options = new DocumentBuilder() - .setTitle(process.env.SWAGGER_TITLE || 'Blockchain Webhook API') - .setDescription( - process.env.SWAGGER_DESCRIPTION || 'The Blockchain Webhook API', - ) - .setVersion('1.0') - .addBearerAuth( - { - name: 'Authorization', - description: 'JWT Authorization', - type: 'http', - scheme: 'bearer', - bearerFormat: 'JWT', - }, - 'JWT', - ) - .addApiKey( - { - name: 'x-api-key', - description: 'API Key', - type: 'apiKey', - scheme: 'string', - }, - 'apiKey', - ) - .build(); - const document = SwaggerModule.createDocument(app, options); - SwaggerModule.setup('docs', app, document); - } - - // setting up exception handler - const httpAdapter = app.get(HttpAdapterHost); - app.useGlobalPipes(new ValidationPipe({ transform: true })); - app.useGlobalFilters(new AllExceptionsFilter(httpAdapter)); - app.useGlobalInterceptors(new ResponseInterceptor()); - - await app.listen(process.env.SERVER_PORT); -} - -bootstrap(); diff --git a/app/apps/onebox/src/modules/address/address.controller.ts b/app/apps/onebox/src/modules/address/address.controller.ts deleted file mode 100644 index 974ac3b..0000000 --- a/app/apps/onebox/src/modules/address/address.controller.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { - Body, - Controller, - Delete, - Get, - Post, - Query, - Req, - UseGuards, -} from '@nestjs/common'; -import { - ApiBearerAuth, - ApiCreatedResponse, - ApiOkResponse, - ApiOperation, - ApiTags, -} from '@nestjs/swagger'; -import { Request } from 'express'; -import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; -import { User } from '../users/schemas/user.schema'; -import { MonitorAddressService } from './address.service'; -import { - CreateMonitorAddressDto, - DeleteMonitorAddressDto, - DeleteMonitorAddressResponseDto, - GetMonitorAddressRequestDto, - GetMonitorAddressResponseDto, - MonitorAddressResponseDto, - SearchMonitorAddressRequestDto, -} from './dto/address.dto'; - -@ApiTags('Monitor Address') -@Controller('address') -export class MonitorAddressController { - constructor(private readonly monitorAddressService: MonitorAddressService) {} - - @ApiOperation({ summary: 'Create Monitor Address' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Post('') - @ApiCreatedResponse({ type: [MonitorAddressResponseDto] }) - async createMonitorAddress( - @Req() req: Request, - @Body() body: CreateMonitorAddressDto, - ): Promise { - return this.monitorAddressService.createMonitorAddress( - req.user as User, - body, - ); - } - - @ApiOperation({ summary: 'Get Monitor Address' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Get('') - @ApiOkResponse({ type: GetMonitorAddressResponseDto }) - async getMonitorAddress( - @Req() req: Request, - @Query() - body: GetMonitorAddressRequestDto, - ): Promise { - return this.monitorAddressService.getMonitorAddress(req.user as User, body); - } - - @ApiOperation({ summary: 'Delete Monitor Address' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Delete('') - @ApiOkResponse({ type: DeleteMonitorAddressResponseDto }) - async deleteMonitorAddress( - @Req() req: Request, - @Body() body: DeleteMonitorAddressDto, - ): Promise { - return this.monitorAddressService.deleteMonitorAddress( - req.user as User, - body, - ); - } - - @ApiOperation({ summary: 'Search Monitor Address' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Get('/search') - @ApiOkResponse({ type: GetMonitorAddressResponseDto }) - async searchMonitorAddress( - @Req() req: Request, - @Query() - body: SearchMonitorAddressRequestDto, - ): Promise { - return this.monitorAddressService.searchAddressInMonitor( - req.user as User, - body, - ); - } -} diff --git a/app/apps/onebox/src/modules/address/address.module.ts b/app/apps/onebox/src/modules/address/address.module.ts deleted file mode 100644 index dfe940a..0000000 --- a/app/apps/onebox/src/modules/address/address.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MonitorModule as MonitorModelModule } from '@app/shared_modules/monitor/monitor.module'; -import { ProjectModule as ProjectModelModule } from '@app/shared_modules/project/project.module'; -import { Module } from '@nestjs/common'; -import { MonitorModule } from '../monitor/monitor.module'; -import { MonitorAddressController } from './address.controller'; -import { MonitorAddressService } from './address.service'; - -@Module({ - controllers: [MonitorAddressController], - providers: [MonitorAddressService], - exports: [MonitorAddressService], - imports: [MonitorModelModule, ProjectModelModule, MonitorModule], -}) -export class MonitorAddressModule {} diff --git a/app/apps/onebox/src/modules/address/address.service.ts b/app/apps/onebox/src/modules/address/address.service.ts deleted file mode 100644 index 77f5daf..0000000 --- a/app/apps/onebox/src/modules/address/address.service.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { MonitorAddressRepository } from '@app/shared_modules/monitor/repositories/monitor.address.repository'; -import { MonitorRepository } from '@app/shared_modules/monitor/repositories/monitor.repository'; -import { MonitorAddress } from '@app/shared_modules/monitor/schemas/monitor.address.schema'; -import { ProjectMemberRepository } from '@app/shared_modules/project/repositories/project.member.repository'; -import { Injectable } from '@nestjs/common'; -import { Builder } from 'builder-pattern'; -import { MonitorService } from '../monitor/monitor.service'; -import { User } from '../users/schemas/user.schema'; -import { - CreateMonitorAddressDto, - DeleteMonitorAddressDto, - DeleteMonitorAddressResponseDto, - GetMonitorAddressRequestDto, - GetMonitorAddressResponseDto, - MonitorAddressResponseDto, - SearchMonitorAddressRequestDto, -} from './dto/address.dto'; - -@Injectable() -export class MonitorAddressService { - constructor( - private readonly projectMemberRepository: ProjectMemberRepository, - private readonly monitorRepository: MonitorRepository, - private readonly monitorService: MonitorService, - ) {} - - async createMonitorAddress( - user: User, - request: CreateMonitorAddressDto, - ): Promise { - const monitor = await this.monitorService.findAndAuthMonitor( - user, - request.monitorId, - ); - const addresses = request.addresses.map((address) => - Builder() - .projectId(monitor.projectId) - .monitorId(monitor.monitorId) - .address(address.toLocaleLowerCase()) - .network(monitor.network) - .createdBy(user.userId) - .dateCreated(new Date()) - .build(), - ); - const savedAddresses = await MonitorAddressRepository.getRepository( - monitor.network, - ).saveAll(addresses); - await this.monitorRepository.increaseAddressCount( - monitor.monitorId, - savedAddresses.length, - ); - return savedAddresses.map((address) => - MonitorAddressResponseDto.from(address), - ); - } - - async getMonitorAddress( - user: User, - request: GetMonitorAddressRequestDto, - ): Promise { - const monitor = await this.monitorService.findAndAuthMonitor( - user, - request.monitorId, - ); - return MonitorAddressRepository.getRepository(monitor.network) - .getMonitorAddress(monitor.monitorId, request.limit, request.offset) - .then((addresses) => - Builder() - .addresses( - addresses.map((address) => MonitorAddressResponseDto.from(address)), - ) - .build(), - ); - } - - async deleteMonitorAddress( - user: User, - request: DeleteMonitorAddressDto, - ): Promise { - const monitor = await this.monitorService.findAndAuthMonitor( - user, - request.monitorId, - ); - // lower case request.addresses - request.addresses = request.addresses.map((address) => - address.toLowerCase(), - ); - const deletedCount = await MonitorAddressRepository.getRepository( - monitor.network, - ).deleteMonitorAddress(monitor.monitorId, request.addresses); - - await this.monitorRepository.increaseAddressCount( - monitor.monitorId, - -deletedCount, - ); - return Builder().success(true).build(); - } - - async searchAddressInMonitor( - user: User, - request: SearchMonitorAddressRequestDto, - ): Promise { - const monitor = await this.monitorService.findAndAuthMonitor( - user, - request.monitorId, - ); - return MonitorAddressRepository.getRepository(monitor.network) - .findAddressByMonitorAndAddress( - monitor.monitorId, - request.address.toLowerCase(), - ) - .then((addresses) => - Builder() - .addresses( - addresses.map((address) => MonitorAddressResponseDto.from(address)), - ) - .build(), - ); - } -} diff --git a/app/apps/onebox/src/modules/address/dto/address.dto.ts b/app/apps/onebox/src/modules/address/dto/address.dto.ts deleted file mode 100644 index 0dbe341..0000000 --- a/app/apps/onebox/src/modules/address/dto/address.dto.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { MonitorAddress } from '@app/shared_modules/monitor/schemas/monitor.address.schema'; -import { MonitorNetwork } from '@app/shared_modules/monitor/schemas/monitor.schema'; -import { ApiProperty, ApiResponseProperty } from '@nestjs/swagger'; -import { Transform } from 'class-transformer'; -import { - ArrayMaxSize, - ArrayMinSize, - IsNotEmpty, - IsNumber, - Max, - Min, -} from 'class-validator'; - -export class CreateMonitorAddressDto { - @ApiProperty() - @IsNotEmpty() - monitorId: string; - - @ApiProperty({ type: String, isArray: true }) - @IsNotEmpty() - @ArrayMaxSize(50) - @ArrayMinSize(1) - addresses: string[]; -} - -export class MonitorAddressResponseDto { - @ApiResponseProperty() - monitorId: string; - - @ApiResponseProperty() - address: string; - - @ApiResponseProperty({ enum: MonitorNetwork }) - network: MonitorNetwork; - - @ApiResponseProperty() - dateCreated: Date; - - static from(address: MonitorAddress): MonitorAddressResponseDto { - return { - monitorId: address.monitorId, - address: address.address, - network: address.network, - dateCreated: address.dateCreated, - }; - } -} - -export class GetMonitorAddressRequestDto { - @ApiProperty() - @IsNotEmpty() - monitorId: string; - - @ApiProperty() - @IsNumber() - @Min(1) - @Max(10) - @Transform(({ value }) => Number.parseInt(value)) - limit: number; - - @ApiProperty() - @IsNumber() - @Min(0) - @Transform(({ value }) => Number.parseInt(value)) - offset: number; -} - -export class GetMonitorAddressResponseDto { - @ApiResponseProperty() - addresses: MonitorAddressResponseDto[]; -} - -export class DeleteMonitorAddressDto { - @ApiProperty() - @IsNotEmpty() - monitorId: string; - - @ApiProperty({ type: String, isArray: true }) - @IsNotEmpty() - @ArrayMaxSize(50) - @ArrayMinSize(1) - addresses: string[]; -} - -export class DeleteMonitorAddressResponseDto { - @ApiResponseProperty() - success: boolean; -} - -export class SearchMonitorAddressRequestDto { - @ApiProperty() - @IsNotEmpty() - monitorId: string; - - @ApiProperty() - @IsNotEmpty() - address: string; -} diff --git a/app/apps/onebox/src/modules/api/auth/apikey.guard.ts b/app/apps/onebox/src/modules/api/auth/apikey.guard.ts deleted file mode 100644 index ca50fbf..0000000 --- a/app/apps/onebox/src/modules/api/auth/apikey.guard.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { AuthGuard } from '@nestjs/passport'; - -@Injectable() -export class ApikeyGuard extends AuthGuard('apikey') {} diff --git a/app/apps/onebox/src/modules/api/auth/apikey.strategy.ts b/app/apps/onebox/src/modules/api/auth/apikey.strategy.ts deleted file mode 100644 index b82c25e..0000000 --- a/app/apps/onebox/src/modules/api/auth/apikey.strategy.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { ErrorCode } from '@app/global/global.error'; -import { Injectable } from '@nestjs/common'; -import { PassportStrategy } from '@nestjs/passport'; -import { Request } from 'express'; -import { Strategy } from 'passport-http-header-strategy'; -import { UsersService } from '../../users/users.service'; -import { ApiKeyRepository } from '../../apikey/repositories/apikey.repository'; -import { ApiKeyUser } from '../../apikey/schemas/apikey.schema'; - -@Injectable() -export class ApikeyStrategy extends PassportStrategy(Strategy, 'apikey') { - constructor( - private readonly apikeyRepository: ApiKeyRepository, - private readonly userService: UsersService, - ) { - super({ - header: 'x-api-key', - passReqToCallback: true, - }); - } - - async validate(req: Request, token: string) { - const apikey = await this.apikeyRepository.findByApiKey(token); - if (!apikey) { - throw ErrorCode.UNAUTHORIZED.asException(); - } - const projectId = this.extracProjectId(req); - if (projectId && projectId !== '' && projectId !== apikey.projectId) { - throw ErrorCode.PROJECT_FORBIDDEN.asException(); - } - const user = await this.userService.findOneByUserId(apikey.userId); - if (!user) { - throw ErrorCode.UNAUTHORIZED.asException(); - } - return ApiKeyUser.from(user, apikey); - } - - private extracProjectId(request: Request): string { - let projectId = request.query['projectId']; - if (projectId && projectId != '') { - return projectId as string; - } - projectId = request.body.projectId; - if (projectId && projectId != '') { - return projectId as string; - } - return null; - } -} diff --git a/app/apps/onebox/src/modules/api/v1/address.controller.ts b/app/apps/onebox/src/modules/api/v1/address.controller.ts deleted file mode 100644 index 04c09ff..0000000 --- a/app/apps/onebox/src/modules/api/v1/address.controller.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Body, Controller, Delete, Post, Req, UseGuards } from '@nestjs/common'; -import { - ApiBasicAuth, - ApiCreatedResponse, - ApiOkResponse, - ApiOperation, - ApiTags, -} from '@nestjs/swagger'; -import { MonitorAddressService } from 'apps/onebox/src/modules/address/address.service'; -import { - CreateMonitorAddressDto, - DeleteMonitorAddressDto, - DeleteMonitorAddressResponseDto, - MonitorAddressResponseDto, -} from 'apps/onebox/src/modules/address/dto/address.dto'; -import { Request } from 'express'; -import { ApikeyGuard } from '../auth/apikey.guard'; -import { ApiKeyUser } from '../../apikey/schemas/apikey.schema'; - -@ApiTags('Api V1 / Monitor Address') -@Controller('/api/v1/monitor-addresses') -@ApiBasicAuth('apiKey') -@UseGuards(ApikeyGuard) -export class MonitorAddressController { - constructor(private readonly monitorAddressService: MonitorAddressService) {} - - @ApiOperation({ summary: 'Create Monitor Addresses' }) - @Post('') - @ApiCreatedResponse({ type: [MonitorAddressResponseDto] }) - async createMonitorAddress( - @Req() req: Request, - @Body() body: CreateMonitorAddressDto, - ): Promise { - return this.monitorAddressService.createMonitorAddress( - req.user as ApiKeyUser, - body, - ); - } - - @ApiOperation({ summary: 'Delete Monitor Addresses' }) - @Delete('') - @ApiOkResponse({ type: DeleteMonitorAddressResponseDto }) - async deleteMonitorAddress( - @Req() req: Request, - @Body() body: DeleteMonitorAddressDto, - ): Promise { - return this.monitorAddressService.deleteMonitorAddress( - req.user as ApiKeyUser, - body, - ); - } -} diff --git a/app/apps/onebox/src/modules/api/v1/apiv1.module.ts b/app/apps/onebox/src/modules/api/v1/apiv1.module.ts deleted file mode 100644 index 2e65deb..0000000 --- a/app/apps/onebox/src/modules/api/v1/apiv1.module.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { DatabaseModule } from '@app/database'; -import { Module } from '@nestjs/common'; -import { PassportModule } from '@nestjs/passport'; -import { MonitorAddressModule } from 'apps/onebox/src/modules/address/address.module'; -import { UsersModule } from 'apps/onebox/src/modules/users/users.module'; -import { UsersProviders } from 'apps/onebox/src/modules/users/users.providers'; -import { ApikeyStrategy } from '../auth/apikey.strategy'; -import { MonitorAddressController } from './address.controller'; -import { ApiKeyModule } from '../../apikey/apikey.module'; - -@Module({ - imports: [ - UsersModule, - PassportModule, - DatabaseModule, - ApiKeyModule, - UsersModule, - MonitorAddressModule, - ], - controllers: [MonitorAddressController], - providers: [ApikeyStrategy, ...UsersProviders], - exports: [], -}) -export class ApiV1Module {} diff --git a/app/apps/onebox/src/modules/apikey/apikey.controller.ts b/app/apps/onebox/src/modules/apikey/apikey.controller.ts deleted file mode 100644 index 6485070..0000000 --- a/app/apps/onebox/src/modules/apikey/apikey.controller.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { - Body, - Controller, - Delete, - Get, - Param, - Patch, - Post, - Query, - Req, - UseGuards, -} from '@nestjs/common'; -import { - ApiBearerAuth, - ApiCreatedResponse, - ApiOkResponse, - ApiOperation, - ApiTags, -} from '@nestjs/swagger'; -import { Request } from 'express'; -import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; -import { User } from '../users/schemas/user.schema'; -import { ApikeyService } from './apikey.service'; -import { - ApiKeyResponseDto, - CreateApiKeyDto, - DeleteApiKeyResponseDto, - UpdateApiKeyDto, -} from './dto/apikey.dto'; - -@ApiTags('Api Key') -@Controller('apikey') -export class ApiKeyController { - constructor(private readonly apiKeyService: ApikeyService) {} - - @ApiOperation({ summary: 'Create Apikey' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Post('') - @ApiCreatedResponse({ type: ApiKeyResponseDto }) - async createApikey( - @Req() req: Request, - @Body() body: CreateApiKeyDto, - ): Promise { - return await this.apiKeyService.createApiKey(req.user as User, body); - } - - @ApiOperation({ summary: 'Get Apikey' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Get('/:apikey') - @ApiOkResponse({ type: ApiKeyResponseDto }) - async getApikey( - @Req() req: Request, - @Param('apikey') apiKey: string, - ): Promise { - return await this.apiKeyService.getApiKey(req.user as User, apiKey); - } - - @ApiOperation({ summary: 'Update Apikey' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Patch('/:apikey') - @ApiOkResponse({ type: ApiKeyResponseDto }) - async updateApikey( - @Req() req: Request, - @Param('apikey') apiKey: string, - @Body() body: UpdateApiKeyDto, - ): Promise { - body.apiKey = apiKey; - return await this.apiKeyService.updateApikey(req.user as User, body); - } - - @ApiOperation({ summary: 'Delete Apikey' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Delete('/:apikey') - @ApiOkResponse({ type: DeleteApiKeyResponseDto }) - async deleteApikey( - @Req() req: Request, - @Param('apikey') apiKey: string, - ): Promise { - return await this.apiKeyService.deleteApikey(req.user as User, apiKey); - } - - @ApiOperation({ summary: 'List Apikey' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Get('') - @ApiOkResponse({ type: [ApiKeyResponseDto] }) - async listApikey( - @Req() req: Request, - @Query('projectId') projectId: string, - ): Promise { - return await this.apiKeyService.listApiKeys(req.user as User, projectId); - } -} diff --git a/app/apps/onebox/src/modules/apikey/apikey.module.ts b/app/apps/onebox/src/modules/apikey/apikey.module.ts deleted file mode 100644 index eb8a7bf..0000000 --- a/app/apps/onebox/src/modules/apikey/apikey.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { DatabaseModule } from '@app/database'; -import { Module } from '@nestjs/common'; -import { ApiKeyProviders } from './apikey.provider'; -import { ApiKeyRepository } from './repositories/apikey.repository'; -import { ApiKeyController } from './apikey.controller'; -import { ApikeyService } from './apikey.service'; -import { ProjectModule } from '../project/project.module'; - -@Module({ - imports: [DatabaseModule, ProjectModule], - providers: [...ApiKeyProviders, ApiKeyRepository, ApikeyService], - exports: [...ApiKeyProviders, ApiKeyRepository, ApikeyService], - controllers: [ApiKeyController], -}) -export class ApiKeyModule {} diff --git a/app/apps/onebox/src/modules/apikey/apikey.provider.ts b/app/apps/onebox/src/modules/apikey/apikey.provider.ts deleted file mode 100644 index 7a1052c..0000000 --- a/app/apps/onebox/src/modules/apikey/apikey.provider.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Connection } from 'mongoose'; -import { ApiKeySchema } from './schemas/apikey.schema'; - -export const ApiKeyProviders = [ - { - provide: 'APIKEY_MODEL', - useFactory: (connection: Connection) => - connection.model('ApiKey', ApiKeySchema), - inject: ['DATABASE_CONNECTION'], - }, -]; diff --git a/app/apps/onebox/src/modules/apikey/apikey.service.ts b/app/apps/onebox/src/modules/apikey/apikey.service.ts deleted file mode 100644 index 4178286..0000000 --- a/app/apps/onebox/src/modules/apikey/apikey.service.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { ErrorCode } from '@app/global/global.error'; -import { shortUUID } from '@app/utils/uuidUtils'; -import { Injectable } from '@nestjs/common'; -import { Builder } from 'builder-pattern'; -import { ProjectService } from '../project/project.service'; -import { User } from '../users/schemas/user.schema'; -import { - ApiKeyResponseDto, - CreateApiKeyDto, - DeleteApiKeyResponseDto, - UpdateApiKeyDto, -} from './dto/apikey.dto'; -import { ApiKeyRepository } from './repositories/apikey.repository'; -import { ApiKey, ApiKeyStatus } from './schemas/apikey.schema'; - -@Injectable() -export class ApikeyService { - constructor( - private readonly apiKeyRepository: ApiKeyRepository, - private readonly projectService: ProjectService, - ) {} - - async createApiKey( - user: User, - request: CreateApiKeyDto, - ): Promise { - const member = await this.projectService.checkProjectPermission( - user, - request.projectId, - ); - - const apiKey = Builder() - .apiKey(shortUUID(32)) - .userId(member.userId) - .projectId(member.projectId) - .name(request.name) - .description(request.description) - .status(ApiKeyStatus.ENABLE) - .dateCreated(new Date()) - .build(); - await this.apiKeyRepository.saveApiKey(apiKey); - return ApiKeyResponseDto.from(apiKey); - } - - async updateApikey( - user: User, - request: UpdateApiKeyDto, - ): Promise { - const apiKey = await this.apiKeyRepository.findByApiKey(request.apiKey); - if (!apiKey) { - throw ErrorCode.APIKEY_NOT_FOUND.asException(); - } - - const member = await this.projectService.checkProjectPermission( - user, - apiKey.projectId, - ); - - const updateMap = new Map(); - if (request.name) { - updateMap['name'] = request.name; - } - if (request.description) { - updateMap['description'] = request.description; - } - if (request.status) { - updateMap['status'] = request.status; - } - const updatedApikey = await this.apiKeyRepository.updateApiKey( - apiKey.apiKey, - updateMap, - ); - return ApiKeyResponseDto.from(updatedApikey); - } - - async deleteApikey( - user: User, - apiKeyId: string, - ): Promise { - const apiKey = await this.apiKeyRepository.findByApiKey(apiKeyId); - if (!apiKey) { - throw ErrorCode.APIKEY_NOT_FOUND.asException(); - } - - const member = await this.projectService.checkProjectPermission( - user, - apiKey.projectId, - ); - - await this.apiKeyRepository.deleteApiKey(apiKey.apiKey); - - return Builder().success(true).build(); - } - - async getApiKey(user: User, apiKeyId: string): Promise { - const apiKey = await this.apiKeyRepository.findByApiKey(apiKeyId); - if (!apiKey) { - throw ErrorCode.APIKEY_NOT_FOUND.asException(); - } - - const member = await this.projectService.checkProjectPermission( - user, - apiKey.projectId, - ); - return ApiKeyResponseDto.from(apiKey); - } - - async listApiKeys( - user: User, - projectId: string, - ): Promise { - const member = await this.projectService.checkProjectPermission( - user, - projectId, - ); - const apiKeys = await this.apiKeyRepository.listByProjectId(projectId); - return apiKeys.map((apiKey) => ApiKeyResponseDto.from(apiKey)); - } -} diff --git a/app/apps/onebox/src/modules/apikey/dto/apikey.dto.ts b/app/apps/onebox/src/modules/apikey/dto/apikey.dto.ts deleted file mode 100644 index 91569b8..0000000 --- a/app/apps/onebox/src/modules/apikey/dto/apikey.dto.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { ApiProperty, ApiResponseProperty } from '@nestjs/swagger'; -import { Builder } from 'builder-pattern'; -import { ApiKey, ApiKeyStatus } from '../schemas/apikey.schema'; - -export class CreateApiKeyDto { - @ApiProperty() - projectId: string; - - @ApiProperty() - name: string; - - @ApiProperty() - description: string; -} - -export class ApiKeyResponseDto { - @ApiResponseProperty() - apiKey: string; - - @ApiResponseProperty() - projectId: string; - - @ApiResponseProperty() - name: string; - - @ApiResponseProperty() - description: string; - - @ApiResponseProperty({ type: 'enum', enum: ApiKeyStatus }) - status: ApiKeyStatus; - - @ApiResponseProperty() - dateCreated: Date; - - static from(apiKey: ApiKey): ApiKeyResponseDto { - return Builder() - .apiKey(apiKey.apiKey) - .projectId(apiKey.projectId) - .name(apiKey.name) - .description(apiKey.description) - .status(apiKey.status) - .dateCreated(apiKey.dateCreated) - .build(); - } -} - -export class UpdateApiKeyDto { - apiKey: string; - - @ApiProperty() - name: string; - - @ApiProperty() - description: string; - - @ApiProperty({ type: 'enum', enum: ApiKeyStatus }) - status: ApiKeyStatus; -} - -export class DeleteApiKeyResponseDto { - @ApiResponseProperty() - success: boolean; -} diff --git a/app/apps/onebox/src/modules/apikey/repositories/apikey.repository.ts b/app/apps/onebox/src/modules/apikey/repositories/apikey.repository.ts deleted file mode 100644 index e7bbfab..0000000 --- a/app/apps/onebox/src/modules/apikey/repositories/apikey.repository.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Inject, Injectable } from '@nestjs/common'; -import { Model } from 'mongoose'; -import { ApiKey, ApiKeyStatus } from '../schemas/apikey.schema'; - -@Injectable() -export class ApiKeyRepository { - constructor( - @Inject('APIKEY_MODEL') private readonly apiKeyModel: Model, - ) {} - - async findByApiKey(apiKey: string): Promise { - return await this.apiKeyModel.findOne({ apiKey }); - } - - async listByProjectId(projectId: string): Promise { - return await this.apiKeyModel.find({ projectId }); - } - - async saveApiKey(apiKey: ApiKey): Promise { - return new this.apiKeyModel(apiKey).save(); - } - - async updateStatus(apiKey: string, status: ApiKeyStatus): Promise { - return await this.apiKeyModel.findOneAndUpdate( - { apiKey }, - { status }, - { new: true }, - ); - } - - async updateApiKey( - apiKey: string, - updateMap: Map, - ): Promise { - return this.apiKeyModel - .findOneAndUpdate( - { apiKey: apiKey }, - { - $set: { - ...updateMap, - }, - }, - { - new: true, - }, - ) - .exec(); - } - - async deleteApiKey(apiKey: string): Promise { - return await this.apiKeyModel.findOneAndDelete({ apiKey }); - } -} diff --git a/app/apps/onebox/src/modules/apikey/schemas/apikey.schema.ts b/app/apps/onebox/src/modules/apikey/schemas/apikey.schema.ts deleted file mode 100644 index 2225093..0000000 --- a/app/apps/onebox/src/modules/apikey/schemas/apikey.schema.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; -import { User } from 'apps/onebox/src/modules/users/schemas/user.schema'; -import { Builder } from 'builder-pattern'; -import { HydratedDocument } from 'mongoose'; - -export enum ApiKeyStatus { - ENABLE = 'ENABLE', - DISABLE = 'DISABLE', -} - -@Schema() -export class ApiKey { - @Prop({ required: true, unique: true }) - apiKey: string; - - @Prop({ required: true, index: 1 }) - userId: string; - - @Prop({ required: true, index: 1 }) - projectId: string; - - @Prop() - name: string; - - @Prop() - description: string; - - @Prop() - status: ApiKeyStatus; - - @Prop() - dateCreated: Date; -} -export type ApiKeyDocument = HydratedDocument; -export const ApiKeySchema = SchemaFactory.createForClass(ApiKey); - -export class ApiKeyUser extends User { - apiKey: string; - projectId: string; - - static from(user: User, apiKey: ApiKey): ApiKeyUser { - return Builder() - .userId(user.userId) - .email(user.email) - .name(user.name) - .country(user.country) - .dateCreated(user.dateCreated) - .enableEmailUpdate(user.enableEmailUpdate) - .language(user.language) - .status(user.status) - .apiKey(apiKey.apiKey) - .projectId(apiKey.projectId) - .build(); - } -} diff --git a/app/apps/onebox/src/modules/auth/auth.controller.ts b/app/apps/onebox/src/modules/auth/auth.controller.ts deleted file mode 100644 index 36cf3b4..0000000 --- a/app/apps/onebox/src/modules/auth/auth.controller.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { - Body, - Controller, - HttpCode, - Post, - Req, - UseGuards, -} from '@nestjs/common'; -import { ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger'; -import { Request } from 'express'; -import { User } from '../users/schemas/user.schema'; -import { AuthService } from './auth.service'; -import { ActivateDto } from './dto/activate.dto'; -import { LoginDto, LoginEmailDto, LoginWithTokenDto } from './dto/login.dto'; -import { - LoginEmailResponseDto, - LoginResponseDto, -} from './dto/login.reponse.dto'; -import { LocalAuthGuard } from './guards/local-auth.guard'; - -@ApiTags('Auth') -@Controller('auth') -export class AuthController { - constructor(private authService: AuthService) {} - - @ApiOperation({ summary: 'Login' }) - @UseGuards(LocalAuthGuard) - @Post('login') - @HttpCode(200) - @ApiOkResponse({ type: LoginResponseDto }) - async login( - @Req() req: Request, - @Body() body: LoginDto, - ): Promise { - return this.authService.login(req.user as User); - } - - @ApiOperation({ summary: 'Login Using Email only' }) - @Post('login-email') - @HttpCode(200) - @ApiOkResponse({ type: LoginEmailResponseDto }) - async loginWithEmail( - @Req() req: Request, - @Body() body: LoginEmailDto, - ): Promise { - return this.authService.loginWithEmail(body); - } - - @ApiOperation({ summary: 'Login Using Token' }) - @Post('login-token') - @HttpCode(200) - @ApiOkResponse({ type: LoginResponseDto }) - async loginWithToken( - @Req() req: Request, - @Body() body: LoginWithTokenDto, - ): Promise { - return this.authService.loginWithToken(body); - } - - @ApiOperation({ summary: 'Activate account' }) - @Post('activate') - @HttpCode(200) - @ApiOkResponse({ type: LoginResponseDto }) - async activateAccount( - @Req() req: Request, - @Body() body: ActivateDto, - ): Promise { - return this.authService.activateAccount(body); - } -} diff --git a/app/apps/onebox/src/modules/auth/auth.module.ts b/app/apps/onebox/src/modules/auth/auth.module.ts deleted file mode 100644 index 97417e7..0000000 --- a/app/apps/onebox/src/modules/auth/auth.module.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Module } from '@nestjs/common'; -import { JwtModule } from '@nestjs/jwt'; -import { PassportModule } from '@nestjs/passport'; -import { UsersModule } from '../users/users.module'; -import { AuthController } from './auth.controller'; -import { AuthService } from './auth.service'; -import { JwtStrategy } from './strategies/jwt.strategy'; -import { LocalStrategy } from './strategies/local.strategy'; -import { DatabaseModule } from '@app/database'; -import { UsersProviders } from '../users/users.providers'; - -@Module({ - imports: [ - JwtModule.registerAsync({ - useFactory: () => ({ - global: true, - secret: process.env.JWT_SECRET_KEY, - signOptions: { expiresIn: '30 days' }, - }), - }), - UsersModule, - PassportModule, - DatabaseModule, - ], - controllers: [AuthController], - providers: [AuthService, LocalStrategy, JwtStrategy, ...UsersProviders], - exports: [AuthService], -}) -export class AuthModule {} diff --git a/app/apps/onebox/src/modules/auth/auth.service.ts b/app/apps/onebox/src/modules/auth/auth.service.ts deleted file mode 100644 index 3be3da7..0000000 --- a/app/apps/onebox/src/modules/auth/auth.service.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { ErrorCode } from '@app/global/global.error'; -import { comparePassword } from '@app/utils/bcrypt.util'; -import { sendEmail } from '@app/utils/email.sender'; -import { renderTemplate } from '@app/utils/file-template'; -import { generateUUID } from '@app/utils/uuidUtils'; -import { Inject, Injectable } from '@nestjs/common'; -import { JwtService } from '@nestjs/jwt'; -import { Builder } from 'builder-pattern'; -import { Model } from 'mongoose'; -import { User, UserStatus } from '../users/schemas/user.schema'; -import { UsersService } from '../users/users.service'; -import { ActivateDto } from './dto/activate.dto'; -import { LoginEmailDto, LoginWithTokenDto } from './dto/login.dto'; -import { - LoginEmailResponseDto, - LoginResponseDto, -} from './dto/login.reponse.dto'; - -@Injectable() -export class AuthService { - constructor( - @Inject('USER_MODEL') private readonly userModel: Model, - private usersService: UsersService, - private jwtService: JwtService, - ) {} - - async validateUser(email: string, pass: string): Promise { - const user = await this.usersService.findOne(email); - if (!user || !user.password) { - throw ErrorCode.WRONG_EMAIL_OR_PASSWORD.asException(); - } - if (!(await comparePassword(pass, user.password))) { - throw ErrorCode.WRONG_EMAIL_OR_PASSWORD.asException(); - } - if (user.status && user.status !== UserStatus.Active) { - throw ErrorCode.ACCOUNT_NOT_ACTIVE.asException(); - } - return user; - } - - async login(user: User): Promise { - const payload = { - userId: user.userId, - email: user.email, - token: user.passwordHash, - }; - return new LoginResponseDto(this.jwtService.sign(payload)); - } - - async loginWithEmail(request: LoginEmailDto): Promise { - const user = await this.usersService.findOne(request.email.toLowerCase()); - if (!user) { - throw ErrorCode.ACCOUNT_NOT_FOUND.asException(); - } - - if (user.status && user.status !== UserStatus.Active) { - throw ErrorCode.ACCOUNT_NOT_ACTIVE.asException(); - } - - const loginToken = generateUUID(); - const tokenExpire = Date.now() + 5 * 60 * 1000; // 5 minutes - await this.userModel.updateOne( - { userId: user.userId }, - { - emailLogin: { - token: loginToken, - expire: tokenExpire, - }, - }, - ); - const encodedToken = Buffer.from(`${user.email}:${loginToken}`).toString( - 'base64', - ); - const linkEmailLogin = `https://${process.env.WEB_DOMAIN}/token-login?token=${encodedToken}`; - const emailBody = await renderTemplate( - 'resources/email_template/token_login.html', - { - linkEmailLogin, - expire: new Date(tokenExpire).toUTCString(), - }, - ); - sendEmail(user.email, 'Login Confirmation', emailBody); - return Builder().success(true).build(); - } - - async loginWithToken(request: LoginWithTokenDto): Promise { - const decodedToken = Buffer.from(request.token, 'base64').toString(); - const [email, loginToken] = decodedToken.split(':'); - const user = await this.usersService.findOne(email); - if (!user || !user.emailLogin) { - throw ErrorCode.WRONG_EMAIL_OR_TOKEN.asException(); - } - if (user.emailLogin.token !== loginToken) { - throw ErrorCode.WRONG_EMAIL_OR_TOKEN.asException(); - } - if (user.emailLogin.expire < Date.now()) { - throw ErrorCode.WRONG_EMAIL_OR_TOKEN.asException(); - } - await this.userModel.updateOne( - { userId: user.userId }, - { - $unset: { emailLogin: '' }, - }, - ); - return this.login(user); - } - - async activateAccount(request: ActivateDto): Promise { - const user = await this.usersService.activateAccount(request.token); - return this.login(user); - } -} diff --git a/app/apps/onebox/src/modules/auth/constants.ts b/app/apps/onebox/src/modules/auth/constants.ts deleted file mode 100644 index 7f8dc88..0000000 --- a/app/apps/onebox/src/modules/auth/constants.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const jwtConstants = { - secret: process.env.SECRET_KEY, -}; diff --git a/app/apps/onebox/src/modules/auth/dto/activate.dto.ts b/app/apps/onebox/src/modules/auth/dto/activate.dto.ts deleted file mode 100644 index 1b06868..0000000 --- a/app/apps/onebox/src/modules/auth/dto/activate.dto.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; - -export class ActivateDto { - @ApiProperty() - token: string; -} diff --git a/app/apps/onebox/src/modules/auth/dto/login.dto.ts b/app/apps/onebox/src/modules/auth/dto/login.dto.ts deleted file mode 100644 index 098ff4c..0000000 --- a/app/apps/onebox/src/modules/auth/dto/login.dto.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { IsEmail, IsNotEmpty, IsString } from 'class-validator'; - -export class LoginDto { - @ApiProperty() - @IsString() - @IsEmail() - @IsNotEmpty() - email: string; - - @ApiProperty() - @IsString() - @IsNotEmpty() - password: string; -} - -export class LoginEmailDto { - @ApiProperty() - @IsString() - @IsEmail() - @IsNotEmpty() - email: string; -} - -export class LoginWithTokenDto { - @ApiProperty() - @IsString() - @IsNotEmpty() - token: string; -} diff --git a/app/apps/onebox/src/modules/auth/dto/login.reponse.dto.ts b/app/apps/onebox/src/modules/auth/dto/login.reponse.dto.ts deleted file mode 100644 index 2aaad3d..0000000 --- a/app/apps/onebox/src/modules/auth/dto/login.reponse.dto.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { ApiResponseProperty } from '@nestjs/swagger'; - -export class LoginResponseDto { - @ApiResponseProperty() - accessToken: string; - constructor(accessToken: string) { - this.accessToken = accessToken; - } -} - -export class LoginEmailResponseDto { - @ApiResponseProperty() - success: boolean; -} diff --git a/app/apps/onebox/src/modules/auth/guards/jwt-auth.guard.ts b/app/apps/onebox/src/modules/auth/guards/jwt-auth.guard.ts deleted file mode 100644 index 2155290..0000000 --- a/app/apps/onebox/src/modules/auth/guards/jwt-auth.guard.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { AuthGuard } from '@nestjs/passport'; - -@Injectable() -export class JwtAuthGuard extends AuthGuard('jwt') {} diff --git a/app/apps/onebox/src/modules/auth/guards/local-auth.guard.ts b/app/apps/onebox/src/modules/auth/guards/local-auth.guard.ts deleted file mode 100644 index ccf962b..0000000 --- a/app/apps/onebox/src/modules/auth/guards/local-auth.guard.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { AuthGuard } from '@nestjs/passport'; - -@Injectable() -export class LocalAuthGuard extends AuthGuard('local') {} diff --git a/app/apps/onebox/src/modules/auth/strategies/jwt.strategy.ts b/app/apps/onebox/src/modules/auth/strategies/jwt.strategy.ts deleted file mode 100644 index 29d0a48..0000000 --- a/app/apps/onebox/src/modules/auth/strategies/jwt.strategy.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ErrorCode } from '@app/global/global.error'; -import { Injectable } from '@nestjs/common'; -import { PassportStrategy } from '@nestjs/passport'; -import { ExtractJwt, Strategy } from 'passport-jwt'; -import { UsersService } from '../../users/users.service'; - -@Injectable() -export class JwtStrategy extends PassportStrategy(Strategy) { - constructor(private usersService: UsersService) { - super({ - jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), - ignoreExpiration: false, - secretOrKey: process.env.JWT_SECRET_KEY, - }); - } - - async validate(payload: any) { - const user = await this.usersService.findOneByUserId(payload.userId); - if (!user) { - throw ErrorCode.UNAUTHORIZED.asException(); - } - if (user.passwordHash !== payload.token) { - throw ErrorCode.UNAUTHORIZED.asException(); - } - return user; - } -} diff --git a/app/apps/onebox/src/modules/auth/strategies/local.strategy.ts b/app/apps/onebox/src/modules/auth/strategies/local.strategy.ts deleted file mode 100644 index 6c4a402..0000000 --- a/app/apps/onebox/src/modules/auth/strategies/local.strategy.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { ErrorCode } from '@app/global/global.error'; -import { Injectable } from '@nestjs/common'; -import { PassportStrategy } from '@nestjs/passport'; -import { Strategy } from 'passport-local'; -import { AuthService } from '../auth.service'; - -@Injectable() -export class LocalStrategy extends PassportStrategy(Strategy) { - constructor(private authService: AuthService) { - super({ - usernameField: 'email', - }); - } - - async validate(email: string, password: string): Promise { - const user = await this.authService.validateUser(email, password); - if (!user) { - throw ErrorCode.UNAUTHORIZED.asException(); - } - return user; - } -} diff --git a/app/apps/onebox/src/modules/blocksync/blocksync.controller.ts b/app/apps/onebox/src/modules/blocksync/blocksync.controller.ts deleted file mode 100644 index daf806a..0000000 --- a/app/apps/onebox/src/modules/blocksync/blocksync.controller.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { BadRequestException, Body, Controller, Post } from '@nestjs/common'; -import { - BlockSync, - BlockSyncRepository, - CreateBlockSyncDto, - DeleteBlockSyncDto, -} from 'libs'; - -@Controller('blocksync') -export class BlockSyncController { - constructor(private blockSyncRepository: BlockSyncRepository) {} - - @Post('/create') - async create(@Body() blockSync: CreateBlockSyncDto) { - try { - const result: InstanceType = - await this.blockSyncRepository.create(blockSync); - - return result; - } catch (error) { - if (error.hasOwnProperty('code')) { - if (error.name === 'MongoServerError' && error.code === 11000) { - throw new BadRequestException({ - error: { - rpcUrl: { - notUnique: 'rpcUrl is already in use by a different id', - }, - }, - }); - } - } - - throw new BadRequestException( - { - error: error, - }, - 'Bad request', - ); - } - } - - @Post('/remove') - async remove(@Body() blockSync: DeleteBlockSyncDto) { - try { - await this.blockSyncRepository.deleteOne(blockSync.rpcUrl); - } catch (error) { - if (error.hasOwnProperty('code')) { - if (error.name === 'MongoServerError' && error.code === 11000) { - throw new BadRequestException({ - error: { - rpcUrl: { - notUnique: 'rpcUrl is already in use by a different id', - }, - }, - }); - } - } - - throw new BadRequestException( - { - error: error, - }, - 'Bad request', - ); - } - } -} diff --git a/app/apps/onebox/src/modules/blocksync/blocksync.module.ts b/app/apps/onebox/src/modules/blocksync/blocksync.module.ts deleted file mode 100644 index fb1a5ca..0000000 --- a/app/apps/onebox/src/modules/blocksync/blocksync.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { DatabaseModule } from '@app/database'; -import { Module } from '@nestjs/common'; -import { BlockSyncModelModule, BlockSyncProviders } from 'libs'; -import { BlockSyncController } from './blocksync.controller'; -@Module({ - controllers: [BlockSyncController], - providers: [...BlockSyncProviders], - exports: [], - imports: [DatabaseModule, BlockSyncModelModule], -}) -export class BlockSyncModule {} diff --git a/app/apps/onebox/src/modules/delivery/delivery.controller.ts b/app/apps/onebox/src/modules/delivery/delivery.controller.ts deleted file mode 100644 index ba20fa5..0000000 --- a/app/apps/onebox/src/modules/delivery/delivery.controller.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Controller, Get, Query, Req, UseGuards } from '@nestjs/common'; -import { - ApiBearerAuth, - ApiOkResponse, - ApiOperation, - ApiTags, -} from '@nestjs/swagger'; -import { Request } from 'express'; -import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; -import { User } from '../users/schemas/user.schema'; -import { DeliveryService } from './delivery.service'; -import { - DeliveryAttemptResponseDto, - GetMonitorDeliveryDto, - MonitorDeliveryResponseDto, -} from './dto/delivery.dto'; - -@ApiTags('Monitor Delivery') -@Controller('/delivery') -export class DeliveryController { - constructor(private readonly deliveryService: DeliveryService) {} - - @ApiOperation({ summary: 'Get Monitor Deliveries' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Get('') - @ApiOkResponse({ type: [MonitorDeliveryResponseDto] }) - async getMonitorDeliveries( - @Req() req: Request, - @Query() body: GetMonitorDeliveryDto, - ): Promise { - return await this.deliveryService.getMonitorDeliveries( - req.user as User, - body, - ); - } - - @ApiOperation({ summary: 'Get Delivery Attempts' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Get('/attempts') - @ApiOkResponse({ type: [DeliveryAttemptResponseDto] }) - async getDeliveryAttempts( - @Req() req: Request, - @Query('deliveryId') deliveryId: string, - ): Promise { - return await this.deliveryService.getDeliveryAttempt( - req.user as User, - deliveryId, - ); - } -} diff --git a/app/apps/onebox/src/modules/delivery/delivery.module.ts b/app/apps/onebox/src/modules/delivery/delivery.module.ts deleted file mode 100644 index bedcbe7..0000000 --- a/app/apps/onebox/src/modules/delivery/delivery.module.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MonitorModule as MonitorModelModule } from '@app/shared_modules/monitor/monitor.module'; -import { ProjectModule as ProjectModelModule } from '@app/shared_modules/project/project.module'; -import { WebhookModule } from '@app/shared_modules/webhook/webhook.module'; -import { Module } from '@nestjs/common'; -import { MonitorModule } from '../monitor/monitor.module'; -import { ProjectModule } from '../project/project.module'; -import { DeliveryController } from './delivery.controller'; -import { DeliveryService } from './delivery.service'; -@Module({ - controllers: [DeliveryController], - providers: [DeliveryService], - exports: [DeliveryService], - imports: [ - WebhookModule, - ProjectModelModule, - MonitorModelModule, - ProjectModule, - MonitorModule, - ], -}) -export class DeliveryModule {} diff --git a/app/apps/onebox/src/modules/delivery/delivery.service.ts b/app/apps/onebox/src/modules/delivery/delivery.service.ts deleted file mode 100644 index b8c7e87..0000000 --- a/app/apps/onebox/src/modules/delivery/delivery.service.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { WebhookService } from '@app/shared_modules/webhook/webhook.service'; -import { Injectable } from '@nestjs/common'; -import { MonitorService } from '../monitor/monitor.service'; -import { User } from '../users/schemas/user.schema'; -import { - DeliveryAttemptResponseDto, - GetMonitorDeliveryDto, - MonitorDeliveryResponseDto, -} from './dto/delivery.dto'; - -@Injectable() -export class DeliveryService { - constructor( - private readonly webhookService: WebhookService, - private readonly monitorService: MonitorService, - ) {} - - async getMonitorDeliveries( - user: User, - request: GetMonitorDeliveryDto, - ): Promise { - const monitor = await this.monitorService.findAndAuthMonitor( - user, - request.monitorId, - ); - - return this.webhookService - .getDeliveries( - monitor.webhookId, - request.limit, - request.offset, - request.status, - ) - .then((response) => { - return response.deliveries.map((delivery) => - MonitorDeliveryResponseDto.from(delivery), - ); - }); - } - - async getDeliveryAttempt( - user: User, - deliveryId: string, - ): Promise { - return this.webhookService - .getDeliveryAttempts(deliveryId) - .then((response) => { - return response.delivery_attempts.map((attempt) => - DeliveryAttemptResponseDto.from(attempt), - ); - }); - } -} diff --git a/app/apps/onebox/src/modules/delivery/dto/delivery.dto.ts b/app/apps/onebox/src/modules/delivery/dto/delivery.dto.ts deleted file mode 100644 index ddf0e2a..0000000 --- a/app/apps/onebox/src/modules/delivery/dto/delivery.dto.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { - DeliveryAttemptDto, - DeliveryDto, -} from '@app/shared_modules/webhook/webhook.service'; -import { ApiProperty, ApiResponseProperty } from '@nestjs/swagger'; -import { Builder } from 'builder-pattern'; -import { Transform } from 'class-transformer'; -import { IsNotEmpty, Max, Min } from 'class-validator'; - -export class GetMonitorDeliveryDto { - @ApiProperty() - @IsNotEmpty() - monitorId: string; - - @ApiProperty({ required: false }) - status?: 'succeeded' | 'pending' | 'failed'; - - @ApiProperty({ default: 10 }) - @Max(10) - @Min(1) - @Transform(({ value }) => parseInt(value)) - limit: number; - - @ApiProperty({ default: 0 }) - @Min(0) - @Transform(({ value }) => parseInt(value)) - offset: number; -} - -export class MonitorDeliveryResponseDto { - @ApiResponseProperty() - id: string; - - @ApiResponseProperty() - payload: string; - - @ApiResponseProperty() - status: string; - - @ApiResponseProperty() - attempts: number; - - @ApiResponseProperty() - dateScheduled: string; - - @ApiResponseProperty() - dateCreated: string; - - @ApiResponseProperty() - dateUpdated: string; - - static from(dto: DeliveryDto): MonitorDeliveryResponseDto { - return Builder() - .id(dto.id) - .payload(dto.payload) - .status(dto.status) - .attempts(dto.delivery_attempts) - .dateScheduled(dto.scheduled_at) - .dateCreated(dto.created_at) - .dateUpdated(dto.updated_at) - .build(); - } -} - -export class DeliveryAttemptResponseDto { - @ApiResponseProperty() - id: string; - - @ApiResponseProperty() - deliveryId: string; - - @ApiResponseProperty() - request: string; - - @ApiResponseProperty() - response: string; - - @ApiResponseProperty() - responseStatusCode: number; - - @ApiResponseProperty() - executionDuration: number; - - @ApiResponseProperty() - success: boolean; - - @ApiResponseProperty() - error: string; - - @ApiResponseProperty() - dateCreated: string; - - static from(dto: DeliveryAttemptDto): DeliveryAttemptResponseDto { - return Builder() - .id(dto.id) - .deliveryId(dto.delivery_id) - .request(dto.raw_request) - .response(dto.raw_response) - .responseStatusCode(dto.response_status_code) - .executionDuration(dto.execution_duration) - .success(dto.success) - .error(dto.error) - .dateCreated(dto.created_at) - .build(); - } -} diff --git a/app/apps/onebox/src/modules/event_history/dto/event_history.dto.ts b/app/apps/onebox/src/modules/event_history/dto/event_history.dto.ts deleted file mode 100644 index 30694eb..0000000 --- a/app/apps/onebox/src/modules/event_history/dto/event_history.dto.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { - EventHistory, - WebhookCategory, - WebhookType, -} from '@app/shared_modules/event_history/schemas/event_history.schema'; -import { ApiProperty, ApiResponseProperty } from '@nestjs/swagger'; -import { Builder } from 'builder-pattern'; -import { Transform } from 'class-transformer'; -import { IsNotEmpty, Max, Min } from 'class-validator'; - -export class GetMonitorEventHistoryDto { - @ApiProperty({ required: true }) - @IsNotEmpty() - monitorId: string; - - // @ApiProperty({ required: false }) - // status?: 'succeeded' | 'pending' | 'failed'; - - @ApiProperty({ default: 10 }) - @Max(10) - @Min(1) - @Transform(({ value }) => parseInt(value)) - limit: number; - - @ApiProperty({ default: 0 }) - @Min(0) - @Transform(({ value }) => parseInt(value)) - offset: number; -} - -export class GetMonitorEventHistoryByAssociatedAddressDto extends GetMonitorEventHistoryDto { - @ApiProperty({ required: true }) - @IsNotEmpty() - associatedAddress: string; -} - -export class GetMonitorEventHistoryByHashDto extends GetMonitorEventHistoryDto { - @ApiProperty({ required: true }) - @IsNotEmpty() - hash: string; -} - -export class GetMonitorEventHistoryByEventIdDto { - @ApiProperty({ required: true }) - @IsNotEmpty() - monitorId: string; - - @ApiProperty({ required: true }) - @IsNotEmpty() - eventId: string; -} - -export class MonitorEventHistoryResponseDto { - @ApiResponseProperty() - eventId: string; // md5 of message exclude timestamp and confirm - - @ApiResponseProperty() - chain: string; - - @ApiResponseProperty() - monitorId: string; - - @ApiResponseProperty() - associatedAddress: string; - - @ApiResponseProperty() - hash: string; - - @ApiResponseProperty() - blockNumber: number; // decimal string - - @ApiResponseProperty() - contract: { - address: string; - name: string; - symbol: string; - }; - - @ApiResponseProperty() - fromAddress: string; - - @ApiResponseProperty() - toAddress: string; - - @ApiResponseProperty() - tokenId: string; // decimal string - - @ApiResponseProperty() - tokenValue: string; // decimal string - - @ApiResponseProperty() - nativeAmount: string; // decimal string - - @ApiResponseProperty() - type: WebhookType; - - @ApiResponseProperty() - confirm: boolean; - - @ApiResponseProperty() - category: WebhookCategory; - - @ApiResponseProperty() - rawLog: { - topics: string[]; - data: string; - }; - - @ApiResponseProperty() - logIndex: number; - - @ApiResponseProperty() - txnIndex: number; - - @ApiResponseProperty() - tags: string[]; - - @ApiResponseProperty() - dateCreated: Date; - - @ApiResponseProperty() - deliveryIds: string[]; - - static from(dto: EventHistory): MonitorEventHistoryResponseDto { - return Builder() - .eventId(dto.eventId) - .chain(dto.chain) - .monitorId(dto.monitorId) - .associatedAddress(dto.associatedAddress) - .hash(dto.hash) - .blockNumber(dto.blockNumber) - .contract(dto.contract) - .fromAddress(dto.fromAddress) - .toAddress(dto.toAddress) - .tokenId(dto.tokenId) - .tokenValue(dto.tokenValue) - .nativeAmount(dto.nativeAmount) - .type(dto.type) - .confirm(dto.confirm) - .category(dto.category) - .rawLog(dto.rawLog) - .logIndex(dto.logIndex) - .txnIndex(dto.txnIndex) - .tags(dto.tags) - .dateCreated(dto.dateCreated) - .deliveryIds(dto.deliveryIds) - .build(); - } -} diff --git a/app/apps/onebox/src/modules/event_history/event_history.controller.ts b/app/apps/onebox/src/modules/event_history/event_history.controller.ts deleted file mode 100644 index 087427b..0000000 --- a/app/apps/onebox/src/modules/event_history/event_history.controller.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { Controller, Get, Query, Req, UseGuards } from '@nestjs/common'; -import { - ApiBearerAuth, - ApiOkResponse, - ApiOperation, - ApiTags, -} from '@nestjs/swagger'; -import { Request } from 'express'; -import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; -import { User } from '../users/schemas/user.schema'; -import { - GetMonitorEventHistoryByAssociatedAddressDto, - GetMonitorEventHistoryByEventIdDto, - GetMonitorEventHistoryByHashDto, - GetMonitorEventHistoryDto, - MonitorEventHistoryResponseDto, -} from './dto/event_history.dto'; -import { EventHistoryService } from './event_history.service'; - -@ApiTags('Monitor Event History') -@Controller('/event') -export class EventHistoryController { - constructor(private readonly eventHistoryService: EventHistoryService) {} - - @ApiOperation({ summary: 'Get Monitor Event' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Get('') - @ApiOkResponse({ type: [MonitorEventHistoryResponseDto] }) - async getMonitorEvent( - @Req() req: Request, - @Query() body: GetMonitorEventHistoryDto, - ): Promise { - return await this.eventHistoryService.getMonitorEventHistory( - req.user as User, - body, - ); - } - - @ApiOperation({ summary: 'Get Monitor Event History By Transaction Hash' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Get('by-hash') - @ApiOkResponse({ type: [MonitorEventHistoryResponseDto] }) - async getMonitorEventHistoryByTxnHash( - @Req() req: Request, - @Query() body: GetMonitorEventHistoryByHashDto, - ): Promise { - return await this.eventHistoryService.getMonitorEventHistoryByTxnHash( - req.user as User, - body, - ); - } - - @ApiOperation({ summary: 'Get Monitor Event History By Event Id' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Get('by-event-id') - @ApiOkResponse({ type: [MonitorEventHistoryResponseDto] }) - async getMonitorEventHistoryByEventId( - @Req() req: Request, - @Query() body: GetMonitorEventHistoryByEventIdDto, - ): Promise { - return await this.eventHistoryService.getMonitorEventHistoryByEventId( - req.user as User, - body, - ); - } - - @ApiOperation({ summary: 'Get Monitor Event History By Associated Address' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Get('by-address') - @ApiOkResponse({ type: [MonitorEventHistoryResponseDto] }) - async getMonitorEventHistoryByAssociatedAddress( - @Req() req: Request, - @Query() body: GetMonitorEventHistoryByAssociatedAddressDto, - ): Promise { - return await this.eventHistoryService.getMonitorEventHistoryByAssociatedAddress( - req.user as User, - body, - ); - } -} diff --git a/app/apps/onebox/src/modules/event_history/event_history.module.ts b/app/apps/onebox/src/modules/event_history/event_history.module.ts deleted file mode 100644 index 316b943..0000000 --- a/app/apps/onebox/src/modules/event_history/event_history.module.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { EventHistoryModelModule } from '@app/shared_modules/event_history/event_history.module'; -import { Module } from '@nestjs/common'; -import { MonitorModule } from '../monitor/monitor.module'; -import { EventHistoryController } from './event_history.controller'; -import { EventHistoryService } from './event_history.service'; -@Module({ - controllers: [EventHistoryController], - providers: [EventHistoryService], - exports: [EventHistoryService], - imports: [EventHistoryModelModule, MonitorModule], -}) -export class EventHistoryModule {} diff --git a/app/apps/onebox/src/modules/event_history/event_history.service.ts b/app/apps/onebox/src/modules/event_history/event_history.service.ts deleted file mode 100644 index 9c246af..0000000 --- a/app/apps/onebox/src/modules/event_history/event_history.service.ts +++ /dev/null @@ -1,334 +0,0 @@ -import { ErrorCode } from '@app/global/global.error'; -import { - AvaxEventHistoryRepository, - BscEventHistoryRepository, - EthEventHistoryRepository, - MantleEventHistoryRepository, - PolygonEventHistoryRepository, -} from '@app/shared_modules/event_history/repositories/event_history.repository'; -import { MonitorNetwork } from '@app/shared_modules/monitor/schemas/monitor.schema'; -import { Injectable, Logger } from '@nestjs/common'; -import { MonitorService } from '../monitor/monitor.service'; -import { User } from '../users/schemas/user.schema'; -import { - GetMonitorEventHistoryByAssociatedAddressDto, - GetMonitorEventHistoryByEventIdDto, - GetMonitorEventHistoryByHashDto, - GetMonitorEventHistoryDto, - MonitorEventHistoryResponseDto, -} from './dto/event_history.dto'; - -@Injectable() -export class EventHistoryService { - private readonly logger = new Logger(EventHistoryService.name); - constructor( - private readonly ethEventHistoryRepository: EthEventHistoryRepository, - private readonly polygonEventHistoryRepository: PolygonEventHistoryRepository, - private readonly avaxEventHistoryRepository: AvaxEventHistoryRepository, - private readonly mantleEventHistoryRepository: MantleEventHistoryRepository, - private readonly bscEventHistoryRepository: BscEventHistoryRepository, - private readonly monitorService: MonitorService, - ) {} - - async getMonitorEventHistory( - user: User, - request: GetMonitorEventHistoryDto, - ): Promise { - const monitor = await this.monitorService.findAndAuthMonitor( - user, - request.monitorId, - ); - - if (!monitor) { - throw ErrorCode.MONITOR_NOT_FOUND.asException(); - } - - if (monitor.network === MonitorNetwork.Ethereum) { - return this.ethEventHistoryRepository - .getEventHistory(monitor.monitorId, request.limit, request.offset) - .then((response) => { - return response.map((event) => - MonitorEventHistoryResponseDto.from(event), - ); - }); - } - - if (monitor.network === MonitorNetwork.Polygon) { - return this.polygonEventHistoryRepository - .getEventHistory(monitor.monitorId, request.limit, request.offset) - .then((response) => { - return response.map((event) => - MonitorEventHistoryResponseDto.from(event), - ); - }); - } - - if (monitor.network === MonitorNetwork.Avalanche) { - return this.avaxEventHistoryRepository - .getEventHistory(monitor.monitorId, request.limit, request.offset) - .then((response) => { - return response.map((event) => - MonitorEventHistoryResponseDto.from(event), - ); - }); - } - - if (monitor.network === MonitorNetwork.Mantle) { - return this.mantleEventHistoryRepository - .getEventHistory(monitor.monitorId, request.limit, request.offset) - .then((response) => { - return response.map((event) => - MonitorEventHistoryResponseDto.from(event), - ); - }); - } - - if (monitor.network === MonitorNetwork.BSC) { - return this.bscEventHistoryRepository - .getEventHistory(monitor.monitorId, request.limit, request.offset) - .then((response) => { - return response.map((event) => - MonitorEventHistoryResponseDto.from(event), - ); - }); - } - - this.logger.error(`network ${monitor.network} not supported`); - throw ErrorCode.INTERNAL_SERVER_ERROR.asException(); - } - - async getMonitorEventHistoryByTxnHash( - user: User, - request: GetMonitorEventHistoryByHashDto, - ): Promise { - const monitor = await this.monitorService.findAndAuthMonitor( - user, - request.monitorId, - ); - - if (!monitor) { - throw ErrorCode.MONITOR_NOT_FOUND.asException(); - } - if (monitor.network === MonitorNetwork.Ethereum) { - return this.ethEventHistoryRepository - .findEventHistoryByMonitorAndHash( - monitor.monitorId, - request.hash, - request.limit, - request.offset, - ) - .then((response) => { - return response.map((event) => - MonitorEventHistoryResponseDto.from(event), - ); - }); - } - if (monitor.network === MonitorNetwork.Polygon) { - return this.polygonEventHistoryRepository - .findEventHistoryByMonitorAndHash( - monitor.monitorId, - request.hash, - request.limit, - request.offset, - ) - .then((response) => { - return response.map((event) => - MonitorEventHistoryResponseDto.from(event), - ); - }); - } - - if (monitor.network === MonitorNetwork.Avalanche) { - return this.avaxEventHistoryRepository - .findEventHistoryByMonitorAndHash( - monitor.monitorId, - request.hash, - request.limit, - request.offset, - ) - .then((response) => { - return response.map((event) => - MonitorEventHistoryResponseDto.from(event), - ); - }); - } - - if (monitor.network === MonitorNetwork.Mantle) { - return this.mantleEventHistoryRepository - .findEventHistoryByMonitorAndHash( - monitor.monitorId, - request.hash, - request.limit, - request.offset, - ) - .then((response) => { - return response.map((event) => - MonitorEventHistoryResponseDto.from(event), - ); - }); - } - - if (monitor.network === MonitorNetwork.BSC) { - return this.bscEventHistoryRepository - .findEventHistoryByMonitorAndHash( - monitor.monitorId, - request.hash, - request.limit, - request.offset, - ) - .then((response) => { - return response.map((event) => - MonitorEventHistoryResponseDto.from(event), - ); - }); - } - - this.logger.error(`network ${monitor.network} not supported`); - throw ErrorCode.INTERNAL_SERVER_ERROR.asException(); - } - - async getMonitorEventHistoryByAssociatedAddress( - user: User, - request: GetMonitorEventHistoryByAssociatedAddressDto, - ): Promise { - const monitor = await this.monitorService.findAndAuthMonitor( - user, - request.monitorId, - ); - - if (!monitor) { - throw ErrorCode.MONITOR_NOT_FOUND.asException(); - } - if (monitor.network === MonitorNetwork.Ethereum) { - return this.ethEventHistoryRepository - .findByMonitorAndAssociatedAddress( - monitor.monitorId, - request.associatedAddress, - request.limit, - request.offset, - ) - .then((response) => { - return response.map((event) => - MonitorEventHistoryResponseDto.from(event), - ); - }); - } - if (monitor.network === MonitorNetwork.Polygon) { - return this.polygonEventHistoryRepository - .findEventHistoryByMonitorAndHash( - monitor.monitorId, - request.associatedAddress, - request.limit, - request.offset, - ) - .then((response) => { - return response.map((event) => - MonitorEventHistoryResponseDto.from(event), - ); - }); - } - - if (monitor.network === MonitorNetwork.Avalanche) { - return this.avaxEventHistoryRepository - .findEventHistoryByMonitorAndHash( - monitor.monitorId, - request.associatedAddress, - request.limit, - request.offset, - ) - .then((response) => { - return response.map((event) => - MonitorEventHistoryResponseDto.from(event), - ); - }); - } - - if (monitor.network === MonitorNetwork.Mantle) { - return this.mantleEventHistoryRepository - .findEventHistoryByMonitorAndHash( - monitor.monitorId, - request.associatedAddress, - request.limit, - request.offset, - ) - .then((response) => { - return response.map((event) => - MonitorEventHistoryResponseDto.from(event), - ); - }); - } - - if (monitor.network === MonitorNetwork.BSC) { - return this.bscEventHistoryRepository - .findEventHistoryByMonitorAndHash( - monitor.monitorId, - request.associatedAddress, - request.limit, - request.offset, - ) - .then((response) => { - return response.map((event) => - MonitorEventHistoryResponseDto.from(event), - ); - }); - } - - this.logger.error(`network ${monitor.network} not supported`); - throw ErrorCode.INTERNAL_SERVER_ERROR.asException(); - } - - async getMonitorEventHistoryByEventId( - user: User, - request: GetMonitorEventHistoryByEventIdDto, - ): Promise { - const monitor = await this.monitorService.findAndAuthMonitor( - user, - request.monitorId, - ); - - if (!monitor) { - throw ErrorCode.MONITOR_NOT_FOUND.asException(); - } - if (monitor.network === MonitorNetwork.Ethereum) { - return this.ethEventHistoryRepository - .findByEventId(request.eventId) - .then((response) => { - return MonitorEventHistoryResponseDto.from(response); - }); - } - if (monitor.network === MonitorNetwork.Polygon) { - return this.polygonEventHistoryRepository - .findByEventId(request.eventId) - .then((response) => { - return MonitorEventHistoryResponseDto.from(response); - }); - } - - if (monitor.network === MonitorNetwork.Avalanche) { - return this.avaxEventHistoryRepository - .findByEventId(request.eventId) - .then((response) => { - return MonitorEventHistoryResponseDto.from(response); - }); - } - - if (monitor.network === MonitorNetwork.Mantle) { - return this.mantleEventHistoryRepository - .findByEventId(request.eventId) - .then((response) => { - return MonitorEventHistoryResponseDto.from(response); - }); - } - - if (monitor.network === MonitorNetwork.BSC) { - return this.bscEventHistoryRepository - .findByEventId(request.eventId) - .then((response) => { - return MonitorEventHistoryResponseDto.from(response); - }); - } - - this.logger.error(`network ${monitor.network} not supported`); - throw ErrorCode.INTERNAL_SERVER_ERROR.asException(); - } -} diff --git a/app/apps/onebox/src/modules/monitor/monitor.controller.ts b/app/apps/onebox/src/modules/monitor/monitor.controller.ts deleted file mode 100644 index 499f020..0000000 --- a/app/apps/onebox/src/modules/monitor/monitor.controller.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { - Body, - Controller, - Delete, - Get, - Param, - Patch, - Post, - Query, - Req, - UseGuards, -} from '@nestjs/common'; -import { - ApiBearerAuth, - ApiCreatedResponse, - ApiOkResponse, - ApiOperation, - ApiTags, -} from '@nestjs/swagger'; -import { Builder } from 'builder-pattern'; -import { Request } from 'express'; -import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; -import { User } from '../users/schemas/user.schema'; -import { - CreateMonitorDto, - DeleteMonitorDto, - DeleteMonitorResponseDto, - ListMonitorDto, - MonitorResponseDto, - UpdateMonitorDto, -} from 'libs/shared_modules/src/monitor/dto/monitor.dto'; -import { MonitorService } from './monitor.service'; - -@ApiTags('Monitor') -@Controller('monitor') -export class MonitorController { - constructor(private readonly monitorService: MonitorService) {} - - @ApiOperation({ summary: 'Get monitor by id' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Get('/:id') - @ApiOkResponse({ type: MonitorResponseDto }) - async getMonitor( - @Req() req: Request, - @Param('id') monitorId: string, - ): Promise { - return await this.monitorService.getMonitor(req.user as User, monitorId); - } - - @ApiOperation({ summary: 'List monitors of project' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Get('') - @ApiOkResponse({ type: [MonitorResponseDto] }) - async listMonitor( - @Req() req: Request, - @Query() body: ListMonitorDto, - ): Promise { - return await this.monitorService.listMonitors(req.user as User, body); - } - - @ApiOperation({ summary: 'Create monitor' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Post('') - @ApiCreatedResponse({ type: MonitorResponseDto }) - async createMonitor( - @Req() req: Request, - @Body() body: CreateMonitorDto, - ): Promise { - return await this.monitorService.createMonitor(req.user as User, body); - } - - @ApiOperation({ summary: 'Delete monitor' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Delete('/:id') - @ApiOkResponse({ type: DeleteMonitorResponseDto }) - async deleteMonitor( - @Req() req: Request, - @Param('id') monitorId: string, - ): Promise { - return await this.monitorService.deleteMonitor( - req.user as User, - Builder().monitorId(monitorId).build(), - ); - } - - @ApiOperation({ summary: 'Update monitor' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Patch('/:id') - @ApiOkResponse({ type: MonitorResponseDto }) - async updateMonitor( - @Req() req: Request, - @Param('id') monitorId: string, - @Body() body: UpdateMonitorDto, - ): Promise { - body.monitorId = monitorId; - return await this.monitorService.updateMonitor(req.user as User, body); - } -} diff --git a/app/apps/onebox/src/modules/monitor/monitor.module.ts b/app/apps/onebox/src/modules/monitor/monitor.module.ts deleted file mode 100644 index e73baa6..0000000 --- a/app/apps/onebox/src/modules/monitor/monitor.module.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MonitorModule as MonitorModelModule } from '@app/shared_modules/monitor/monitor.module'; -import { ProjectModule as ProjectModelModule } from '@app/shared_modules/project/project.module'; -import { WebhookModule } from '@app/shared_modules/webhook/webhook.module'; -import { Module } from '@nestjs/common'; -import { ProjectModule } from '../project/project.module'; -import { MonitorController } from './monitor.controller'; -import { MonitorService } from './monitor.service'; -@Module({ - controllers: [MonitorController], - providers: [MonitorService], - exports: [MonitorService], - imports: [ - MonitorModelModule, - ProjectModelModule, - WebhookModule, - ProjectModule, - ], -}) -export class MonitorModule {} diff --git a/app/apps/onebox/src/modules/monitor/monitor.service.ts b/app/apps/onebox/src/modules/monitor/monitor.service.ts deleted file mode 100644 index 75f1c05..0000000 --- a/app/apps/onebox/src/modules/monitor/monitor.service.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { ErrorCode } from '@app/global/global.error'; -import { MonitorAddressRepository } from '@app/shared_modules/monitor/repositories/monitor.address.repository'; -import { MonitorRepository } from '@app/shared_modules/monitor/repositories/monitor.repository'; -import { - Monitor, - MonitorNotificationMethod, - WebhookNotification, -} from '@app/shared_modules/monitor/schemas/monitor.schema'; -import { ProjectMemberRepository } from '@app/shared_modules/project/repositories/project.member.repository'; -import { ProjectRepository } from '@app/shared_modules/project/repositories/project.repository'; -import { WebhookService } from '@app/shared_modules/webhook/webhook.service'; -import { measureTime } from '@app/utils/time.utils'; -import { Injectable } from '@nestjs/common'; -import { Builder } from 'builder-pattern'; -import { ProjectService } from '../project/project.service'; -import { User } from '../users/schemas/user.schema'; -import { - CreateMonitorDto, - DeleteMonitorDto, - DeleteMonitorResponseDto, - ListMonitorDto, - MonitorResponseDto, - UpdateMonitorDto, -} from '@app/shared_modules/monitor/dto/monitor.dto'; - -@Injectable() -export class MonitorService { - constructor( - private readonly projectMemberRepository: ProjectMemberRepository, - private readonly projectRepository: ProjectRepository, - private readonly monitorRepository: MonitorRepository, - private readonly webhookService: WebhookService, - private readonly projectService: ProjectService, - ) {} - - async findAndAuthMonitor(user: User, monitorId: string): Promise { - const monitor = await this.monitorRepository.findById(monitorId); - if (!monitor) { - throw ErrorCode.MONITOR_NOT_FOUND.asException(); - } - await this.projectService.checkProjectPermission(user, monitor.projectId); - return monitor; - } - - async listMonitors( - user: User, - request: ListMonitorDto, - ): Promise { - await this.projectService.checkProjectPermission(user, request.projectId); - const monitors = await this.monitorRepository.listMonitors(request); - return monitors.map((monitor) => MonitorResponseDto.from(monitor)); - } - - async getMonitor(user: User, monitorId: string): Promise { - const monitor = await this.findAndAuthMonitor(user, monitorId); - return MonitorResponseDto.from(monitor); - } - - async createMonitor( - user: User, - request: CreateMonitorDto, - ): Promise { - await this.projectService.checkProjectPermission(user, request.projectId); - - const monitor = request.toMonitor(user.userId); - // request create webhook in webhook microservice - if (monitor.notification.method === MonitorNotificationMethod.Webhook) { - const method = monitor.notification as WebhookNotification; - const webhookId = await this.webhookService.createWebhook( - monitor.monitorId, - method.url, - method.secret_token, - method.authorization, - ); - monitor.webhookId = webhookId; - } - await this.monitorRepository.saveMonitor(monitor); - await this.projectRepository.increaseMonitorCount(monitor.projectId, 1); - // todo: check max monitor - return MonitorResponseDto.from(monitor); - } - - async deleteMonitor( - user: User, - request: DeleteMonitorDto, - ): Promise { - const monitor = await this.monitorRepository.findById(request.monitorId); - if (!monitor) { - return Builder().success(true).build(); - } - await this.projectService.checkProjectPermission(user, monitor.projectId); - await measureTime('delete_monitor_resource', async () => { - Promise.all([ - this.monitorRepository.deleteMonitor(monitor.monitorId), - this.projectRepository.increaseMonitorCount(monitor.projectId, -1), - MonitorAddressRepository.getRepository( - monitor.network, - ).deleteAllMonitorAddress(monitor.monitorId), - ]); - }); - - if (monitor.notification.method === MonitorNotificationMethod.Webhook) { - const method = monitor.notification as WebhookNotification; - await this.webhookService.updateWebhook(monitor.webhookId, { - name: monitor.monitorId, - webhookUrl: method.url, - secret_token: method.secret_token, - authorization: method.authorization, - active: false, - }); - } - - return Builder().success(true).build(); - } - - async updateMonitor( - user: User, - request: UpdateMonitorDto, - ): Promise { - const monitor = await this.findAndAuthMonitor(user, request.monitorId); - const updateMonitor = new Map(); - if (request.name) { - updateMonitor['name'] = request.name; - } - if (request.condition) { - if (request.condition.native != undefined) { - updateMonitor['condition.native'] = request.condition.native; - } - if (request.condition.internal != undefined) { - updateMonitor['condition.internal'] = request.condition.internal; - } - if (request.condition.erc721 != undefined) { - updateMonitor['condition.erc721'] = request.condition.erc721; - } - if (request.condition.erc20 != undefined) { - updateMonitor['condition.erc20'] = request.condition.erc20; - } - if (request.condition.specific != undefined) { - updateMonitor['condition.specific'] = request.condition.specific; - } - if (request.condition.cryptos != undefined) { - updateMonitor['condition.cryptos'] = request.condition.cryptos; - } - } - if (request.notification) { - updateMonitor['notification'] = request.notification; - } - if (request.type) { - updateMonitor['type'] = request.type; - } - if (request.note) { - updateMonitor['note'] = request.note; - } - if (request.tags) { - updateMonitor['tags'] = request.tags; - } - if (request.disabled != undefined) { - updateMonitor['disabled'] = request.disabled; - } - - return await this.monitorRepository - .updateMonitor(monitor.monitorId, updateMonitor) - .then(async (monitor) => { - // @todo handle error on update webhook service - if (monitor.notification) { - if ( - request.notification.method === MonitorNotificationMethod.Webhook - ) { - const method = monitor.notification as WebhookNotification; - await this.webhookService.updateWebhook(monitor.webhookId, { - name: monitor.monitorId, - webhookUrl: method.url, - secret_token: method.secret_token, - authorization: method.authorization, - active: true, - }); - } - } - return MonitorResponseDto.from(monitor); - }); - } -} diff --git a/app/apps/onebox/src/modules/polling.block/avax.polling.block.service.ts b/app/apps/onebox/src/modules/polling.block/avax.polling.block.service.ts deleted file mode 100644 index 3c0121a..0000000 --- a/app/apps/onebox/src/modules/polling.block/avax.polling.block.service.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { TopicName } from '@app/utils/topicUtils'; -import { Inject, Injectable, Logger } from '@nestjs/common'; -import { ClientKafka } from '@nestjs/microservices'; -import { CronExpression, SchedulerRegistry } from '@nestjs/schedule'; -import { CronJob } from 'cron'; -import { ethers } from 'ethers'; -import { BlockSyncRepository } from 'libs'; -import { SupportedChain } from '@app/utils/supportedChain.util'; -import { BlockTransportDto } from '@app/utils/dto/transport.dto'; - -@Injectable() -export class AvaxPollingBlockService { - private detectInfo = { flag: false, blockNumber: 0 }; - - private readonly logger = new Logger(AvaxPollingBlockService.name); - - constructor( - private schedulerRegistry: SchedulerRegistry, - private readonly blockSyncRepository: BlockSyncRepository, - @Inject('WORKER_CLIENT_SERVICE') - private readonly workerClient: ClientKafka, - ) {} - - rpcUrl: string; - provider: ethers.Provider; - - onModuleInit() { - this.logger.log(`The module has been initialized.`); - if (process.env.AVAX_DISABLE !== 'false') { - this.detectInfo.flag = true; - return; - } - this.rpcUrl = process.env.AVAX_PROVIDER_URL; - this.provider = new ethers.JsonRpcProvider( - process.env.AVAX_PROVIDER_URL, - null, - { staticNetwork: true }, - ); - this.init(); - } - - async init() { - this.detectInfo.flag = true; - let blockSync = await this.blockSyncRepository.findOne(this.rpcUrl); - if (!blockSync) { - blockSync = await this.blockSyncRepository.create({ - rpcUrl: this.rpcUrl, - chain: SupportedChain.AVALANCHE.name, - lastSync: await this.getBlockNumber(), - }); - } - // checking force latest block config - const startBlockConfig = process.env.AVAX_START_BLOCK_CONFIG; - if (startBlockConfig === 'latest') { - const latestBlockNumber = await this.provider.getBlockNumber(); - this.logger.warn( - 'force running latest block from network ' + latestBlockNumber, - ); - this.updateLastSyncBlock(latestBlockNumber); - // if start at latest block, we need to minus 1 - // we suppose that we already scan at (latest block - 1) - this.detectInfo.blockNumber = latestBlockNumber - 1; - } else if (startBlockConfig === 'config') { - this.logger.warn( - 'force running start block from config ' + process.env.AVAX_START_BLOCK, - ); - this.updateLastSyncBlock(parseInt(process.env.AVAX_START_BLOCK)); - // if we start at config block, we suppose that we already scan at (config block - 1) - this.detectInfo.blockNumber = parseInt(process.env.AVAX_START_BLOCK) - 1; - } else { - this.logger.warn('running start block from db ' + blockSync.lastSync); - // if we start at db block, we suppose that we already scan at db block - this.detectInfo.blockNumber = - blockSync.lastSync + SupportedChain.AVALANCHE.confirmationBlock; - } - this.detectInfo.flag = false; - this.addCronJob('AvaxPollingBlock', CronExpression.EVERY_5_SECONDS); - } - - addCronJob(name: string, seconds: string) { - const job = new CronJob(seconds, () => this.pollingBlock()); - - this.schedulerRegistry.addCronJob(name, job); - job.start(); - - this.logger.warn(`job ${name} added for each ${seconds} seconds!`); - } - - private async updateLastSyncBlock(blockNumber: number): Promise { - // Update the last sync block in MongoDB - await this.blockSyncRepository.updateLastSync(this.rpcUrl, blockNumber); - } - - async pollingBlock() { - this.logger.debug('Start polling block number'); - if (this.detectInfo.flag) { - this.logger.error('conflict with last job. quit current job'); - return; - } - this.detectInfo.flag = true; - const lastDetectedBlock = this.detectInfo.blockNumber + 1; - - // Get the latest block number - const latestDetectedBlockNumber = await this.getBlockNumber(); - - // Scan each block - for ( - let blockNumber = lastDetectedBlock; - blockNumber <= latestDetectedBlockNumber; - blockNumber++ - ) { - try { - // emit event detect block with blocknumber - this.workerClient.emit( - TopicName.AVAX_DETECTED_BLOCK, - new BlockTransportDto(blockNumber, false), - ); - // emit event confirm block with block number - confirm block - this.workerClient.emit( - TopicName.AVAX_DETECTED_BLOCK, - new BlockTransportDto( - blockNumber - SupportedChain.AVALANCHE.confirmationBlock, - true, - ), - ); - - this.detectInfo.blockNumber = blockNumber; - this.logger.debug(`last emitted block ${blockNumber}`); - //only update last sync for confirm - await this.updateLastSyncBlock( - blockNumber - SupportedChain.AVALANCHE.confirmationBlock, - ); - } catch (error) { - this.logger.error([`Error polling block ${blockNumber}:`, error]); - break; - } - } - - this.detectInfo.flag = false; - return; - } - - private async getBlockNumber(): Promise { - try { - // Perform an asynchronous operation (e.g., fetching data) - const blockNumber = await Promise.race([ - this.provider.getBlockNumber(), // Your asynchronous operation - delay(5000).then(() => { - throw new Error('Get block number Timeout'); - }), // Timeout promise - ]); - this.logger.log('got latest block from network: ' + blockNumber); - return blockNumber; - } catch (error) { - this.logger.error('error while getting block number', error); - } - return 0; - } -} - -function delay(ms: number) { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); -} diff --git a/app/apps/onebox/src/modules/polling.block/bsc.polling.block.service.ts b/app/apps/onebox/src/modules/polling.block/bsc.polling.block.service.ts deleted file mode 100644 index 2e8d448..0000000 --- a/app/apps/onebox/src/modules/polling.block/bsc.polling.block.service.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { TopicName } from '@app/utils/topicUtils'; -import { Inject, Injectable, Logger } from '@nestjs/common'; -import { ClientKafka } from '@nestjs/microservices'; -import { CronExpression, SchedulerRegistry } from '@nestjs/schedule'; -import { CronJob } from 'cron'; -import { ethers } from 'ethers'; -import { BlockSyncRepository } from 'libs'; -import { SupportedChain } from '@app/utils/supportedChain.util'; -import { BlockTransportDto } from '@app/utils/dto/transport.dto'; - -@Injectable() -export class BscPollingBlockService { - private detectInfo = { flag: false, blockNumber: 0 }; - - private readonly logger = new Logger(BscPollingBlockService.name); - - constructor( - private schedulerRegistry: SchedulerRegistry, - private readonly blockSyncRepository: BlockSyncRepository, - @Inject('WORKER_CLIENT_SERVICE') - private readonly workerClient: ClientKafka, - ) {} - - rpcUrl: string; - provider: ethers.Provider; - - onModuleInit() { - this.logger.log(`The module has been initialized.`); - if (process.env.BSC_DISABLE !== 'false') { - this.detectInfo.flag = true; - return; - } - this.rpcUrl = process.env.BSC_PROVIDER_URL; - this.provider = new ethers.JsonRpcProvider( - process.env.BSC_PROVIDER_URL, - null, - { staticNetwork: true }, - ); - this.init(); - } - - async init() { - this.detectInfo.flag = true; - let blockSync = await this.blockSyncRepository.findOne(this.rpcUrl); - if (!blockSync) { - blockSync = await this.blockSyncRepository.create({ - rpcUrl: this.rpcUrl, - chain: SupportedChain.BSC.name, - lastSync: await this.getBlockNumber(), - }); - } - // checking force latest block config - const startBlockConfig = process.env.BSC_START_BLOCK_CONFIG; - if (startBlockConfig === 'latest') { - const latestBlockNumber = await this.provider.getBlockNumber(); - this.logger.warn( - 'force running latest block from network ' + latestBlockNumber, - ); - this.updateLastSyncBlock(latestBlockNumber); - // if start at latest block, we need to minus 1 - // we suppose that we already scan at (latest block - 1) - this.detectInfo.blockNumber = latestBlockNumber - 1; - } else if (startBlockConfig === 'config') { - this.logger.warn( - 'force running start block from config ' + process.env.BSC_START_BLOCK, - ); - this.updateLastSyncBlock(parseInt(process.env.BSC_START_BLOCK)); - // if we start at config block, we suppose that we already scan at (config block - 1) - this.detectInfo.blockNumber = parseInt(process.env.BSC_START_BLOCK) - 1; - } else { - this.logger.warn('running start block from db ' + blockSync.lastSync); - // if we start at db block, we suppose that we already scan at db block - this.detectInfo.blockNumber = - blockSync.lastSync + SupportedChain.BSC.confirmationBlock; - } - this.detectInfo.flag = false; - this.addCronJob('BscPollingBlock', CronExpression.EVERY_5_SECONDS); - } - - addCronJob(name: string, seconds: string) { - const job = new CronJob(seconds, () => this.pollingBlock()); - - this.schedulerRegistry.addCronJob(name, job); - job.start(); - - this.logger.warn(`job ${name} added for each ${seconds} seconds!`); - } - - private async updateLastSyncBlock(blockNumber: number): Promise { - // Update the last sync block in MongoDB - await this.blockSyncRepository.updateLastSync(this.rpcUrl, blockNumber); - } - - async pollingBlock() { - this.logger.debug('Start polling block number'); - if (this.detectInfo.flag) { - this.logger.error('conflict with last job. quit current job'); - return; - } - this.detectInfo.flag = true; - const lastDetectedBlock = this.detectInfo.blockNumber + 1; - - // Get the latest block number - const latestDetectedBlockNumber = await this.getBlockNumber(); - - // Scan each block - for ( - let blockNumber = lastDetectedBlock; - blockNumber <= latestDetectedBlockNumber; - blockNumber++ - ) { - try { - // emit event detect block with blocknumber - this.workerClient.emit( - TopicName.BSC_DETECTED_BLOCK, - new BlockTransportDto(blockNumber, false), - ); - // emit event confirm block with block number - confirm block - this.workerClient.emit( - TopicName.BSC_DETECTED_BLOCK, - new BlockTransportDto( - blockNumber - SupportedChain.BSC.confirmationBlock, - true, - ), - ); - - this.detectInfo.blockNumber = blockNumber; - this.logger.debug(`last emitted block ${blockNumber}`); - //only update last sync for confirm - await this.updateLastSyncBlock( - blockNumber - SupportedChain.BSC.confirmationBlock, - ); - } catch (error) { - this.logger.error([`Error polling block ${blockNumber}:`, error]); - break; - } - } - - this.detectInfo.flag = false; - return; - } - - private async getBlockNumber(): Promise { - try { - // Perform an asynchronous operation (e.g., fetching data) - const blockNumber = await Promise.race([ - this.provider.getBlockNumber(), // Your asynchronous operation - delay(5000).then(() => { - throw new Error('Get block number Timeout'); - }), // Timeout promise - ]); - this.logger.log('got latest block from network: ' + blockNumber); - return blockNumber; - } catch (error) { - this.logger.error('error while getting block number', error); - } - return 0; - } -} - -function delay(ms: number) { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); -} diff --git a/app/apps/onebox/src/modules/polling.block/ethereum.polling.block.service.ts b/app/apps/onebox/src/modules/polling.block/ethereum.polling.block.service.ts deleted file mode 100644 index 7b50b0b..0000000 --- a/app/apps/onebox/src/modules/polling.block/ethereum.polling.block.service.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { TopicName } from '@app/utils/topicUtils'; -import { Inject, Injectable, Logger } from '@nestjs/common'; -import { ClientKafka } from '@nestjs/microservices'; -import { CronExpression, SchedulerRegistry } from '@nestjs/schedule'; -import { CronJob } from 'cron'; -import { ethers } from 'ethers'; -import { BlockSyncRepository } from 'libs'; -import { SupportedChain } from '@app/utils/supportedChain.util'; -import { BlockTransportDto } from '@app/utils/dto/transport.dto'; - -@Injectable() -export class EthereumPollingBlockService { - private detectInfo = { flag: false, blockNumber: 0 }; - - private readonly logger = new Logger(EthereumPollingBlockService.name); - - constructor( - private schedulerRegistry: SchedulerRegistry, - private readonly blockSyncRepository: BlockSyncRepository, - @Inject('WORKER_CLIENT_SERVICE') - private readonly workerClient: ClientKafka, - ) {} - - rpcUrl: string; - provider: ethers.Provider; - - onModuleInit() { - this.logger.log(`The module has been initialized.`); - if (process.env.EVM_DISABLE !== 'false') { - this.detectInfo.flag = true; - return; - } - this.rpcUrl = process.env.ETH_PROVIDER_URL; - this.provider = new ethers.JsonRpcProvider( - process.env.ETH_PROVIDER_URL, - null, - { staticNetwork: true }, - ); - this.init(); - } - - async init() { - this.detectInfo.flag = true; - let blockSync = await this.blockSyncRepository.findOne(this.rpcUrl); - if (!blockSync) { - blockSync = await this.blockSyncRepository.create({ - rpcUrl: this.rpcUrl, - chain: SupportedChain.ETH.name, - lastSync: await this.getBlockNumber(), - }); - } - // checking force latest block config - const startBlockConfig = process.env.EVM_START_BLOCK_CONFIG; - if (startBlockConfig === 'latest') { - const latestBlockNumber = await this.provider.getBlockNumber(); - this.logger.warn( - 'force running latest block from network ' + latestBlockNumber, - ); - this.updateLastSyncBlock(latestBlockNumber); - // if start at latest block, we need to minus 1 - // we suppose that we already scan at (latest block - 1) - this.detectInfo.blockNumber = latestBlockNumber - 1; - } else if (startBlockConfig === 'config') { - this.logger.warn( - 'force running start block from config ' + process.env.EVM_START_BLOCK, - ); - this.updateLastSyncBlock(parseInt(process.env.EVM_START_BLOCK)); - // if we start at config block, we suppose that we already scan at (config block - 1) - this.detectInfo.blockNumber = parseInt(process.env.EVM_START_BLOCK) - 1; - } else { - this.logger.warn('running start block from db ' + blockSync.lastSync); - // if we start at db block, we suppose that we already scan at db block - this.detectInfo.blockNumber = - blockSync.lastSync + SupportedChain.ETH.confirmationBlock; - } - this.detectInfo.flag = false; - this.addCronJob('EthereumPollingBlock', CronExpression.EVERY_10_SECONDS); - } - - addCronJob(name: string, seconds: string) { - const job = new CronJob(seconds, () => this.pollingBlock()); - - this.schedulerRegistry.addCronJob(name, job); - job.start(); - - this.logger.warn(`job ${name} added for each ${seconds} seconds!`); - } - - private async updateLastSyncBlock(blockNumber: number): Promise { - // Update the last sync block in MongoDB - await this.blockSyncRepository.updateLastSync(this.rpcUrl, blockNumber); - } - - async pollingBlock() { - this.logger.debug('Start polling block number'); - if (this.detectInfo.flag) { - this.logger.error('conflict with last job. quit current job'); - return; - } - this.detectInfo.flag = true; - const lastDetectedBlock = this.detectInfo.blockNumber + 1; - - // Get the latest block number - const latestDetectedBlockNumber = await this.getBlockNumber(); - - // Scan each block - for ( - let blockNumber = lastDetectedBlock; - blockNumber <= latestDetectedBlockNumber; - blockNumber++ - ) { - try { - // emit event detect block with blocknumber - this.workerClient.emit( - TopicName.ETH_DETECTED_BLOCK, - new BlockTransportDto(blockNumber, false), - ); - // emit event confirm block with block number - confirm block - this.workerClient.emit( - TopicName.ETH_DETECTED_BLOCK, - new BlockTransportDto( - blockNumber - SupportedChain.ETH.confirmationBlock, - true, - ), - ); - - this.detectInfo.blockNumber = blockNumber; - this.logger.debug(`last emitted block ${blockNumber}`); - //only update last sync for confirm - await this.updateLastSyncBlock( - blockNumber - SupportedChain.ETH.confirmationBlock, - ); - } catch (error) { - this.logger.error([`Error polling block ${blockNumber}:`, error]); - break; - } - } - - this.detectInfo.flag = false; - return; - } - - private async getBlockNumber(): Promise { - try { - // Perform an asynchronous operation (e.g., fetching data) - const blockNumber = await Promise.race([ - this.provider.getBlockNumber(), // Your asynchronous operation - delay(5000).then(() => { - throw new Error('Get block number Timeout'); - }), // Timeout promise - ]); - this.logger.log('got latest block from network: ' + blockNumber); - return blockNumber; - } catch (error) { - this.logger.error('error while getting block number', error); - } - return 0; - } -} - -function delay(ms: number) { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); -} diff --git a/app/apps/onebox/src/modules/polling.block/mantle.polling.block.service.ts b/app/apps/onebox/src/modules/polling.block/mantle.polling.block.service.ts deleted file mode 100644 index 1248227..0000000 --- a/app/apps/onebox/src/modules/polling.block/mantle.polling.block.service.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { TopicName } from '@app/utils/topicUtils'; -import { Inject, Injectable, Logger } from '@nestjs/common'; -import { ClientKafka } from '@nestjs/microservices'; -import { CronExpression, SchedulerRegistry } from '@nestjs/schedule'; -import { CronJob } from 'cron'; -import { ethers } from 'ethers'; -import { BlockSyncRepository } from 'libs'; -import { SupportedChain } from '@app/utils/supportedChain.util'; -import { BlockTransportDto } from '@app/utils/dto/transport.dto'; - -@Injectable() -export class MantlePollingBlockService { - private detectInfo = { flag: false, blockNumber: 0 }; - - private readonly logger = new Logger(MantlePollingBlockService.name); - - constructor( - private schedulerRegistry: SchedulerRegistry, - private readonly blockSyncRepository: BlockSyncRepository, - @Inject('WORKER_CLIENT_SERVICE') - private readonly workerClient: ClientKafka, - ) {} - - rpcUrl: string; - provider: ethers.Provider; - - onModuleInit() { - this.logger.log(`The module has been initialized.`); - if (process.env.MANTLE_DISABLE !== 'false') { - this.detectInfo.flag = true; - return; - } - this.rpcUrl = process.env.MANTLE_PROVIDER_URL; - this.provider = new ethers.JsonRpcProvider( - process.env.MANTLE_PROVIDER_URL, - null, - { staticNetwork: true }, - ); - this.init(); - } - - async init() { - this.detectInfo.flag = true; - let blockSync = await this.blockSyncRepository.findOne(this.rpcUrl); - if (!blockSync) { - blockSync = await this.blockSyncRepository.create({ - rpcUrl: this.rpcUrl, - chain: SupportedChain.AVALANCHE.name, - lastSync: await this.getBlockNumber(), - }); - } - // checking force latest block config - const startBlockConfig = process.env.MANTLE_START_BLOCK_CONFIG; - if (startBlockConfig === 'latest') { - const latestBlockNumber = await this.provider.getBlockNumber(); - this.logger.warn( - 'force running latest block from network ' + latestBlockNumber, - ); - this.updateLastSyncBlock(latestBlockNumber); - // if start at latest block, we need to minus 1 - // we suppose that we already scan at (latest block - 1) - this.detectInfo.blockNumber = latestBlockNumber - 1; - } else if (startBlockConfig === 'config') { - this.logger.warn( - 'force running start block from config ' + - process.env.MANTLE_START_BLOCK, - ); - this.updateLastSyncBlock(parseInt(process.env.MANTLE_START_BLOCK)); - // if we start at config block, we suppose that we already scan at (config block - 1) - this.detectInfo.blockNumber = - parseInt(process.env.MANTLE_START_BLOCK) - 1; - } else { - this.logger.warn('running start block from db ' + blockSync.lastSync); - // if we start at db block, we suppose that we already scan at db block - this.detectInfo.blockNumber = - blockSync.lastSync + SupportedChain.AVALANCHE.confirmationBlock; - } - this.detectInfo.flag = false; - this.addCronJob('MantlePollingBlock', CronExpression.EVERY_5_SECONDS); - } - - addCronJob(name: string, seconds: string) { - const job = new CronJob(seconds, () => this.pollingBlock()); - - this.schedulerRegistry.addCronJob(name, job); - job.start(); - - this.logger.warn(`job ${name} added for each ${seconds} seconds!`); - } - - private async updateLastSyncBlock(blockNumber: number): Promise { - // Update the last sync block in MongoDB - await this.blockSyncRepository.updateLastSync(this.rpcUrl, blockNumber); - } - - async pollingBlock() { - this.logger.debug('Start polling block number'); - if (this.detectInfo.flag) { - this.logger.error('conflict with last job. quit current job'); - return; - } - this.detectInfo.flag = true; - const lastDetectedBlock = this.detectInfo.blockNumber + 1; - - // Get the latest block number - const latestDetectedBlockNumber = await this.getBlockNumber(); - - // Scan each block - for ( - let blockNumber = lastDetectedBlock; - blockNumber <= latestDetectedBlockNumber; - blockNumber++ - ) { - try { - // emit event detect block with blocknumber - this.workerClient.emit( - TopicName.MANTLE_DETECTED_BLOCK, - new BlockTransportDto(blockNumber, false), - ); - // emit event confirm block with block number - confirm block - this.workerClient.emit( - TopicName.MANTLE_DETECTED_BLOCK, - new BlockTransportDto( - blockNumber - SupportedChain.AVALANCHE.confirmationBlock, - true, - ), - ); - - this.detectInfo.blockNumber = blockNumber; - this.logger.debug(`last emitted block ${blockNumber}`); - - //only update last sync for confirm - await this.updateLastSyncBlock( - blockNumber - SupportedChain.AVALANCHE.confirmationBlock, - ); - } catch (error) { - this.logger.error([`Error polling block ${blockNumber}:`, error]); - break; - } - } - - this.detectInfo.flag = false; - return; - } - - private async getBlockNumber(): Promise { - try { - // Perform an asynchronous operation (e.g., fetching data) - const blockNumber = await Promise.race([ - this.provider.getBlockNumber(), // Your asynchronous operation - delay(5000).then(() => { - throw new Error('Get block number Timeout'); - }), // Timeout promise - ]); - this.logger.log('got latest block from network: ' + blockNumber); - return blockNumber; - } catch (error) { - this.logger.error('error while getting block number', error); - } - return 0; - } -} - -function delay(ms: number) { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); -} diff --git a/app/apps/onebox/src/modules/polling.block/polling.block.module.ts b/app/apps/onebox/src/modules/polling.block/polling.block.module.ts deleted file mode 100644 index 576d98b..0000000 --- a/app/apps/onebox/src/modules/polling.block/polling.block.module.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Module } from '@nestjs/common'; -import { ClientsModule, Transport } from '@nestjs/microservices'; -import { ScheduleModule } from '@nestjs/schedule'; -import { BlockSyncModelModule } from 'libs'; -import { AvaxPollingBlockService } from './avax.polling.block.service'; -import { BscPollingBlockService } from './bsc.polling.block.service'; -import { EthereumPollingBlockService } from './ethereum.polling.block.service'; -import { MantlePollingBlockService } from './mantle.polling.block.service'; -import { PolygonPollingBlockService } from './polygon.polling.block.service'; - -@Module({ - imports: [ - ClientsModule.registerAsync([ - { - name: 'WORKER_CLIENT_SERVICE', - useFactory: () => ({ - transport: Transport.KAFKA, - options: { - client: { - clientId: 'worker', - brokers: process.env.KAFKA_BROKERS.split(','), - ssl: process.env.KAFKA_SSL === 'true', - sasl: - process.env.KAFKA_AUTH_ENABLE === 'true' - ? { - mechanism: 'plain', - username: process.env.KAFKA_USERNAME || '', - password: process.env.KAFKA_PASSWORD || '', - } - : null, - retry: { - restartOnFailure: async (e) => { - console.log('RESTART ON FAILURE polling module'); - console.log(e); - return true; - }, - }, - }, - producer: {}, - consumer: { - groupId: 'worker-consumer', - }, - }, - }), - }, - ]), - ScheduleModule, - BlockSyncModelModule, - ], - providers: [ - EthereumPollingBlockService, - PolygonPollingBlockService, - AvaxPollingBlockService, - MantlePollingBlockService, - BscPollingBlockService, - ], -}) -export class PollingBlockModule {} diff --git a/app/apps/onebox/src/modules/polling.block/polygon.polling.block.service.ts b/app/apps/onebox/src/modules/polling.block/polygon.polling.block.service.ts deleted file mode 100644 index c00175d..0000000 --- a/app/apps/onebox/src/modules/polling.block/polygon.polling.block.service.ts +++ /dev/null @@ -1,167 +0,0 @@ -import { TopicName } from '@app/utils/topicUtils'; -import { Inject, Injectable, Logger } from '@nestjs/common'; -import { ClientKafka } from '@nestjs/microservices'; -import { CronExpression, SchedulerRegistry } from '@nestjs/schedule'; -import { CronJob } from 'cron'; -import { ethers } from 'ethers'; -import { BlockSyncRepository } from 'libs'; -import { SupportedChain } from '@app/utils/supportedChain.util'; -import { BlockTransportDto } from '@app/utils/dto/transport.dto'; - -@Injectable() -export class PolygonPollingBlockService { - private detectInfo = { flag: false, blockNumber: 0 }; - - private readonly logger = new Logger(PolygonPollingBlockService.name); - - constructor( - private schedulerRegistry: SchedulerRegistry, - private readonly blockSyncRepository: BlockSyncRepository, - @Inject('WORKER_CLIENT_SERVICE') - private readonly workerClient: ClientKafka, - ) {} - - rpcUrl: string; - provider: ethers.Provider; - - onModuleInit() { - this.logger.log(`The module has been initialized.`); - if (process.env.POLYGON_DISABLE !== 'false') { - this.detectInfo.flag = true; - return; - } - this.rpcUrl = process.env.POLYGON_PROVIDER_URL; - this.provider = new ethers.JsonRpcProvider( - process.env.POLYGON_PROVIDER_URL, - null, - { staticNetwork: true }, - ); - this.init(); - } - - async init() { - this.detectInfo.flag = true; - let blockSync = await this.blockSyncRepository.findOne(this.rpcUrl); - if (!blockSync) { - blockSync = await this.blockSyncRepository.create({ - rpcUrl: this.rpcUrl, - chain: SupportedChain.POLYGON.name, - lastSync: await this.getBlockNumber(), - }); - } - // checking force latest block config - const startBlockConfig = process.env.POLYGON_START_BLOCK_CONFIG; - if (startBlockConfig === 'latest') { - const latestBlockNumber = await this.provider.getBlockNumber(); - this.logger.warn( - 'force running latest block from network ' + latestBlockNumber, - ); - this.updateLastSyncBlock(latestBlockNumber); - // if start at latest block, we need to minus 1 - // we suppose that we already scan at (latest block - 1) - this.detectInfo.blockNumber = latestBlockNumber - 1; - } else if (startBlockConfig === 'config') { - this.logger.warn( - 'force running start block from config ' + - process.env.POLYGON_START_BLOCK, - ); - this.updateLastSyncBlock(parseInt(process.env.POLYGON_START_BLOCK)); - // if we start at config block, we suppose that we already scan at (config block - 1) - this.detectInfo.blockNumber = - parseInt(process.env.POLYGON_START_BLOCK) - 1; - } else { - this.logger.warn('running start block from db ' + blockSync.lastSync); - // if we start at db block, we suppose that we already scan at db block - this.detectInfo.blockNumber = - blockSync.lastSync + SupportedChain.POLYGON.confirmationBlock; - } - this.detectInfo.flag = false; - this.addCronJob('PolygonPollingBlock', CronExpression.EVERY_5_SECONDS); - } - - addCronJob(name: string, seconds: string) { - const job = new CronJob(seconds, () => this.pollingBlock()); - - this.schedulerRegistry.addCronJob(name, job); - job.start(); - - this.logger.warn(`job ${name} added for each ${seconds} seconds!`); - } - - private async updateLastSyncBlock(blockNumber: number): Promise { - // Update the last sync block in MongoDB - await this.blockSyncRepository.updateLastSync(this.rpcUrl, blockNumber); - } - - async pollingBlock() { - this.logger.debug('Start polling block number'); - if (this.detectInfo.flag) { - this.logger.error('conflict with last job. quit current job'); - return; - } - this.detectInfo.flag = true; - const lastDetectedBlock = this.detectInfo.blockNumber + 1; - - // Get the latest block number - const latestDetectedBlockNumber = await this.getBlockNumber(); - - // Scan each block - for ( - let blockNumber = lastDetectedBlock; - blockNumber <= latestDetectedBlockNumber; - blockNumber++ - ) { - try { - // emit event detect block with blocknumber - this.workerClient.emit( - TopicName.POLYGON_DETECTED_BLOCK, - new BlockTransportDto(blockNumber, false), - ); - // emit event confirm block with block number - confirm block - this.workerClient.emit( - TopicName.POLYGON_DETECTED_BLOCK, - new BlockTransportDto( - blockNumber - SupportedChain.POLYGON.confirmationBlock, - true, - ), - ); - - this.detectInfo.blockNumber = blockNumber; - this.logger.debug(`last emitted block ${blockNumber}`); - //only update last sync for confirm - await this.updateLastSyncBlock( - blockNumber - SupportedChain.POLYGON.confirmationBlock, - ); - } catch (error) { - this.logger.error([`Error polling block ${blockNumber}:`, error]); - break; - } - } - - this.detectInfo.flag = false; - return; - } - - private async getBlockNumber(): Promise { - try { - // Perform an asynchronous operation (e.g., fetching data) - const blockNumber = await Promise.race([ - this.provider.getBlockNumber(), // Your asynchronous operation - delay(5000).then(() => { - throw new Error('Get block number Timeout'); - }), // Timeout promise - ]); - this.logger.log('got latest block from network: ' + blockNumber); - return blockNumber; - } catch (error) { - this.logger.error('error while getting block number', error); - } - return 0; - } -} - -function delay(ms: number) { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); -} diff --git a/app/apps/onebox/src/modules/project/dto/project.dto.ts b/app/apps/onebox/src/modules/project/dto/project.dto.ts deleted file mode 100644 index 39b3037..0000000 --- a/app/apps/onebox/src/modules/project/dto/project.dto.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { - Project, - ProjectQuota, - ProjectStatus, -} from '@app/shared_modules/project/schemas/project.schema'; -import { ApiProperty, ApiResponseProperty } from '@nestjs/swagger'; -import { Builder } from 'builder-pattern'; -import { IsNotEmpty } from 'class-validator'; - -export class CreateProjectDto { - @ApiProperty() - @IsNotEmpty() - name: string; -} - -export class ProjectResponseDto { - @ApiResponseProperty() - projectId: string; - - @ApiResponseProperty() - ownerId: string; - - @ApiResponseProperty() - name: string; - - @ApiResponseProperty() - status: ProjectStatus; - - @ApiResponseProperty() - maxMember: number; - - @ApiResponseProperty() - memberCount: number; - - @ApiResponseProperty() - maxMonitor: number; - - @ApiResponseProperty() - monitorCount: number; - - @ApiResponseProperty() - maxAddress: number; - - @ApiResponseProperty() - addressCount: number; - - @ApiResponseProperty() - dateCreated: Date; - - @ApiResponseProperty() - currentQuota: number; - - static from(project: Project) { - return Builder() - .projectId(project.projectId) - .ownerId(project.ownerId) - .name(project.name) - .status(project.status) - .maxMember(project.maxMember) - .memberCount(project.memberCount) - .maxMonitor(project.maxMonitor) - .monitorCount(project.monitorCount) - .maxAddress(project.maxAddress) - .addressCount(project.addressCount) - .dateCreated(project.dateCreated) - .currentQuota(project.currentQuota) - .build(); - } -} - -export class ProjectQuotaResponseDto { - @ApiResponseProperty() - projectId: string; - - @ApiResponseProperty() - month: string; - - @ApiResponseProperty() - ownerId: string; - - @ApiResponseProperty() - quota: number; - - @ApiResponseProperty() - used: number; - - @ApiResponseProperty() - dateCreated: Date; - - static from(projectQuota: ProjectQuota): ProjectQuotaResponseDto { - return Builder() - .projectId(projectQuota.projectId) - .month(projectQuota.month) - .ownerId(projectQuota.ownerId) - .quota(projectQuota.quota) - .used(projectQuota.used) - .dateCreated(projectQuota.dateCreated) - .build(); - } -} diff --git a/app/apps/onebox/src/modules/project/project.controller.ts b/app/apps/onebox/src/modules/project/project.controller.ts deleted file mode 100644 index ca98ff2..0000000 --- a/app/apps/onebox/src/modules/project/project.controller.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { - Body, - Controller, - Get, - Param, - Post, - Query, - Req, - UseGuards, -} from '@nestjs/common'; -import { - ApiBearerAuth, - ApiCreatedResponse, - ApiOkResponse, - ApiOperation, - ApiTags, -} from '@nestjs/swagger'; -import { Request } from 'express'; -import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; -import { User } from '../users/schemas/user.schema'; -import { - CreateProjectDto, - ProjectQuotaResponseDto, - ProjectResponseDto, -} from './dto/project.dto'; -import { ProjectService } from './project.service'; - -@ApiTags('Project') -@Controller('project') -export class ProjectController { - constructor(private readonly projectService: ProjectService) {} - - @ApiOperation({ summary: 'Get project by id' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Get('/:id') - @ApiOkResponse({ type: ProjectResponseDto }) - async getProject( - @Req() req: Request, - @Param('id') projectId: string, - ): Promise { - return await this.projectService.getProject(req.user as User, projectId); - } - - @ApiOperation({ summary: 'List projects' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Get('') - @ApiOkResponse({ type: [ProjectResponseDto] }) - async getProjects(@Req() req: Request): Promise { - return await this.projectService.listProjects(req.user as User); - } - - @ApiOperation({ summary: 'Create project' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Post('') - @ApiCreatedResponse({ type: ProjectResponseDto }) - async createProject( - @Req() req: Request, - @Body() body: CreateProjectDto, - ): Promise { - return await this.projectService.createProject(req.user as User, body); - } - - @ApiOperation({ summary: 'Get project current month quota' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Get('/quota/current') - @ApiOkResponse({ type: ProjectQuotaResponseDto }) - async getProjectQuotaCurrentMonth( - @Req() req: Request, - @Query('projectId') projectId: string, - ): Promise { - return await this.projectService.getProjectCurrentQuora( - req.user as User, - projectId, - ); - } -} diff --git a/app/apps/onebox/src/modules/project/project.module.ts b/app/apps/onebox/src/modules/project/project.module.ts deleted file mode 100644 index e67c571..0000000 --- a/app/apps/onebox/src/modules/project/project.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ProjectModule as ProjectModelModule } from '@app/shared_modules/project/project.module'; -import { Module } from '@nestjs/common'; -import { ProjectController } from './project.controller'; -import { ProjectService } from './project.service'; -@Module({ - controllers: [ProjectController], - providers: [ProjectService], - exports: [ProjectService], - imports: [ProjectModelModule], -}) -export class ProjectModule {} diff --git a/app/apps/onebox/src/modules/project/project.service.ts b/app/apps/onebox/src/modules/project/project.service.ts deleted file mode 100644 index 2c9690f..0000000 --- a/app/apps/onebox/src/modules/project/project.service.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { ErrorCode } from '@app/global/global.error'; -import { ProjectMemberRepository } from '@app/shared_modules/project/repositories/project.member.repository'; -import { ProjectQuotaRepository } from '@app/shared_modules/project/repositories/project.quota.repository'; -import { ProjectRepository } from '@app/shared_modules/project/repositories/project.repository'; -import { - Project, - ProjectMember, - ProjectQuota, - ProjectRole, - ProjectStatus, -} from '@app/shared_modules/project/schemas/project.schema'; -import { generateProjectId } from '@app/utils/uuidUtils'; -import { Injectable } from '@nestjs/common'; -import { Builder } from 'builder-pattern'; -import { User } from '../users/schemas/user.schema'; -import { - CreateProjectDto, - ProjectQuotaResponseDto, - ProjectResponseDto, -} from './dto/project.dto'; -import { ApiKeyUser } from '../apikey/schemas/apikey.schema'; - -@Injectable() -export class ProjectService { - constructor( - private readonly projectRepository: ProjectRepository, - private readonly projectMemberRepository: ProjectMemberRepository, - private readonly projectQuotaRepository: ProjectQuotaRepository, - ) {} - - async checkProjectPermission( - user: User, - projectId: string, - ): Promise { - if (user instanceof ApiKeyUser) { - if (user.projectId !== projectId) { - throw ErrorCode.PROJECT_FORBIDDEN.asException(); - } - } - const member = await this.projectMemberRepository.findByUserAndProject( - user.userId, - projectId, - ); - if (!member) { - throw ErrorCode.PROJECT_FORBIDDEN.asException(); - } - return member; - } - - async getProject(user: User, id: string): Promise { - const project = await this.projectRepository.findById(id); - if (!project) { - throw ErrorCode.PROJECT_NOT_FOUND.asException(); - } - - await this.checkProjectPermission(user, project.projectId); - - return ProjectResponseDto.from(project); - } - - async createProject( - user: User, - createProjectDto: CreateProjectDto, - ): Promise { - const project = Builder() - .projectId(generateProjectId()) - .ownerId(user.userId) - .name(createProjectDto.name) - .status(ProjectStatus.ACTIVE) - .maxMember(5) - .memberCount(1) - .maxMonitor(5) - .monitorCount(0) - .maxAddress(1000) - .addressCount(0) - .dateCreated(new Date()) - .currentQuota(1000) - .build(); - - const createdProject = await this.projectRepository.saveProject(project); - const member = Builder() - .projectId(createdProject.projectId) - .userId(user.userId) - .role(ProjectRole.OWNER) - .build(); - await this.projectMemberRepository.save(member); - return ProjectResponseDto.from(createdProject); - } - - async listProjects(user: User): Promise { - const projects = await this.projectRepository.listUserProjects(user.userId); - return projects.map((project) => ProjectResponseDto.from(project)); - } - - async getProjectCurrentQuora( - user: User, - projectId: string, - ): Promise { - const project = await this.projectRepository.findById(projectId); - if (!project) { - throw ErrorCode.PROJECT_NOT_FOUND.asException(); - } - - await this.checkProjectPermission(user, project.projectId); - return this.projectQuotaRepository - .getCurrentMonthQuota(projectId) - .then((quota) => { - if (quota) { - return ProjectQuotaResponseDto.from(quota); - } else { - const date = new Date(); - const month = - `${date.getMonth() + 1}`.padStart(2, '0') + `${date.getFullYear()}`; - return ProjectQuotaResponseDto.from( - Builder() - .projectId(project.projectId) - .month(month) - .ownerId(project.ownerId) - .quota(project.currentQuota) - .used(0) - .dateCreated(date) - .build(), - ); - } - }); - } -} diff --git a/app/apps/onebox/src/modules/quickstart/dto/quickstart.dto.ts b/app/apps/onebox/src/modules/quickstart/dto/quickstart.dto.ts deleted file mode 100644 index 93c704e..0000000 --- a/app/apps/onebox/src/modules/quickstart/dto/quickstart.dto.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ApiProperty, ApiResponseProperty } from '@nestjs/swagger'; -import { CreateMonitorDto } from 'libs/shared_modules/src/monitor/dto/monitor.dto'; -import { Type } from 'class-transformer'; - -export class QuickStartDto { - @ApiProperty() - email: string; - - @ApiProperty() - @Type(() => CreateMonitorDto) - monitor: CreateMonitorDto; - - @ApiProperty() - addresses: string[]; -} - -export class QuickStartResponseDto { - @ApiResponseProperty() - success: boolean; -} diff --git a/app/apps/onebox/src/modules/quickstart/quickstart.controller.ts b/app/apps/onebox/src/modules/quickstart/quickstart.controller.ts deleted file mode 100644 index d17f03a..0000000 --- a/app/apps/onebox/src/modules/quickstart/quickstart.controller.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Body, Controller, Post } from '@nestjs/common'; -import { ApiCreatedResponse, ApiOperation, ApiTags } from '@nestjs/swagger'; -import { QuickStartDto, QuickStartResponseDto } from './dto/quickstart.dto'; -import { QuickStartService } from './quickstart.service'; - -@ApiTags('Quickstart') -@Controller('quick-start') -export class QuickstartController { - constructor(private readonly quickstartService: QuickStartService) {} - - @ApiOperation({ summary: 'Quick Start' }) - @Post('') - @ApiCreatedResponse({ type: QuickStartResponseDto }) - async quickStart( - @Body() request: QuickStartDto, - ): Promise { - return this.quickstartService.quickStart(request); - } -} diff --git a/app/apps/onebox/src/modules/quickstart/quickstart.module.ts b/app/apps/onebox/src/modules/quickstart/quickstart.module.ts deleted file mode 100644 index d40ec13..0000000 --- a/app/apps/onebox/src/modules/quickstart/quickstart.module.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { DatabaseModule } from '@app/database'; -import { Module } from '@nestjs/common'; -import { MonitorAddressModule } from '../address/address.module'; -import { AuthModule } from '../auth/auth.module'; -import { MonitorModule } from '../monitor/monitor.module'; -import { ProjectModule } from '../project/project.module'; -import { UsersModule } from '../users/users.module'; -import { UsersProviders } from '../users/users.providers'; -import { QuickstartController } from './quickstart.controller'; -import { QuickStartService } from './quickstart.service'; -@Module({ - controllers: [QuickstartController], - providers: [QuickStartService, ...UsersProviders], - exports: [QuickStartService], - imports: [ - DatabaseModule, - UsersModule, - ProjectModule, - MonitorModule, - MonitorAddressModule, - AuthModule, - ], -}) -export class QuickStartModule {} diff --git a/app/apps/onebox/src/modules/quickstart/quickstart.service.ts b/app/apps/onebox/src/modules/quickstart/quickstart.service.ts deleted file mode 100644 index ebc904a..0000000 --- a/app/apps/onebox/src/modules/quickstart/quickstart.service.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { ErrorCode } from '@app/global/global.error'; -import { sendEmail } from '@app/utils/email.sender'; -import { renderTemplate } from '@app/utils/file-template'; -import { generateUUID } from '@app/utils/uuidUtils'; -import { Inject, Injectable } from '@nestjs/common'; -import { Builder } from 'builder-pattern'; -import { Model } from 'mongoose'; -import { MonitorAddressService } from '../address/address.service'; -import { CreateMonitorAddressDto } from '../address/dto/address.dto'; -import { AuthService } from '../auth/auth.service'; -import { MonitorService } from '../monitor/monitor.service'; -import { CreateProjectDto } from '../project/dto/project.dto'; -import { ProjectService } from '../project/project.service'; -import { User, UserStatus } from '../users/schemas/user.schema'; -import { UsersService } from '../users/users.service'; -import { QuickStartDto, QuickStartResponseDto } from './dto/quickstart.dto'; - -@Injectable() -export class QuickStartService { - constructor( - @Inject('USER_MODEL') private readonly userModel: Model, - private readonly userService: UsersService, - private readonly projectService: ProjectService, - private readonly monitorService: MonitorService, - private readonly monitorAddressService: MonitorAddressService, - private readonly authService: AuthService, - ) {} - - async quickStart(request: QuickStartDto): Promise { - const existedUser = await this.userModel.findOne({ email: request.email }); - if (existedUser) { - throw ErrorCode.ACCOUNT_EXISTS.asException('Email already exists'); - } - const userId = generateUUID(); - const user = await new this.userModel({ - email: request.email, - userId: userId, - dateCreated: new Date(), - enableEmailUpdate: true, - language: 'en', - status: UserStatus.Pending, - }).save(); - - const project = await this.projectService.createProject( - user, - Builder().name('My Project').build(), - ); - - const createMonitor = request.monitor; - createMonitor.projectId = project.projectId; - createMonitor.disabled = true; - const monitor = await this.monitorService.createMonitor( - user, - createMonitor, - ); - - const createAddress = { - monitorId: monitor.monitorId, - addresses: request.addresses, - } as CreateMonitorAddressDto; - await this.monitorAddressService.createMonitorAddress(user, createAddress); - - const activateToken = generateUUID(); - const tokenExpire = Date.now() + 365 * 24 * 60 * 60 * 1000; // 1 year - await this.userModel.updateOne( - { userId: user.userId }, - { - emailActivation: { - token: activateToken, - expire: tokenExpire, - monitorId: monitor.monitorId, - }, - }, - ); - const encodedToken = Buffer.from(`${user.email}:${activateToken}`).toString( - 'base64', - ); - const linkActivate = `https://${process.env.WEB_DOMAIN}/activate?token=${encodedToken}`; - const emailBody = await renderTemplate( - 'resources/email_template/activate.html', - { - linkActivate: linkActivate, - }, - ); - sendEmail(user.email, 'Account Activation', emailBody); - return Builder().success(true).build(); - } -} diff --git a/app/apps/onebox/src/modules/users/dto/change-password.dto.ts b/app/apps/onebox/src/modules/users/dto/change-password.dto.ts deleted file mode 100644 index 1504b63..0000000 --- a/app/apps/onebox/src/modules/users/dto/change-password.dto.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { ApiProperty, ApiResponseProperty } from '@nestjs/swagger'; -import { - IsNotEmpty, - IsString, - IsStrongPassword, - MaxLength, - MinLength, -} from 'class-validator'; - -export class ChangePasswordDto { - @ApiProperty() - @IsNotEmpty() - @IsString() - oldPassword: string; - - @ApiProperty() - @IsNotEmpty() - @IsString() - @MinLength(8) - @MaxLength(30) - @IsStrongPassword({ - minLength: 8, - minLowercase: 1, - minUppercase: 1, - minNumbers: 1, - minSymbols: 1, - }) - newPassword: string; - - @ApiProperty() - @IsNotEmpty() - @IsString() - confirmPassword: string; -} - -export class ChangePasswordResponseDto { - @ApiResponseProperty() - success: boolean; - constructor(success: boolean) { - this.success = success; - } -} diff --git a/app/apps/onebox/src/modules/users/dto/create-user.dto.ts b/app/apps/onebox/src/modules/users/dto/create-user.dto.ts deleted file mode 100644 index 7680c53..0000000 --- a/app/apps/onebox/src/modules/users/dto/create-user.dto.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { - IsEmail, - IsNotEmpty, - IsString, - IsStrongPassword, - MaxLength, - MinLength, -} from 'class-validator'; - -export class CreateUserDto { - @ApiProperty() - @IsString() - @IsEmail() - @IsNotEmpty() - email: string; - - @ApiProperty() - @IsString() - @IsNotEmpty() - @MinLength(8) - @MaxLength(30) - @IsStrongPassword({ - minLength: 8, - minLowercase: 1, - minUppercase: 1, - minNumbers: 1, - minSymbols: 1, - }) - password: string; - - @ApiProperty() - country: string; - - @ApiProperty() - name: string; - - @ApiProperty({ - default: false, - }) - enableEmailUpdate: boolean; - - @ApiProperty({ - default: 'en', - }) - language: string; -} diff --git a/app/apps/onebox/src/modules/users/dto/forgot-password.dto.ts b/app/apps/onebox/src/modules/users/dto/forgot-password.dto.ts deleted file mode 100644 index 4cf15a8..0000000 --- a/app/apps/onebox/src/modules/users/dto/forgot-password.dto.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { ApiProperty, ApiResponseProperty } from '@nestjs/swagger'; -import { - IsEmail, - IsNotEmpty, - IsString, - IsStrongPassword, - MaxLength, - MinLength, -} from 'class-validator'; - -export class ForgotPasswordDto { - @ApiProperty() - @IsEmail() - @IsNotEmpty() - email: string; -} - -export class ForgotPasswordResponseDto { - @ApiResponseProperty() - success: boolean; - constructor(success: boolean) { - this.success = success; - } -} - -export class ResetPasswordDto { - @ApiProperty() - @IsNotEmpty() - @IsEmail() - email: string; - - @ApiProperty() - @IsNotEmpty() - @IsString() - token: string; - - @ApiProperty() - @IsNotEmpty() - @IsString() - @MinLength(8) - @MaxLength(30) - @IsStrongPassword({ - minLength: 8, - minLowercase: 1, - minUppercase: 1, - minNumbers: 1, - minSymbols: 1, - }) - password: string; - - @ApiProperty() - @IsNotEmpty() - @IsString() - confirmPassword: string; -} - -export class ResetPasswordResponseDto { - @ApiResponseProperty() - success: boolean; - constructor(success: boolean) { - this.success = success; - } -} diff --git a/app/apps/onebox/src/modules/users/dto/user-profile.dto.ts b/app/apps/onebox/src/modules/users/dto/user-profile.dto.ts deleted file mode 100644 index f7416c8..0000000 --- a/app/apps/onebox/src/modules/users/dto/user-profile.dto.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { ApiResponseProperty } from '@nestjs/swagger'; -import { User } from '../schemas/user.schema'; - -export class UserProfileDto { - @ApiResponseProperty() - userId: string; - @ApiResponseProperty() - email: string; - @ApiResponseProperty() - name: string; - @ApiResponseProperty() - country: string; - @ApiResponseProperty() - dateCreated: Date; - @ApiResponseProperty() - enableEmailUpdate: boolean; - @ApiResponseProperty() - language: string; - - static from(user: User) { - return new UserProfileDto(user); - } - - constructor(user: User) { - this.userId = user.userId; - this.email = user.email; - this.name = user.name; - this.country = user.country; - this.dateCreated = user.dateCreated; - this.enableEmailUpdate = user.enableEmailUpdate; - this.language = user.language; - } -} diff --git a/app/apps/onebox/src/modules/users/schemas/user.schema.ts b/app/apps/onebox/src/modules/users/schemas/user.schema.ts deleted file mode 100644 index d72ad97..0000000 --- a/app/apps/onebox/src/modules/users/schemas/user.schema.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; -import { HydratedDocument } from 'mongoose'; - -export type UserDocument = HydratedDocument; - -export enum UserStatus { - Active = 'active', - Pending = 'pending', - Disabled = 'disabled', -} - -@Schema() -export class User { - @Prop({ required: true, unique: true }) - userId: string; - - @Prop({ required: true, unique: true, lowercase: true }) - email: string; - - @Prop() - password: string; - - @Prop() - passwordHash: string; - - @Prop() - name: string; - - @Prop() - country: string; - - @Prop({ default: Date.now() }) - dateCreated: Date; - - @Prop({ default: false }) - enableEmailUpdate: boolean; - - @Prop({ default: 'en' }) - language: string; - - @Prop({ default: UserStatus.Active }) - status: UserStatus; - - @Prop({ type: Object }) - forgotPassword: { - token: string; - expire: number; - }; - - @Prop({ type: Object }) - emailLogin: { - token: string; - expire: number; - }; - - @Prop({ type: Object }) - emailActivation: { - token: string; - expire: number; - monitorId: string; - }; -} - -export const UserSchema = SchemaFactory.createForClass(User); diff --git a/app/apps/onebox/src/modules/users/users.controller.ts b/app/apps/onebox/src/modules/users/users.controller.ts deleted file mode 100644 index 2481d7e..0000000 --- a/app/apps/onebox/src/modules/users/users.controller.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { - Body, - Controller, - Get, - HttpCode, - Post, - Req, - UseGuards, - UsePipes, -} from '@nestjs/common'; -import { - ApiBearerAuth, - ApiCreatedResponse, - ApiOkResponse, - ApiOperation, - ApiTags, -} from '@nestjs/swagger'; -import { Request } from 'express'; -import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; -import { User } from '../users/schemas/user.schema'; -import { - ChangePasswordDto, - ChangePasswordResponseDto, -} from './dto/change-password.dto'; -import { CreateUserDto } from './dto/create-user.dto'; -import { - ForgotPasswordDto, - ForgotPasswordResponseDto, - ResetPasswordDto, - ResetPasswordResponseDto, -} from './dto/forgot-password.dto'; -import { UserProfileDto } from './dto/user-profile.dto'; -import { CreateUserValidationPipe } from './users.pipe'; -import { UsersService } from './users.service'; - -@ApiTags('User') -@Controller('user') -export class UsersController { - constructor(private usersService: UsersService) {} - - @ApiOperation({ summary: 'Register new account' }) - @Post('/register') - @UsePipes(new CreateUserValidationPipe()) - @ApiCreatedResponse({ type: UserProfileDto }) - async register(@Body() user: CreateUserDto): Promise { - const result: InstanceType = await this.usersService.create( - user, - ); - return UserProfileDto.from(result); - } - - @ApiOperation({ summary: 'Get user profile' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Get('profile') - @ApiOkResponse({ type: UserProfileDto }) - async getProfile(@Req() req: Request): Promise { - return UserProfileDto.from(req.user as User); - } - - @ApiOperation({ summary: 'Change user password' }) - @ApiBearerAuth('JWT') - @UseGuards(JwtAuthGuard) - @Post('change-password') - @HttpCode(200) - @ApiOkResponse({ type: ChangePasswordResponseDto }) - async changePassword( - @Req() req: Request, - @Body() changePasswordDto: ChangePasswordDto, - ): Promise { - return this.usersService.changePassword( - req.user as User, - changePasswordDto, - ); - } - - @ApiOperation({ summary: 'Forgot password' }) - @Post('forgot-password') - @HttpCode(200) - @ApiOkResponse({ type: ForgotPasswordResponseDto }) - async forgotPassword( - @Body() forgotPasswordDto: ForgotPasswordDto, - ): Promise { - return this.usersService.forgotPassword(forgotPasswordDto); - } - - @ApiOperation({ summary: 'Reset password' }) - @Post('reset-password') - @HttpCode(200) - @ApiOkResponse({ type: ResetPasswordResponseDto }) - async resetPassword( - @Body() resetPasswordDto: ResetPasswordDto, - ): Promise { - return this.usersService.resetPassword(resetPasswordDto); - } -} diff --git a/app/apps/onebox/src/modules/users/users.module.ts b/app/apps/onebox/src/modules/users/users.module.ts deleted file mode 100644 index d12a1d2..0000000 --- a/app/apps/onebox/src/modules/users/users.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { DatabaseModule } from '@app/database'; -import { MonitorModule } from '@app/shared_modules/monitor/monitor.module'; -import { Module } from '@nestjs/common'; -import { ProjectModule } from '../project/project.module'; -import { UsersController } from './users.controller'; -import { UsersProviders } from './users.providers'; -import { UsersService } from './users.service'; -@Module({ - controllers: [UsersController], - providers: [UsersService, ...UsersProviders], - exports: [UsersService], - imports: [DatabaseModule, ProjectModule, MonitorModule], -}) -export class UsersModule {} diff --git a/app/apps/onebox/src/modules/users/users.pipe.ts b/app/apps/onebox/src/modules/users/users.pipe.ts deleted file mode 100644 index 8ecbf17..0000000 --- a/app/apps/onebox/src/modules/users/users.pipe.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { ErrorCode } from '@app/global/global.error'; -import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common'; -import { plainToInstance } from 'class-transformer'; -import { validate } from 'class-validator'; - -@Injectable() -export class CreateUserValidationPipe implements PipeTransform { - async transform(value: any, { metatype }: ArgumentMetadata) { - if (!metatype || !this.toValidate(metatype)) { - return value; - } - const object = plainToInstance(metatype, value); - const errors = await validate(object); - if (errors.length > 0) { - const err = this.buildError(errors); - throw ErrorCode.BAD_REQUEST.asException('Invalid data', err); - } - return value; - } - - private buildError(errors) { - const result = { - error: {}, - }; - errors.forEach((el) => { - const prop = el.property; - result.error[prop] = {}; - Object.entries(el.constraints).forEach((constraint) => { - result.error[prop][constraint[0]] = `${constraint[1]}`; - }); - }); - return result; - } - - // eslint-disable-next-line @typescript-eslint/ban-types - private toValidate(metatype: Function): boolean { - // eslint-disable-next-line @typescript-eslint/ban-types - const types: Function[] = [String, Boolean, Number, Array, Object]; - return !types.includes(metatype); - } -} diff --git a/app/apps/onebox/src/modules/users/users.providers.ts b/app/apps/onebox/src/modules/users/users.providers.ts deleted file mode 100644 index 4ed8699..0000000 --- a/app/apps/onebox/src/modules/users/users.providers.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Connection } from 'mongoose'; -import { UserSchema } from './schemas/user.schema'; - -export const UsersProviders = [ - { - provide: 'USER_MODEL', - useFactory: (connection: Connection) => - connection.model('User', UserSchema), - inject: ['DATABASE_CONNECTION'], - }, -]; diff --git a/app/apps/onebox/src/modules/users/users.service.ts b/app/apps/onebox/src/modules/users/users.service.ts deleted file mode 100644 index 3f6e1bd..0000000 --- a/app/apps/onebox/src/modules/users/users.service.ts +++ /dev/null @@ -1,252 +0,0 @@ -import { Inject, Injectable, Logger } from '@nestjs/common'; -import { Model } from 'mongoose'; - -import { ErrorCode } from '@app/global/global.error'; -import { MonitorRepository } from '@app/shared_modules/monitor/repositories/monitor.repository'; -import { comparePassword, hashPassword } from '@app/utils/bcrypt.util'; -import { sendEmail } from '@app/utils/email.sender'; -import { renderTemplate } from '@app/utils/file-template'; -import { hashMd5 } from '@app/utils/md5'; -import { generateUUID } from '@app/utils/uuidUtils'; -import { Builder } from 'builder-pattern'; -import { CreateProjectDto } from '../project/dto/project.dto'; -import { ProjectService } from '../project/project.service'; -import { - ChangePasswordDto, - ChangePasswordResponseDto, -} from './dto/change-password.dto'; -import { CreateUserDto } from './dto/create-user.dto'; -import { - ForgotPasswordDto, - ForgotPasswordResponseDto, - ResetPasswordDto, - ResetPasswordResponseDto, -} from './dto/forgot-password.dto'; -import { User, UserStatus } from './schemas/user.schema'; - -@Injectable() -export class UsersService { - constructor( - @Inject('USER_MODEL') private readonly userModel: Model, - private readonly projectService: ProjectService, - private readonly monitorRepository: MonitorRepository, - ) {} - - /** - * Create new user. - * - * @param createUserDto The user to create. - * @returns {User} - */ - async create(createUserDto: CreateUserDto): Promise { - const existedUser = await this.findOne(createUserDto.email); - if (existedUser) { - throw ErrorCode.ACCOUNT_EXISTS.asException('Email already exists'); - } - const userId = generateUUID(); - // store password as hash - createUserDto.password = await hashPassword(createUserDto.password); - const passwordHash = hashMd5(createUserDto.password); - const user = await new this.userModel({ - ...createUserDto, - userId, - passwordHash, - status: UserStatus.Active, - dateCreated: new Date(), - }).save(); - const linkLogin = `https://${process.env.WEB_DOMAIN}/sign-in`; - const emailBody = await renderTemplate( - 'resources/email_template/welcome.html', - { - linkLogin, - }, - ); - sendEmail(user.email, 'Welcome', emailBody); - this.projectService - .createProject( - user, - Builder().name('My Project').build(), - ) - .then((project) => { - Logger.log('Create project successfully: {}', project); - }); - return user; - } - - /** - * Get all Users. - * - * @returns {User[]} - */ - async findAll(): Promise { - return this.userModel.find().exec(); - } - - /** - * Find a single user by their email. - * - * @param email The users email to filter by. - * @returns {User} - */ - async findOne(email: string): Promise { - return this.userModel.findOne({ email: email }); - } - - /** - * Find a single user by their userId. - * - * @param userId The users userId to filter by. - * @returns {User} - */ - async findOneByUserId(userId: string): Promise { - return this.userModel.findOne({ userId: userId }); - } - - /** - * Change user password. - * @param user user - * @param changePasswordDto changePasswordDto - * @returns {ChangePasswordResponseDto} - */ - async changePassword( - user: User, - changePasswordDto: ChangePasswordDto, - ): Promise { - // check new password - if (changePasswordDto.newPassword !== changePasswordDto.confirmPassword) { - throw ErrorCode.PASSWORD_NOT_MATCH.asException( - 'New password and confirm password do not match', - ); - } - - // check old password - if ( - !(await comparePassword(changePasswordDto.oldPassword, user.password)) - ) { - throw ErrorCode.WRONG_PASSWORD.asException('Wrong old password'); - } - - // update password - user.password = await hashPassword(changePasswordDto.newPassword); - user.passwordHash = hashMd5(user.password); - await this.userModel.updateOne( - { userId: user.userId }, - { password: user.password, passwordHash: user.passwordHash }, - ); - return new ChangePasswordResponseDto(true); - } - - /** - * Forgot password - * @param forgotPasswordDto forgotPasswordDto - * @returns {ForgotPasswordResponseDto} - */ - async forgotPassword( - forgotPasswordDto: ForgotPasswordDto, - ): Promise { - const user = await this.findOne(forgotPasswordDto.email); - if (!user) { - throw ErrorCode.ACCOUNT_NOT_FOUND.asException('Email not found'); - } - const forgotPasswordToken = generateUUID(); - const forgotPasswordExpire = Date.now() + 24 * 60 * 60 * 1000; - await this.userModel.updateOne( - { userId: user.userId }, - { - forgotPassword: { - token: forgotPasswordToken, - expire: forgotPasswordExpire, - }, - }, - ); - const linkResetPassword = `https://${process.env.WEB_DOMAIN}/reset-password?token=${forgotPasswordToken}&email=${user.email}`; - const emailBody = await renderTemplate( - 'resources/email_template/forgot_password.html', - { - linkResetPassword, - expire: new Date(forgotPasswordExpire).toUTCString(), - }, - ); - sendEmail(user.email, 'Reset Password Request', emailBody); - return new ForgotPasswordResponseDto(true); - } - - /** - * Reset password - * @param resetPasswordDto resetPasswordDto - * @returns {ResetPasswordResponseDto} - */ - async resetPassword( - resetPasswordDto: ResetPasswordDto, - ): Promise { - const user = await this.findOne(resetPasswordDto.email); - if (!user) { - throw ErrorCode.ACCOUNT_NOT_FOUND.asException(); - } - if ( - !user.forgotPassword || - user.forgotPassword.token !== resetPasswordDto.token - ) { - throw ErrorCode.INVALID_TOKEN.asException(); - } - if (user.forgotPassword.expire < Date.now()) { - throw ErrorCode.INVALID_TOKEN.asException('Token expired'); - } - if (resetPasswordDto.password !== resetPasswordDto.confirmPassword) { - throw ErrorCode.PASSWORD_NOT_MATCH.asException( - 'New password and confirm password do not match', - ); - } - user.password = await hashPassword(resetPasswordDto.password); - user.passwordHash = hashMd5(user.password); - await this.userModel.updateOne( - { userId: user.userId }, - { - password: user.password, - passwordHash: user.passwordHash, - forgotPassword: null, - }, - ); - const linkLogin = `https://${process.env.WEB_DOMAIN}/sign-in`; - const emailBody = await renderTemplate( - 'resources/email_template/reset_password_success.html', - { - linkLogin, - }, - ); - sendEmail(user.email, 'Password Reset Successfully', emailBody); - return new ResetPasswordResponseDto(true); - } - - async activateAccount(token: string): Promise { - const decodedToken = Buffer.from(token, 'base64').toString(); - const [email, activateToken] = decodedToken.split(':'); - const user = await this.findOne(email); - if (!user || !user.emailActivation) { - throw ErrorCode.WRONG_EMAIL_OR_TOKEN.asException(); - } - if (user.emailActivation.token !== activateToken) { - throw ErrorCode.WRONG_EMAIL_OR_TOKEN.asException(); - } - if (user.emailActivation.expire < Date.now()) { - throw ErrorCode.WRONG_EMAIL_OR_TOKEN.asException(); - } - const updatedUser = await this.userModel.findOneAndUpdate( - { userId: user.userId }, - { - $set: { - status: UserStatus.Active, - }, - $unset: { emailLogin: '' }, - }, - { new: true }, - ); - const updateMonitor = new Map(); - updateMonitor['disabled'] = false; - await this.monitorRepository.updateMonitor( - user.emailActivation.monitorId, - updateMonitor, - ); - return updatedUser; - } -} diff --git a/app/apps/onebox/tsconfig.app.json b/app/apps/onebox/tsconfig.app.json deleted file mode 100644 index 758c8ef..0000000 --- a/app/apps/onebox/tsconfig.app.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "declaration": false, - "outDir": "../../dist/apps/onebox" - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] -}