From de43f0f28bd013d6e85bafb5b4a98e8dc74cd598 Mon Sep 17 00:00:00 2001 From: Firman Ramdhani <33869609+firmanramdhani@users.noreply.github.com> Date: Thu, 19 Jun 2025 15:55:01 +0700 Subject: [PATCH 1/7] feat(SPG-1236): setup otp checker guard --- src/app.module.ts | 3 + src/core/guards/domain/otp-checker.guard.ts | 57 +++++++++++++++++++ .../{otp-auth-guard.ts => otp-auth.guard.ts} | 0 .../otp-verification-data.controller.ts | 2 +- .../otp-verification.module.ts | 2 +- .../transaction-data.controller.ts | 2 +- 6 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 src/core/guards/domain/otp-checker.guard.ts rename src/modules/configuration/otp-verification/infrastructure/guards/{otp-auth-guard.ts => otp-auth.guard.ts} (100%) 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..2ef4802 --- /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, + }, + }); + } + + if (otpData && otpData?.verified_at) return true; + console.log({ dataIdentity, otpCode, otpData }); + } + + 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/transaction/transaction/infrastructure/transaction-data.controller.ts b/src/modules/transaction/transaction/infrastructure/transaction-data.controller.ts index 97d3e30..d2b401d 100644 --- a/src/modules/transaction/transaction/infrastructure/transaction-data.controller.ts +++ b/src/modules/transaction/transaction/infrastructure/transaction-data.controller.ts @@ -20,7 +20,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 { 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'; @ApiTags(`${MODULE_NAME.TRANSACTION.split('-').join(' ')} - data`) @Controller(`v1/${MODULE_NAME.TRANSACTION}`) From 822cfe606a2dff1ae28008b7ee534d4623d2db93 Mon Sep 17 00:00:00 2001 From: Firman Ramdhani <33869609+firmanramdhani@users.noreply.github.com> Date: Thu, 19 Jun 2025 15:55:19 +0700 Subject: [PATCH 2/7] feat(SPG-1236): implement otp checker guard on active and confirm user --- .../user/infrastructure/user-data.controller.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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); } From 8df836ff3e71774f468305850b5f9f67c82f1d05 Mon Sep 17 00:00:00 2001 From: Firman Ramdhani <33869609+firmanramdhani@users.noreply.github.com> Date: Thu, 19 Jun 2025 16:24:20 +0700 Subject: [PATCH 3/7] feat(SPG-1236): implement otp checker guard on session period --- src/core/guards/domain/otp-checker.guard.ts | 2 +- .../item/infrastructure/item-data.controller.ts | 9 +++++---- .../infrastructure/season-period-data.controller.ts | 4 ++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/core/guards/domain/otp-checker.guard.ts b/src/core/guards/domain/otp-checker.guard.ts index 2ef4802..00b1af2 100644 --- a/src/core/guards/domain/otp-checker.guard.ts +++ b/src/core/guards/domain/otp-checker.guard.ts @@ -48,8 +48,8 @@ export class OtpCheckerGuard implements CanActivate { }); } - if (otpData && otpData?.verified_at) return true; console.log({ dataIdentity, otpCode, otpData }); + if (otpData && otpData?.verified_at) return true; } throw new UnprocessableEntityException('OTP not verified.'); 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..dde6225 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); } From 08a35dfdf4b5e8043e8dd069b889e58e7f294242 Mon Sep 17 00:00:00 2001 From: Firman Ramdhani <33869609+firmanramdhani@users.noreply.github.com> Date: Thu, 19 Jun 2025 16:32:48 +0700 Subject: [PATCH 4/7] feat(SPG-1236): implement otp checker guard on booking transaction --- .../transaction/infrastructure/transaction-data.controller.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/transaction/transaction/infrastructure/transaction-data.controller.ts b/src/modules/transaction/transaction/infrastructure/transaction-data.controller.ts index d2b401d..5b239ff 100644 --- a/src/modules/transaction/transaction/infrastructure/transaction-data.controller.ts +++ b/src/modules/transaction/transaction/infrastructure/transaction-data.controller.ts @@ -21,6 +21,7 @@ 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 { 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); } From 42060384aa0ef844a8039e676237edd062a54556 Mon Sep 17 00:00:00 2001 From: Firman Ramdhani <33869609+firmanramdhani@users.noreply.github.com> Date: Thu, 19 Jun 2025 17:04:07 +0700 Subject: [PATCH 5/7] feat(SPG-1236): implement otp checker guard on session period --- .../infrastructure/season-period-data.controller.ts | 1 + 1 file changed, 1 insertion(+) 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 dde6225..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 @@ -86,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, From 83f33774651a0ead94dd5645b934f5caade9ac9e Mon Sep 17 00:00:00 2001 From: Firman Ramdhani <33869609+firmanramdhani@users.noreply.github.com> Date: Thu, 19 Jun 2025 17:09:42 +0700 Subject: [PATCH 6/7] feat(SPG-1236): setup otp checker guard --- src/core/guards/domain/otp-checker.guard.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/guards/domain/otp-checker.guard.ts b/src/core/guards/domain/otp-checker.guard.ts index 00b1af2..61e5146 100644 --- a/src/core/guards/domain/otp-checker.guard.ts +++ b/src/core/guards/domain/otp-checker.guard.ts @@ -48,7 +48,7 @@ export class OtpCheckerGuard implements CanActivate { }); } - console.log({ dataIdentity, otpCode, otpData }); + // console.log({ dataIdentity, otpCode, otpData }); if (otpData && otpData?.verified_at) return true; } From 63bb55b04be44ac053f40d93135fe2e627fc0cf0 Mon Sep 17 00:00:00 2001 From: Firman Ramdhani <33869609+firmanramdhani@users.noreply.github.com> Date: Thu, 19 Jun 2025 18:30:07 +0700 Subject: [PATCH 7/7] feat(SPG-1137): add time group at booking and refund detail --- .../domain/usecases/managers/detail-refund.manager.ts | 8 ++++++++ .../usecases/managers/detail-transaction.manager.ts | 5 +++++ .../managers/helpers/mapping-transaction.helper.ts | 3 +++ 3 files changed, 16 insertions(+) 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,