import { Body, Controller, Get, Post, Request, Route, Security, Tags } from "tsoa"; import prisma from "../db"; import nodemailer from "nodemailer"; import { notFoundError } from "../utils/error"; import { RequestWithLineUser } from "../interfaces/user"; import HttpError from "../interfaces/http-error"; import HttpStatus from "../interfaces/http-status"; type SendEmail = { email: string; } & ({ legalPersonNo: string } | { citizenId: string }); type VerificationPayload = { email: string; otp: string; } & ({ legalPersonNo: string } | { citizenId: string }); let emailTransport: ReturnType<(typeof nodemailer)["createTransport"]>; @Route("/api/v1/verification") @Tags("Verification") export class verificationController extends Controller { @Get() @Security("line") async isRegistered(@Request() req: RequestWithLineUser) { return !!(await prisma.customerBranch.findFirst({ where: { userId: req.user.sub } })); } @Post("/send-otp") public async sendOTP(@Body() body: SendEmail) { if ( ![ process.env.SMTP_HOST, process.env.SMTP_PORT, process.env.SMTP_USER, process.env.SMTP_PASS, ].every(Boolean) ) { throw new HttpError( HttpStatus.PRECONDITION_FAILED, "SMTP not configured", "smtpNotConfigured", ); } if (!emailTransport) { emailTransport = nodemailer.createTransport({ host: process.env.SMTP_HOST!, port: +process.env.SMTP_PORT!, secure: false, // true for port 465, false for other ports auth: { user: process.env.SMTP_USER!, pass: process.env.SMTP_PASS!, }, }); } const generateOTP = Math.floor(100000 + Math.random() * 900000).toString(); const expiresTime = new Date(Date.now() + 5 * 60 * 1000); const dataCustomerBranch = await prisma.customerBranch.findFirst({ where: { email: body.email, ...("citizenId" in body ? { citizenId: body.citizenId, customer: { customerType: "PERS", }, } : { legalPersonNo: body.legalPersonNo, customer: { customerType: "CORP", }, }), }, }); if (!dataCustomerBranch) throw notFoundError("Customer Branch"); await emailTransport.sendMail({ from: process.env.SMTP_USER, to: body.email, subject: "Your OTP Code", text: `Your OTP Code ${generateOTP}`, html: `

Your OTP code is: ${generateOTP}

`, }); await prisma.customerBranch.update({ where: { id: dataCustomerBranch.id, }, data: { otpCode: generateOTP, otpExpires: expiresTime, }, }); return { message: "OTP sent successfully" }; } @Post("/verify-otp") @Security("line") public async verifyOTP(@Request() req: RequestWithLineUser, @Body() body: VerificationPayload) { const customerBranch = await prisma.customerBranch.findFirst({ where: { email: body.email, ...("citizenId" in body ? { citizenId: body.citizenId, customer: { customerType: "PERS", }, } : { legalPersonNo: body.legalPersonNo, customer: { customerType: "CORP", }, }), }, }); if (!customerBranch) throw notFoundError("Customer Branch"); if ( customerBranch.otpCode && customerBranch.otpCode === body.otp && customerBranch.otpExpires && customerBranch.otpExpires >= new Date() ) { const dataCustomer = await prisma.customerBranch.update({ where: { id: customerBranch.id, }, data: { userId: req.user.sub, }, }); return dataCustomer; } else { return "OTP ไม่ถูกต้อง"; } } }