diff --git a/src/app.module.ts b/src/app.module.ts index 7a8461f..cef2349 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -106,6 +106,7 @@ import { OtpVerificationModule } from './modules/configuration/otp-verification/ import { OtpVerificationModel } from './modules/configuration/otp-verification/data/models/otp-verification.model'; import { OtpVerifierModel } from './modules/configuration/otp-verification/data/models/otp-verifier.model'; import { RescheduleVerificationModel } from './modules/booking-online/order/data/models/reschedule-verification.model'; +import { OtpCheckerGuard } from './core/guards/domain/otp-checker.guard'; @Module({ imports: [ @@ -246,6 +247,8 @@ import { RescheduleVerificationModel } from './modules/booking-online/order/data providers: [ AuthService, PrivilegeService, + OtpCheckerGuard, + /** * By default all request from client will protect by JWT * if there is some endpoint/function that does'nt require authentication diff --git a/src/core/guards/domain/otp-checker.guard.ts b/src/core/guards/domain/otp-checker.guard.ts new file mode 100644 index 0000000..61e5146 --- /dev/null +++ b/src/core/guards/domain/otp-checker.guard.ts @@ -0,0 +1,57 @@ +import { + CanActivate, + ExecutionContext, + Injectable, + UnprocessableEntityException, +} from '@nestjs/common'; +import { InjectDataSource } from '@nestjs/typeorm'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { OtpVerificationModel } from 'src/modules/configuration/otp-verification/data/models/otp-verification.model'; +import { OtpVerificationEntity } from 'src/modules/configuration/otp-verification/domain/entities/otp-verification.entity'; +import { DataSource } from 'typeorm'; + +@Injectable() +export class OtpCheckerGuard implements CanActivate { + constructor( + @InjectDataSource(CONNECTION_NAME.DEFAULT) + protected readonly dataSource: DataSource, + ) {} + + get otpRepository() { + return this.dataSource.getRepository(OtpVerificationModel); + } + + async canActivate(context: ExecutionContext): Promise { + const request = context.switchToHttp().getRequest(); + const verificationCode = request.headers['x-verification-code']; + console.log({ verificationCode }); + + if (verificationCode) { + const decoded = Buffer.from(verificationCode, 'base64').toString('ascii'); + const [dataIdentity, otpCode] = decoded.split('|'); + + let otpData: OtpVerificationEntity; + + otpData = await this.otpRepository.findOne({ + where: { + otp_code: otpCode, + target_id: dataIdentity, + }, + }); + + if (!otpData) { + otpData = await this.otpRepository.findOne({ + where: { + otp_code: otpCode, + reference: dataIdentity, + }, + }); + } + + // console.log({ dataIdentity, otpCode, otpData }); + if (otpData && otpData?.verified_at) return true; + } + + throw new UnprocessableEntityException('OTP not verified.'); + } +} diff --git a/src/modules/configuration/otp-verification/infrastructure/guards/otp-auth-guard.ts b/src/modules/configuration/otp-verification/infrastructure/guards/otp-auth.guard.ts similarity index 100% rename from src/modules/configuration/otp-verification/infrastructure/guards/otp-auth-guard.ts rename to src/modules/configuration/otp-verification/infrastructure/guards/otp-auth.guard.ts diff --git a/src/modules/configuration/otp-verification/infrastructure/otp-verification-data.controller.ts b/src/modules/configuration/otp-verification/infrastructure/otp-verification-data.controller.ts index 1d1124f..b441441 100644 --- a/src/modules/configuration/otp-verification/infrastructure/otp-verification-data.controller.ts +++ b/src/modules/configuration/otp-verification/infrastructure/otp-verification-data.controller.ts @@ -16,7 +16,7 @@ import { OtpVerifierCreateDto, OtpVerifyDto, } from './dto/otp-verification.dto'; -import { OtpAuthGuard } from './guards/otp-auth-guard'; +import { OtpAuthGuard } from './guards/otp-auth.guard'; import { OtpVerifierService } from '../data/services/otp-verifier.service'; @ApiTags(`${MODULE_NAME.OTP_VERIFICATIONS.split('-').join(' ')} - data`) diff --git a/src/modules/configuration/otp-verification/otp-verification.module.ts b/src/modules/configuration/otp-verification/otp-verification.module.ts index efdfba6..d4e933d 100644 --- a/src/modules/configuration/otp-verification/otp-verification.module.ts +++ b/src/modules/configuration/otp-verification/otp-verification.module.ts @@ -10,7 +10,7 @@ import { } from './infrastructure/otp-verification-data.controller'; import { OtpVerificationService } from './data/services/otp-verification.service'; import { OtpVerifierModel } from './data/models/otp-verifier.model'; -import { OtpAuthGuard } from './infrastructure/guards/otp-auth-guard'; +import { OtpAuthGuard } from './infrastructure/guards/otp-auth.guard'; import { JwtModule } from '@nestjs/jwt'; import { JWT_EXPIRED } from 'src/core/sessions/constants'; diff --git a/src/modules/item-related/item/infrastructure/item-data.controller.ts b/src/modules/item-related/item/infrastructure/item-data.controller.ts index 01ed1dd..76e43fb 100644 --- a/src/modules/item-related/item/infrastructure/item-data.controller.ts +++ b/src/modules/item-related/item/infrastructure/item-data.controller.ts @@ -6,6 +6,7 @@ import { Patch, Post, Put, + UseGuards, } from '@nestjs/common'; import { ItemDataOrchestrator } from '../domain/usecases/item-data.orchestrator'; import { ItemDto } from './dto/item.dto'; @@ -16,6 +17,7 @@ import { BatchResult } from 'src/core/response/domain/ok-response.interface'; import { BatchIdsDto } from 'src/core/modules/infrastructure/dto/base-batch.dto'; import { Public } from 'src/core/guards'; import { UpdateItemPriceDto } from './dto/update-item-price.dto'; +import { OtpCheckerGuard } from 'src/core/guards/domain/otp-checker.guard'; @ApiTags(`${MODULE_NAME.ITEM.split('-').join(' ')} - data`) @Controller(`v1/${MODULE_NAME.ITEM}`) @@ -41,19 +43,18 @@ export class ItemDataController { } @Patch(':id/active') - // TODO => simpan OTP update yang disikim dari request ini + @UseGuards(OtpCheckerGuard) async active(@Param('id') dataId: string): Promise { return await this.orchestrator.active(dataId); } @Put('/batch-active') - // TODO => simpan OTP update yang disikim dari request ini async batchActive(@Body() body: BatchIdsDto): Promise { return await this.orchestrator.batchActive(body.ids); } @Patch(':id/confirm') - // TODO => simpan OTP update yang disikim dari request ini + @UseGuards(OtpCheckerGuard) async confirm(@Param('id') dataId: string): Promise { return await this.orchestrator.confirm(dataId); } @@ -74,7 +75,7 @@ export class ItemDataController { } @Put(':id') - // TODO => simpan OTP update yang disikim dari request ini + @UseGuards(OtpCheckerGuard) async update( @Param('id') dataId: string, @Body() data: ItemDto, diff --git a/src/modules/season-related/season-period/infrastructure/season-period-data.controller.ts b/src/modules/season-related/season-period/infrastructure/season-period-data.controller.ts index 20aa20a..4b8a761 100644 --- a/src/modules/season-related/season-period/infrastructure/season-period-data.controller.ts +++ b/src/modules/season-related/season-period/infrastructure/season-period-data.controller.ts @@ -6,6 +6,7 @@ import { Patch, Post, Put, + UseGuards, } from '@nestjs/common'; import { SeasonPeriodDataOrchestrator } from '../domain/usecases/season-period-data.orchestrator'; import { SeasonPeriodDto } from './dto/season-period.dto'; @@ -18,6 +19,7 @@ import { Public } from 'src/core/guards'; import { UpdateSeasonPeriodDto } from './dto/update-season-period.dto'; import { UpdateSeasonPeriodItemDto } from './dto/update-season-period-item.dto'; import { UpdateSeasonPriceDto } from './dto/update-season-price.dto'; +import { OtpCheckerGuard } from 'src/core/guards/domain/otp-checker.guard'; @ApiTags(`${MODULE_NAME.SEASON_PERIOD.split('-').join(' ')} - data`) @Controller(`v1/${MODULE_NAME.SEASON_PERIOD}`) @@ -27,11 +29,13 @@ export class SeasonPeriodDataController { constructor(private orchestrator: SeasonPeriodDataOrchestrator) {} @Post() + @UseGuards(OtpCheckerGuard) async create(@Body() data: SeasonPeriodDto): Promise { return await this.orchestrator.create(data); } @Post('/update-price') + @UseGuards(OtpCheckerGuard) async updatePrice(@Body() body: UpdateSeasonPriceDto): Promise { return await this.orchestrator.updatePrice(body); } @@ -82,6 +86,7 @@ export class SeasonPeriodDataController { // pemisahan update data dengan update items dikarenakan payload (based on tampilan) berbeda // TODO => simpan OTP update yang disikim dari request ini @Put(':id/items') + @UseGuards(OtpCheckerGuard) async updateItems( @Param('id') dataId: string, @Body() data: UpdateSeasonPeriodItemDto, diff --git a/src/modules/transaction/refund/domain/usecases/managers/detail-refund.manager.ts b/src/modules/transaction/refund/domain/usecases/managers/detail-refund.manager.ts index 722f94b..b40b563 100644 --- a/src/modules/transaction/refund/domain/usecases/managers/detail-refund.manager.ts +++ b/src/modules/transaction/refund/domain/usecases/managers/detail-refund.manager.ts @@ -31,6 +31,10 @@ export class DetailRefundManager extends BaseDetailManager { 'items.bundling_items', 'items.refunds item_refunds', 'item_refunds.refund item_refunds_refund', + + 'transaction.items transaction_items', + 'transaction_items.item transaction_items_item', + 'transaction_items_item.time_group transaction_items_item_time_group', ], // relation yang hanya ingin dihitung (akan return number) @@ -65,6 +69,10 @@ export class DetailRefundManager extends BaseDetailManager { 'item_refunds', 'item_refunds_refund.id', 'item_refunds_refund.status', + + 'transaction_items', + 'transaction_items_item', + 'transaction_items_item_time_group', ]; } diff --git a/src/modules/transaction/transaction/domain/usecases/managers/detail-transaction.manager.ts b/src/modules/transaction/transaction/domain/usecases/managers/detail-transaction.manager.ts index b788110..6d229b6 100644 --- a/src/modules/transaction/transaction/domain/usecases/managers/detail-transaction.manager.ts +++ b/src/modules/transaction/transaction/domain/usecases/managers/detail-transaction.manager.ts @@ -31,6 +31,9 @@ export class DetailTransactionManager extends BaseDetailManager item.refund.id == refundId); + const timeGroup = itemData?.item?.time_group; + return { item: { id: itemData.item_id, @@ -57,6 +59,7 @@ export function mappingTransaction(data, refundId?: string) { }, breakdown_bundling: itemData.breakdown_bundling, bundling_items: itemData.bundling_items, + time_group: timeGroup, }, id: itemData.id, refund: refund, diff --git a/src/modules/transaction/transaction/infrastructure/transaction-data.controller.ts b/src/modules/transaction/transaction/infrastructure/transaction-data.controller.ts index 97d3e30..5b239ff 100644 --- a/src/modules/transaction/transaction/infrastructure/transaction-data.controller.ts +++ b/src/modules/transaction/transaction/infrastructure/transaction-data.controller.ts @@ -20,7 +20,8 @@ import { BatchResult } from 'src/core/response/domain/ok-response.interface'; import { BatchIdsDto } from 'src/core/modules/infrastructure/dto/base-batch.dto'; import { Public } from 'src/core/guards'; import { DownloadPdfDto } from './dto/donwload-pdf.dto'; -import { OtpAuthGuard } from 'src/modules/configuration/otp-verification/infrastructure/guards/otp-auth-guard'; +import { OtpAuthGuard } from 'src/modules/configuration/otp-verification/infrastructure/guards/otp-auth.guard'; +import { OtpCheckerGuard } from 'src/core/guards/domain/otp-checker.guard'; @ApiTags(`${MODULE_NAME.TRANSACTION.split('-').join(' ')} - data`) @Controller(`v1/${MODULE_NAME.TRANSACTION}`) @@ -53,6 +54,7 @@ export class TransactionDataController { } @Patch(':id/confirm-data') + @UseGuards(OtpCheckerGuard) async confirmData(@Param('id') dataId: string): Promise { return await this.orchestrator.confirmData(dataId); } @@ -63,6 +65,7 @@ export class TransactionDataController { } @Patch(':id/confirm') + @UseGuards(OtpCheckerGuard) async confirm(@Param('id') dataId: string): Promise { return await this.orchestrator.confirm(dataId); } diff --git a/src/modules/user-related/user/infrastructure/user-data.controller.ts b/src/modules/user-related/user/infrastructure/user-data.controller.ts index d3b6d64..34adc6b 100644 --- a/src/modules/user-related/user/infrastructure/user-data.controller.ts +++ b/src/modules/user-related/user/infrastructure/user-data.controller.ts @@ -6,6 +6,7 @@ import { Patch, Post, Put, + UseGuards, } from '@nestjs/common'; import { UserDataOrchestrator } from '../domain/usecases/user-data.orchestrator'; import { UserDto } from './dto/user.dto'; @@ -17,6 +18,7 @@ import { BatchIdsDto } from 'src/core/modules/infrastructure/dto/base-batch.dto' import { Public } from 'src/core/guards'; import { UpdateUserDto } from './dto/update-user.dto'; import { UpdatePasswordUserDto } from './dto/update-password-user.dto'; +import { OtpCheckerGuard } from 'src/core/guards/domain/otp-checker.guard'; @ApiTags(`${MODULE_NAME.USER.split('-').join(' ')} - data`) @Controller(`v1/${MODULE_NAME.USER}`) @@ -36,25 +38,23 @@ export class UserDataController { } @Patch(':id/active') - // TODO => simpan OTP update yang disikim dari request ini + @UseGuards(OtpCheckerGuard) async active(@Param('id') dataId: string): Promise { return await this.orchestrator.active(dataId); } @Put('/batch-active') - // TODO => simpan OTP update yang disikim dari request ini async batchActive(@Body() body: BatchIdsDto): Promise { return await this.orchestrator.batchActive(body.ids); } @Patch(':id/confirm') - // TODO => simpan OTP update yang disikim dari request ini + @UseGuards(OtpCheckerGuard) async confirm(@Param('id') dataId: string): Promise { return await this.orchestrator.confirm(dataId); } @Put('/batch-confirm') - // TODO => simpan OTP update yang disikim dari request ini async batchConfirm(@Body() body: BatchIdsDto): Promise { return await this.orchestrator.batchConfirm(body.ids); }