diff --git a/src/request-management/request-management.service.ts b/src/request-management/request-management.service.ts index cfdeb38..93d2b20 100644 --- a/src/request-management/request-management.service.ts +++ b/src/request-management/request-management.service.ts @@ -4679,6 +4679,24 @@ export class RequestManagementService { this.verifyExpertAccessForBlameV2(req, actor); const phone = (dto?.phoneNumber || "").trim(); if (!phone) throw new BadRequestException("phoneNumber is required"); + + const twoMinutesAgo = new Date(Date.now() - 2 * 60 * 1000); + const recentlySentToPhone = (req.history || []) + .slice() + .reverse() + .find( + (event: any) => + event?.type === "PARTY_OTP_SENT" && + event?.metadata?.phoneNumber === phone && + event?.timestamp && + new Date(event.timestamp) > twoMinutesAgo, + ); + if (recentlySentToPhone) { + throw new BadRequestException( + `(${phone}): OTP was sent recently. Please wait 2 minutes before requesting again.`, + ); + } + try { await this.userAuthService.sendOtpRequest(phone); } catch (e: any) { @@ -4689,6 +4707,18 @@ export class RequestManagementService { } throw e; } + if (!Array.isArray(req.history)) req.history = []; + req.history.push({ + type: "PARTY_OTP_SENT", + actor: { + actorId: new Types.ObjectId(actor.sub), + actorName: `${actor.firstName || ""} ${actor.lastName || ""}`.trim(), + actorType: + actor?.role === RoleEnum.REGISTRAR ? "registrar" : "field_expert", + }, + metadata: { phoneNumber: phone }, + } as any); + await (req as any).save(); return { sent: true, message: `OTP sent to ${phone}. Collect the code from the party, then call verify-party-otp.`,