This commit is contained in:
2025-11-20 17:00:16 +05:30
5 changed files with 96 additions and 62 deletions

View File

@@ -199,6 +199,21 @@ functions:
path: /stepper path: /stepper
method: get method: get
getSuggestion:
handler: src/modules/minglaradmin/handlers/getSuggestion.handler
package:
patterns:
- 'src/modules/minglaradmin/**'
- 'common/**'
- 'src/common/**'
- 'node_modules/@prisma/client/**'
- 'node_modules/.prisma/**'
events:
- httpApi:
path: /minglaradmin/get-suggestion
method: get
minglarRegistration: minglarRegistration:
handler: src/modules/minglaradmin/handlers/registration.handler handler: src/modules/minglaradmin/handlers/registration.handler
package: package:
@@ -337,21 +352,6 @@ functions:
path: /minglaradmin/add-suggestion path: /minglaradmin/add-suggestion
method: post method: post
getSuggestion:
handler: src/modules/minglaradmin/handlers/getSuggestion.handler
package:
patterns:
- 'src/modules/minglaradmin/**'
- 'common/**'
- 'src/common/**'
- 'node_modules/@prisma/client/**'
- 'node_modules/.prisma/**'
events:
- httpApi:
path: /minglaradmin/get-suggestion
method: get
getAllCoadminAndAMDetails: getAllCoadminAndAMDetails:
handler: src/modules/minglaradmin/handlers/getAllCoadminAndAM.handler handler: src/modules/minglaradmin/handlers/getAllCoadminAndAM.handler
package: package:

View File

@@ -24,8 +24,7 @@ export const MINGLAR_INVITATION_STATUS = {
} }
export const HOST_SUGGESTION_TITLES = { export const HOST_SUGGESTION_TITLES = {
SETUP_PROFILE: "Setup Profile", COMPANY_DETAILS: "Complete Details",
REVIEW_ACCOUNT: "Review Account", COMPANY_DOCUMENTATION:"Company documentataion",
ADD_PAYMENT_DETAILS: "Add Payment Details", COMPANY_SOCIAL_PROOF:"Social Proof",
AGREEMENT: "Agreement"
} }

View File

@@ -1,9 +1,9 @@
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda'; import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
import { safeHandler } from '../../../common/utils/handlers/safeHandler'; import { safeHandler } from '../../../common/utils/handlers/safeHandler';
import { PrismaService } from '../../../common/database/prisma.service'; import { PrismaService } from '../../../common/database/prisma.service';
import { MinglarService } from '../services/minglar.service'; import { MinglarService } from '../../minglaradmin/services/minglar.service';
import ApiError from '../../../common/utils/helper/ApiError'; import ApiError from '../../../common/utils/helper/ApiError';
import { verifyMinglarAdminToken } from '../../../common/middlewares/jwt/authForMinglarAdmin'; import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
const prismaService = new PrismaService(); const prismaService = new PrismaService();
const minglarService = new MinglarService(prismaService); const minglarService = new MinglarService(prismaService);
@@ -23,7 +23,7 @@ export const handler = safeHandler(async (
} }
// Verify token and get user info // Verify token and get user info
const userInfo = await verifyMinglarAdminToken(token); const userInfo = await verifyHostToken(token);
// Get user details including role // Get user details including role
const user = await prismaService.user.findUnique({ const user = await prismaService.user.findUnique({

View File

@@ -2,9 +2,12 @@ import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda
import { PrismaService } from '../../../common/database/prisma.service'; import { PrismaService } from '../../../common/database/prisma.service';
import { safeHandler } from '../../../common/utils/handlers/safeHandler'; import { safeHandler } from '../../../common/utils/handlers/safeHandler';
import ApiError from '../../../common/utils/helper/ApiError'; import ApiError from '../../../common/utils/helper/ApiError';
import { generateOtpHelper } from '../../../common/utils/helper/sendOtp'; import * as bcrypt from 'bcryptjs';
import { OtpGeneratorSixDigit } from '../../../common/utils/helper/OtpGenerator';
import { encryptUserId } from '../../../common/utils/helper/CodeGenerator';
import { HostService } from '../services/host.service'; import { HostService } from '../services/host.service';
import { sendOtpEmailForHost } from '../services/sendOTPEmail.service'; import { sendOtpEmailForHost } from '../services/sendOTPEmail.service';
import { ROLE } from '../../../common/utils/constants/common.constant';
const prismaService = new PrismaService(); const prismaService = new PrismaService();
const hostService = new HostService(prismaService); const hostService = new HostService(prismaService);
@@ -28,38 +31,61 @@ export const handler = safeHandler(async (
throw new ApiError(400, 'Email is required'); throw new ApiError(400, 'Email is required');
} }
const user = await prismaService.user.findUnique({ // Use a single transaction for user creation/lookup and OTP storage
where: { emailAddress: email }, const transactionResult = await prismaService.$transaction(async (tx) => {
select: { emailAddress: true, id: true, userPassword: true }, const user = await tx.user.findUnique({
where: { emailAddress: email },
select: { emailAddress: true, id: true, userPassword: true },
});
if (user && user.userPassword) {
throw new ApiError(409, 'User is already registered. Please login.');
}
let newUserLocal;
if (user && !user.userPassword) {
// reuse existing invited user record
newUserLocal = user;
} else {
// create new user record within the transaction
newUserLocal = await tx.user.create({
data: { emailAddress: email, roleXid: ROLE.HOST },
});
}
// Generate OTP (6-digit) and store within the same transaction
const otp = OtpGeneratorSixDigit.generateOtp();
const hashedOtp = await bcrypt.hash(otp, 10);
const expiry = new Date(Date.now() + 5 * 60 * 1000); // 5 minutes
// delete old active OTPs for this user/purpose
await tx.userOtp.deleteMany({
where: { userXid: Number(newUserLocal.id), otpType: 'Register', isActive: true },
});
await tx.userOtp.create({
data: {
userXid: Number(newUserLocal.id),
otpType: 'Register',
otpCode: hashedOtp,
expiresOn: expiry,
isVerified: false,
isActive: true,
},
});
const encryptedId = encryptUserId(String(newUserLocal.id));
return { newUser: newUserLocal, otp, encryptedId };
}); });
if (user && user.userPassword) { if (!transactionResult || !transactionResult.otp) {
throw new ApiError(409, 'User is already registered. Please login.'); throw new ApiError(500, 'Failed to generate OTP');
} }
let newUser; // Send OTP email outside the DB transaction
// await sendOtpEmailForHost(transactionResult.newUser.emailAddress, transactionResult.otp);
if (user && !user.userPassword) {
// ✅ User already exists but without password → reuse record
newUser = user;
} else {
// ✅ No user found → create new one
newUser = await hostService.createMinglarUser(email);
}
const otpResult = await generateOtpHelper(
Number(newUser?.id),
newUser?.emailAddress,
'Register',
6,
5
);
if (!otpResult || !otpResult.otp) {
throw new ApiError(500, 'Failed to send OTP');
}
// await sendOtpEmailForHost(newUser?.emailAddress, otpResult.otp);
return { return {
statusCode: 200, statusCode: 200,

View File

@@ -78,22 +78,31 @@ export const handler = safeHandler(async (
throw new ApiError(400, 'Per value must be greater than 0'); throw new ApiError(400, 'Per value must be greater than 0');
} }
// Check if user already exists - using service // Run user creation, revenue and invite details inside a transaction
const existingUser = await minglarService.checkUserExists(emailAddress); const createdUser = await prismaService.$transaction(async (tx) => {
// create a transaction-scoped MinglarService instance
const txMinglarService = new MinglarService(tx as unknown as PrismaService);
if (existingUser) { // Check if user already exists within transaction to avoid race
throw new ApiError(400, 'User already exists.'); const existingUser = await txMinglarService.checkUserExists(emailAddress);
} if (existingUser) {
throw new ApiError(400, 'User already exists.');
}
// Create new user - using service // Create new user
const user = await minglarService.createUserForInvite(emailAddress, roleXid); const user = await txMinglarService.createUserForInvite(emailAddress, roleXid);
// Create user revenue - using service // Create user revenue
await minglarService.createUserRevenue(user.id, isFixedSalary, perValue || 0); await txMinglarService.createUserRevenue(user.id, isFixedSalary, perValue || 0);
// Create invite details - using service // Create invite details
await minglarService.createInviteDetails(user.id, userInfo.id, MINGLAR_INVITATION_STATUS.INVITED); await txMinglarService.createInviteDetails(user.id, userInfo.id, MINGLAR_INVITATION_STATUS.INVITED);
// return created user from transaction
return user;
});
// send email after transaction commits
await sendInvitationEmailForMinglarAdmin(emailAddress); await sendInvitationEmailForMinglarAdmin(emailAddress);
return { return {