Refactor host and minglaradmin handlers: update paths, rename functions, and add prepopulateRole handler for role retrieval

This commit is contained in:
paritosh18
2025-11-27 17:26:33 +05:30
parent dcc0fbbcf6
commit 9e0f12117f
5 changed files with 198 additions and 147 deletions

View File

@@ -182,7 +182,7 @@ getAllHostActivity:
memorySize: 384
package:
patterns:
- 'src/modules/host/handlers/getActivityType.*'
- 'src/modules/host/handlers/Activity_Hub/OnBoarding/getAllHostActivity.*'
- 'src/modules/host/services/**'
- ${file(./serverless/patterns/base.yml):pattern1}
- ${file(./serverless/patterns/base.yml):pattern2}

View File

@@ -141,7 +141,7 @@ getAllHostApplication:
path: /minglaradmin/hosthub/hosts/get-all-host-applications-am
method: get
getAllHostActivity:
getAllHostActivityForAdmin:
handler: src/modules/host/handlers/hosthub/onboarding/getAllActivityOfHost.handler
memorySize: 384
package:
@@ -251,7 +251,7 @@ getAllInvitedCoadminAndAMDetails:
method: get
getAmDetailsbyId:
handler: src/modules/minglaradmin/handlers/getAmDetailsById.handler
handler: src/modules/minglaradmin/handlers/getAmDetail_ById.handler
memorySize: 384
package:
patterns:

View File

@@ -1,15 +1,30 @@
// src/modules/host/services/host.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../../../common/database/prisma.service';
import { AddPaymentDetailsDTO, CreateHostDto, UpdateHostDto } from '../dto/host.dto';
import {
AddPaymentDetailsDTO,
CreateHostDto,
UpdateHostDto,
} from '../dto/host.dto';
import * as bcrypt from 'bcryptjs';
import ApiError from '../../../common/utils/helper/ApiError';
import { User } from '@prisma/client';
import { z } from 'zod';
import { hostCompanyDetailsSchema } from '@/common/utils/validation/host/hostCompanyDetails.validation';
import { HOST_STATUS_DISPLAY, HOST_STATUS_INTERNAL, STEPPER } from '@/common/utils/constants/host.constant';
import { MINGLAR_STATUS_DISPLAY, MINGLAR_STATUS_INTERNAL } from '@/common/utils/constants/minglar.constant';
import { ROLE, ROLE_NAME, USER_STATUS } from '@/common/utils/constants/common.constant';
import {
HOST_STATUS_DISPLAY,
HOST_STATUS_INTERNAL,
STEPPER,
} from '@/common/utils/constants/host.constant';
import {
MINGLAR_STATUS_DISPLAY,
MINGLAR_STATUS_INTERNAL,
} from '@/common/utils/constants/minglar.constant';
import {
ROLE,
ROLE_NAME,
USER_STATUS,
} from '@/common/utils/constants/common.constant';
import { getPresignedUrl } from '@/common/middlewares/aws/getPreSignedUrl';
import config from '@/config/config';
@@ -24,7 +39,7 @@ interface HostDocumentInput {
@Injectable()
export class HostService {
constructor(private prisma: PrismaService) { }
constructor(private prisma: PrismaService) {}
async createHost(data: CreateHostDto) {
return this.prisma.user.create({ data });
@@ -59,7 +74,7 @@ export class HostService {
currencies: true,
states: true,
cities: true,
}
},
});
if (!host) {
@@ -76,8 +91,8 @@ export class HostService {
const filePath = doc.filePath;
// If full URL is saved, extract only key
const key = filePath.startsWith("http")
? filePath.split(".com/")[1]
const key = filePath.startsWith('http')
? filePath.split('.com/')[1]
: filePath;
(doc as any).presignedUrl = await getPresignedUrl(bucket, key);
@@ -162,7 +177,10 @@ export class HostService {
throw new ApiError(403, 'Access denied. Not a host user.');
}
const matchPassword = await bcrypt.compare(userPassword, existingUser.userPassword);
const matchPassword = await bcrypt.compare(
userPassword,
existingUser.userPassword,
);
if (!matchPassword) {
throw new ApiError(401, 'Invalid credentials');
}
@@ -190,7 +208,10 @@ export class HostService {
// Check if password already exists
if (user.userPassword) {
throw new ApiError(400, 'Password already exists. Use update password instead.');
throw new ApiError(
400,
'Password already exists. Use update password instead.',
);
}
// Hash the password
@@ -200,7 +221,11 @@ export class HostService {
// Update user with hashed password
await this.prisma.user.update({
where: { id: user.id },
data: { userPassword: hashedPassword, isEmailVerfied: true, userStatus: USER_STATUS.ACTIVE },
data: {
userPassword: hashedPassword,
isEmailVerfied: true,
userStatus: USER_STATUS.ACTIVE,
},
});
return true;
@@ -219,26 +244,25 @@ export class HostService {
await tx.hostHeader.update({
where: { id: data.hostXid },
data: {
stepper: STEPPER.BANK_DETAILS_UPDATED
}
})
})
stepper: STEPPER.BANK_DETAILS_UPDATED,
},
});
});
}
async getAllHostActivity(search?: string , hostXid?: number) {
await this.prisma.activities.findMany({
async getAllHostActivity(search?: string, hostXid?: number) {
return await this.prisma.activities.findMany({
where: {
isActive: true,
hostXid: hostXid,
},
include: {
include: {
ActivitiesMedia: true,
ActivityAmDetails: true,
ActivityAmDetails: true,
activityType: true,
},
})
}
},
});
}
async acceptMinglarAgreement(user_xid: number) {
const hostDetails = await this.prisma.hostHeader.findFirst({
@@ -246,27 +270,31 @@ export class HostService {
select: {
id: true,
userXid: true,
}
})
},
});
await this.prisma.hostHeader.update({
where: { id: hostDetails.id },
data: {
stepper: STEPPER.AGREEMENT_ACCEPTED,
agreementAccepted: true,
}
})
},
});
}
async getPQQQuestionDetail(question_xid: number, activity_xid: number) {
return await this.prisma.activityPQQheader.findFirst({
where: { activityXid: activity_xid, pqqQuestionXid: question_xid, isActive: true },
where: {
activityXid: activity_xid,
pqqQuestionXid: question_xid,
isActive: true,
},
select: {
pqqQuestionXid: true,
pqqAnswerXid: true,
ActivityPQQSupportings: true,
ActivityPQQSuggestions: true
}
})
ActivityPQQSuggestions: true,
},
});
}
async getLatestQuestionDetailsPQQ(activity_xid: number) {
@@ -280,14 +308,14 @@ export class HostService {
pqqSubCategoryXid: true,
pqqSubCategories: {
select: {
categoryXid: true
}
}
}
}
categoryXid: true,
},
},
},
},
},
orderBy: { id: 'desc' }
})
orderBy: { id: 'desc' },
});
}
async addOrUpdateCompanyDetails(
@@ -296,7 +324,7 @@ export class HostService {
documents: HostDocumentInput[],
parentCompanyData?: any | null,
parentDocuments?: HostDocumentInput[],
isDraft: boolean = false // Add isDraft parameter with default false
isDraft: boolean = false, // Add isDraft parameter with default false
) {
return await this.prisma.$transaction(async (tx) => {
// Check if host already has a company
@@ -329,7 +357,11 @@ export class HostService {
const existingByPan = await tx.hostHeader.findFirst({
where: { panNumber: companyData.panNumber },
});
if (existingByPan) throw new ApiError(400, 'Company already exists with this pan/bin number');
if (existingByPan)
throw new ApiError(
400,
'Company already exists with this pan/bin number',
);
}
const refNumber = await this.generateHostRefNumber(tx);
@@ -444,7 +476,7 @@ export class HostService {
hostStatusInternal: hostStatusInternal,
hostStatusDisplay: hostStatusDisplay,
adminStatusInternal: minglarStatusInternal,
adminStatusDisplay: minglarStatusDisplay
adminStatusDisplay: minglarStatusDisplay,
},
});
@@ -528,7 +560,9 @@ export class HostService {
});
// replace parent docs
await tx.hostParenetDocuments.deleteMany({ where: { hostParentXid: parentRecord.id } });
await tx.hostParenetDocuments.deleteMany({
where: { hostParentXid: parentRecord.id },
});
if (parentDocuments?.length) {
const parentDocsData = parentDocuments.map((doc) => ({
hostParentXid: parentRecord.id,
@@ -543,18 +577,22 @@ export class HostService {
// If previously had a parent and now isSubsidairy=false -> optionally delete parent and its docs
const previousParent = (existingHostCompany as any).hostParent;
let prevParentId = null;
if (Array.isArray(previousParent) && previousParent.length) prevParentId = previousParent[0].id;
else if (previousParent && previousParent.id) prevParentId = previousParent.id;
if (Array.isArray(previousParent) && previousParent.length)
prevParentId = previousParent[0].id;
else if (previousParent && previousParent.id)
prevParentId = previousParent.id;
if (prevParentId) {
await tx.hostParenetDocuments.deleteMany({ where: { hostParentXid: prevParentId } });
await tx.hostParenetDocuments.deleteMany({
where: { hostParentXid: prevParentId },
});
await tx.hostParent.delete({ where: { id: prevParentId } });
}
}
const hostDetails = await this.prisma.hostHeader.findFirst({
where: { userXid: user_xid },
})
});
await this.prisma.hostTrack.create({
data: {
@@ -562,8 +600,8 @@ export class HostService {
updatedByRole: ROLE_NAME.HOST,
updatedByXid: user_xid,
trackStatus: hostDetails.hostStatusInternal,
}
})
},
});
return updatedHost;
});
@@ -578,16 +616,16 @@ export class HostService {
id: true,
emailAddress: true,
firstName: true,
}
},
},
accountManager: {
select: {
id: true,
emailAddress: true,
firstName: true,
}
}
}
},
},
},
});
if (!hostDetails) {
@@ -595,7 +633,7 @@ export class HostService {
}
const hostSuggestionDetails = await this.prisma.hostSuggestion.findMany({
where: { hostXid: hostDetails.id, isActive: true, isreviewed: false }
where: { hostXid: hostDetails.id, isActive: true, isreviewed: false },
});
if (hostSuggestionDetails) {
@@ -605,15 +643,13 @@ export class HostService {
isreviewed: true,
reviewedByXid: hostDetails.id,
reviewOn: new Date(),
}
})
},
});
}
return { hostSuggestionDetails, hostDetails };
}
async generateHostRefNumber(tx: any) {
const lastHost = await tx.hostHeader.findFirst({
orderBy: {
@@ -621,7 +657,7 @@ export class HostService {
},
select: {
id: true,
}
},
});
const nextId = lastHost ? lastHost.id + 1 : 1;
@@ -683,7 +719,6 @@ export class HostService {
// });
// }
async calculatePqqScoreForUser(activityXid: number) {
// 1. Get all headers for this activity (user's answers)
const answers = await this.prisma.activityPQQheader.findMany({
@@ -693,19 +728,19 @@ export class HostService {
include: {
pqqSubCategories: {
include: {
category: true
}
}
}
category: true,
},
},
},
},
pqqAnswers: true
}
pqqAnswers: true,
},
});
if (!answers.length) {
return {
overallPercentage: 0,
categoryWise: {}
categoryWise: {},
};
}
@@ -714,12 +749,15 @@ export class HostService {
let totalMaxPoints = 0;
// For category-wise scoring
const categories: Record<number, {
categoryId: number;
categoryName: string;
userPoints: number;
maxPoints: number;
}> = {};
const categories: Record<
number,
{
categoryId: number;
categoryName: string;
userPoints: number;
maxPoints: number;
}
> = {};
for (const item of answers) {
const question = item.pqqQuestions;
@@ -771,117 +809,108 @@ export class HostService {
// Return final score object
return {
overallPercentage,
categoryWise
categoryWise,
};
}
async createHeader(
activityXid: number,
pqqQuestionXid: number,
pqqAnswerXid: number,
comments?: string | null
comments?: string | null,
) {
return await this.prisma.activityPQQheader.create({
data: {
activityXid,
pqqQuestionXid,
pqqAnswerXid,
comments: comments || null // Handle null comments
}
comments: comments || null, // Handle null comments
},
});
}
async findHeaderByCompositeKey(
activityXid: number,
pqqQuestionXid: number,
pqqAnswerXid: number
pqqAnswerXid: number,
) {
return await this.prisma.activityPQQheader.findFirst({
where: {
activityXid,
pqqQuestionXid,
pqqAnswerXid
}
pqqAnswerXid,
},
});
}
async updateHeader(
headerId: number,
comments?: string | null
) {
async updateHeader(headerId: number, comments?: string | null) {
return await this.prisma.activityPQQheader.update({
where: {
id: headerId
id: headerId,
},
data: {
comments: comments || null, // Handle null comments
updatedAt: new Date()
}
updatedAt: new Date(),
},
});
}
async addSupportingFile(
headerId: number,
mimeType: string,
fileUrl: string
) {
async addSupportingFile(headerId: number, mimeType: string, fileUrl: string) {
return await this.prisma.activityPQQSupportings.create({
data: {
activityPqqHeaderXid: headerId,
mediaType: mimeType,
mediaFileName: fileUrl
}
mediaFileName: fileUrl,
},
});
}
async getSupportingFilesByHeaderId(headerId: number) {
return await this.prisma.activityPQQSupportings.findMany({
where: {
activityPqqHeaderXid: headerId
activityPqqHeaderXid: headerId,
},
orderBy: {
id: 'asc' // Maintain consistent order
}
id: 'asc', // Maintain consistent order
},
});
}
async updateSupportingFile(
supportingFileId: number,
mimeType: string,
fileUrl: string
fileUrl: string,
) {
return await this.prisma.activityPQQSupportings.update({
where: {
id: supportingFileId
id: supportingFileId,
},
data: {
mediaType: mimeType,
mediaFileName: fileUrl,
updatedAt: new Date()
}
updatedAt: new Date(),
},
});
}
async deleteSupportingFile(supportingFileId: number) {
return await this.prisma.activityPQQSupportings.delete({
where: {
id: supportingFileId
}
id: supportingFileId,
},
});
}
async getAllPQQQuesAndSubmittedAns(){
return await this.prisma.activityPQQheader.findMany({
async getAllPQQQuesAndSubmittedAns() {
return await this.prisma.activityPQQheader.findMany({
where: { isActive: true },
include: {
pqqQuestions: true,
ActivityPQQSuggestions: true,
pqqAnswers: true,
ActivityPQQSupportings: true
}
})
ActivityPQQSupportings: true,
},
});
}
async getAllActivityTypesWithInterest(search?: string) {
@@ -922,20 +951,26 @@ export class HostService {
frequenciesXid?: number,
) {
// Find host header for this user
const host = await this.prisma.hostHeader.findFirst({ where: { userXid: userId, isActive: true } });
const host = await this.prisma.hostHeader.findFirst({
where: { userXid: userId, isActive: true },
});
if (!host) {
throw new ApiError(404, 'Host not found for the user');
}
// Validate activityType exists
const activityType = await this.prisma.activityTypes.findUnique({ where: { id: activityTypeXid } });
const activityType = await this.prisma.activityTypes.findUnique({
where: { id: activityTypeXid },
});
if (!activityType) {
throw new ApiError(404, 'Activity type not found');
}
// Optionally validate frequency
if (frequenciesXid) {
const freq = await this.prisma.frequencies.findUnique({ where: { id: frequenciesXid } });
const freq = await this.prisma.frequencies.findUnique({
where: { id: frequenciesXid },
});
if (!freq) throw new ApiError(404, 'Frequency not found');
}
@@ -950,5 +985,4 @@ export class HostService {
return created;
}
}

View File

@@ -1,4 +1,8 @@
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
import {
APIGatewayProxyEvent,
APIGatewayProxyResult,
Context,
} from 'aws-lambda';
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
import { PrismaService } from '../../../common/database/prisma.service';
import { MinglarService } from '../services/minglar.service';
@@ -12,38 +16,51 @@ const minglarService = new MinglarService(prismaService);
* Get all host applications handler
* Returns host details with status, submission date, and account manager info
*/
export const handler = safeHandler(async (
event: APIGatewayProxyEvent,
context?: Context
): Promise<APIGatewayProxyResult> => {
// Verify authentication token
const token = event.headers['x-auth-token'] || event.headers['X-Auth-Token'];
if (!token) {
throw new ApiError(401, 'This is a protected route. Please provide a valid token.');
}
export const handler = safeHandler(
async (
event: APIGatewayProxyEvent,
context?: Context,
): Promise<APIGatewayProxyResult> => {
// Verify authentication token
const token =
event.headers['x-auth-token'] || event.headers['X-Auth-Token'];
if (!token) {
throw new ApiError(
401,
'This is a protected route. Please provide a valid token.',
);
}
await verifyMinglarAdminToken(token);
await verifyMinglarAdminToken(token);
const amXid = event.pathParameters?.amXid;
if (!amXid) {
throw new ApiError(
400,
'Account Manager XID is required in path parameters.',
);
}
const amXid = event.pathParameters?.amXid;
if (!amXid) {
throw new ApiError(400, 'Account Manager XID is required in path parameters.');
}
const amId = Number(amXid);
if (Number.isNaN(amId)) {
throw new ApiError(400, 'Account Manager XID must be a valid number.');
}
// Get all host applications from service based on user role
const getAmDetailsByid = await minglarService.getAMdetailById(amXid);
// Get all host applications from service based on user role
const getAmDetailsByid = await minglarService.getAMdetailById( amId );
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify({
success: true,
message: 'Host applications retrieved successfully',
data: getAmDetailsByid,
}),
};
});
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify({
success: true,
message: 'Host applications retrieved successfully',
data: getAmDetailsByid,
}),
};
},
);