Compare commits
55 Commits
validation
...
pqq-optimi
| Author | SHA1 | Date | |
|---|---|---|---|
| ab9e02972e | |||
| 33b330a15b | |||
| d898dcd8ff | |||
|
|
ff18fcbf9f | ||
|
|
a872ed89e4 | ||
| 759eeb298c | |||
| 1b72e65a71 | |||
| 4a7e5fbb1e | |||
| ca5936d0db | |||
| c0d607a321 | |||
| 1d684b7de6 | |||
| 16b16ac7ca | |||
| 0e0c63e31a | |||
| 822b425c1d | |||
| 42e2d7a579 | |||
|
|
78f49b35dd | ||
|
|
930ae708a1 | ||
|
|
8fb3f16d18 | ||
| 3d6226ddac | |||
| 38c616a7af | |||
| c6ab3e57c0 | |||
|
|
776c03911e | ||
|
|
781058c443 | ||
| 3b723e5d1f | |||
|
|
56ebf44d37 | ||
| 4f8274adb9 | |||
| 39f182b8e9 | |||
| d9f7cd9a0f | |||
| 4772c320ba | |||
|
|
f19f5e46c4 | ||
|
|
156aed2429 | ||
|
|
fb77111e34 | ||
| 6b673a173d | |||
| 3c4b0db39f | |||
| e72c260b18 | |||
|
|
9a777eb3f9 | ||
|
|
c3f0a1d82a | ||
| 3f921febe0 | |||
|
|
4bc5eb8d4d | ||
| f3f0b2a81b | |||
|
|
6f0cdb4e0a | ||
| ce9c8174d8 | |||
| c72e757bf3 | |||
|
|
6aaf49bf72 | ||
|
|
1b31ca4a83 | ||
| 140f70615c | |||
| 32f4c7ce42 | |||
|
|
067d1a1f1b | ||
|
|
470298a3fb | ||
| 1d7d0749b3 | |||
|
|
d3fb1c85fb | ||
| e723e680ab | |||
|
|
0e50b8b187 | ||
|
|
bbe725dd9e | ||
| e5861654e9 |
@@ -66,6 +66,7 @@ model User {
|
||||
friendOf Friends[] @relation("FriendUser")
|
||||
userAddressDetails UserAddressDetails[]
|
||||
userDocuments UserDocuments[]
|
||||
activityTracks ActivityTrack[]
|
||||
|
||||
@@map("users")
|
||||
@@schema("usr")
|
||||
@@ -406,11 +407,14 @@ model FoodCuisines {
|
||||
|
||||
model CompanyTypes {
|
||||
id Int @id @default(autoincrement())
|
||||
companyTypeName String @unique @map("company_type_name") @db.VarChar(30)
|
||||
companyTypeName String @unique @map("company_type_name") @db.VarChar(100)
|
||||
displayOrder Int @map("display_order")
|
||||
isActive Boolean @default(true) @map("is_active")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
deletedAt DateTime? @map("deleted_at")
|
||||
hostHeaders HostHeader[]
|
||||
hostParents HostParent[]
|
||||
|
||||
@@map("company_types")
|
||||
@@schema("mst")
|
||||
@@ -664,12 +668,13 @@ model HostHeader {
|
||||
panNumber String? @map("pan_number") @db.VarChar(30)
|
||||
gstNumber String? @map("gst_number") @db.VarChar(30)
|
||||
formationDate DateTime? @map("formation_date")
|
||||
companyType String? @map("company_type") @db.VarChar(30)
|
||||
websiteUrl String? @map("website_url") @db.VarChar(50)
|
||||
instagramUrl String? @map("instagram_url") @db.VarChar(80)
|
||||
facebookUrl String? @map("facebook_url") @db.VarChar(80)
|
||||
linkedinUrl String? @map("linkedin_url") @db.VarChar(80)
|
||||
twitterUrl String? @map("twitter_url") @db.VarChar(80)
|
||||
companyTypeXid Int? @map("company_type_xid")
|
||||
companyTypes CompanyTypes? @relation(fields: [companyTypeXid], references: [id], onDelete: Restrict)
|
||||
websiteUrl String? @map("website_url") @db.VarChar(250)
|
||||
instagramUrl String? @map("instagram_url") @db.VarChar(250)
|
||||
facebookUrl String? @map("facebook_url") @db.VarChar(250)
|
||||
linkedinUrl String? @map("linkedin_url") @db.VarChar(250)
|
||||
twitterUrl String? @map("twitter_url") @db.VarChar(250)
|
||||
currencyXid Int? @map("currency_xid")
|
||||
currencies Currencies? @relation(fields: [currencyXid], references: [id], onDelete: Restrict)
|
||||
stepper Int? @default(1) @map("stepper")
|
||||
@@ -691,6 +696,7 @@ model HostHeader {
|
||||
amountPerBooking Int? @map("amount_per_booking")
|
||||
payoutDurationNum Int? @map("payout_duration_num")
|
||||
payoutDurationFrequency String? @map("payout_duration_frequency") @db.VarChar(20)
|
||||
referencedBy String? @default("null") @map("referenced_by") @db.VarChar(100)
|
||||
isActive Boolean @default(true) @map("is_active")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
@@ -780,17 +786,17 @@ model HostParent {
|
||||
countries Countries? @relation(fields: [countryXid], references: [id], onDelete: Restrict)
|
||||
pinCode String? @map("pin_code") @db.VarChar(30)
|
||||
logoPath String? @map("logo_path") @db.VarChar(400)
|
||||
isSubsidairy Boolean @default(false) @map("is_subsidairy")
|
||||
registrationNumber String? @map("registration_number") @db.VarChar(30)
|
||||
panNumber String? @map("pan_number") @db.VarChar(30)
|
||||
gstNumber String? @map("gst_number") @db.VarChar(30)
|
||||
formationDate DateTime? @map("formation_date")
|
||||
companyType String? @map("company_type") @db.VarChar(30)
|
||||
websiteUrl String? @map("website_url") @db.VarChar(80)
|
||||
instagramUrl String? @map("instagram_url") @db.VarChar(80)
|
||||
facebookUrl String? @map("facebook_url") @db.VarChar(80)
|
||||
linkedinUrl String? @map("linkedin_url") @db.VarChar(80)
|
||||
twitterUrl String? @map("twitter_url") @db.VarChar(80)
|
||||
companyTypeXid Int? @map("company_type_xid")
|
||||
companyTypes CompanyTypes? @relation(fields: [companyTypeXid], references: [id], onDelete: Restrict)
|
||||
websiteUrl String? @map("website_url") @db.VarChar(250)
|
||||
instagramUrl String? @map("instagram_url") @db.VarChar(250)
|
||||
facebookUrl String? @map("facebook_url") @db.VarChar(250)
|
||||
linkedinUrl String? @map("linkedin_url") @db.VarChar(250)
|
||||
twitterUrl String? @map("twitter_url") @db.VarChar(250)
|
||||
isActive Boolean @default(true) @map("is_active")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
@@ -904,6 +910,7 @@ model Activities {
|
||||
ActivityEquipmentTaxes ActivityEquipmentTaxes[]
|
||||
ScheduleHeader ScheduleHeader[]
|
||||
ItineraryActivities ItineraryActivities[]
|
||||
activityTracks ActivityTrack[]
|
||||
|
||||
@@map("activities")
|
||||
@@schema("act")
|
||||
@@ -928,6 +935,25 @@ model ActivityOtherDetails {
|
||||
@@schema("act")
|
||||
}
|
||||
|
||||
model ActivityTrack {
|
||||
id Int @id @default(autoincrement())
|
||||
activityXid Int @map("activity_xid")
|
||||
activity Activities @relation(fields: [activityXid], references: [id], onDelete: Cascade)
|
||||
trackType String? @default("PQQ") @map("track_type")
|
||||
updatedByRole String? @map("updated_by_role")
|
||||
trackStatus String? @map("track_status")
|
||||
updatedByXid Int? @map("updated_by_xid")
|
||||
user User? @relation(fields: [updatedByXid], references: [id], onDelete: Cascade)
|
||||
updatedOn DateTime? @map("updated_on")
|
||||
isActive Boolean @default(true) @map("is_active")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
deletedAt DateTime? @map("deleted_at")
|
||||
|
||||
@@map("activity_track")
|
||||
@@schema("act")
|
||||
}
|
||||
|
||||
model ActivitiesMedia {
|
||||
id Int @id @default(autoincrement())
|
||||
activityXid Int @map("activity_xid")
|
||||
@@ -1115,8 +1141,8 @@ model ActivityPQQheader {
|
||||
activity Activities @relation(fields: [activityXid], references: [id], onDelete: Cascade)
|
||||
pqqQuestionXid Int @map("pqq_question_xid")
|
||||
pqqQuestions PQQQuestions @relation(fields: [pqqQuestionXid], references: [id], onDelete: Restrict)
|
||||
pqqAnswerXid Int @map("pqq_answer_xid")
|
||||
pqqAnswers PQQAnswers @relation(fields: [pqqAnswerXid], references: [id], onDelete: Restrict)
|
||||
pqqAnswerXid Int? @map("pqq_answer_xid")
|
||||
pqqAnswers PQQAnswers? @relation(fields: [pqqAnswerXid], references: [id], onDelete: Restrict)
|
||||
comments String? @map("comments") @db.VarChar(200)
|
||||
isActive Boolean @default(true) @map("is_active")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { PrismaPg } from '@prisma/adapter-pg';
|
||||
import 'dotenv/config';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
const prisma = new PrismaClient({
|
||||
adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }),
|
||||
});
|
||||
|
||||
async function main() {
|
||||
// ✅ Countries
|
||||
@@ -74,35 +78,51 @@ async function main() {
|
||||
create: { interestName: 'Chill and Zen', displayOrder: 1 },
|
||||
});
|
||||
const sweatmode = await prisma.interests.upsert({
|
||||
where: { interestName: 'Sweat Mode' },
|
||||
where: { interestName: 'Sweat Mode On' },
|
||||
update: {},
|
||||
create: { interestName: 'Sweat Mode', displayOrder: 2 },
|
||||
create: { interestName: 'Sweat Mode On', displayOrder: 2 },
|
||||
});
|
||||
const gameon = await prisma.interests.upsert({
|
||||
where: { interestName: 'Game On' },
|
||||
const trackracer = await prisma.interests.upsert({
|
||||
where: { interestName: 'Track Racer' },
|
||||
update: {},
|
||||
create: { interestName: 'Game On', displayOrder: 3 },
|
||||
create: { interestName: 'Track Racer', displayOrder: 3 },
|
||||
});
|
||||
const circuitracer = await prisma.interests.upsert({
|
||||
where: { interestName: 'Circuit Racer' },
|
||||
update: {},
|
||||
create: { interestName: 'Circuit Racer', displayOrder: 4 },
|
||||
});
|
||||
const thermalGliding = await prisma.interests.upsert({
|
||||
where: { interestName: 'Thermal Gliding' },
|
||||
update: {},
|
||||
create: { interestName: 'Thermal Gliding', displayOrder: 5 },
|
||||
});
|
||||
const partycentral = await prisma.interests.upsert({
|
||||
where: { interestName: 'Party Central' },
|
||||
update: {},
|
||||
create: { interestName: 'Party Central', displayOrder: 4 },
|
||||
create: { interestName: 'Party Central', displayOrder: 6 },
|
||||
});
|
||||
const artsy = await prisma.interests.upsert({
|
||||
where: { interestName: 'Artsy' },
|
||||
const aqua = await prisma.interests.upsert({
|
||||
where: { interestName: 'Aqua' },
|
||||
update: {},
|
||||
create: { interestName: 'Artsy', displayOrder: 5 },
|
||||
create: { interestName: 'Aqua', displayOrder: 7 },
|
||||
});
|
||||
const foodiediaries = await prisma.interests.upsert({
|
||||
where: { interestName: 'Foodie Diaries' },
|
||||
const foodie = await prisma.interests.upsert({
|
||||
where: { interestName: 'Foodie' },
|
||||
update: {},
|
||||
create: { interestName: 'Foodie Diaries', displayOrder: 6 },
|
||||
create: { interestName: 'Foodie', displayOrder: 8 },
|
||||
});
|
||||
|
||||
await prisma.activityTypes.createMany({
|
||||
data: [
|
||||
{ interestXid: chillandzen.id, activityTypeName: 'Cricket' },
|
||||
{ interestXid: chillandzen.id, activityTypeName: 'Football' },
|
||||
{ interestXid: aqua.id, activityTypeName: 'Scuba-Diving' },
|
||||
{ interestXid: sweatmode.id, activityTypeName: 'Cloudboarding' },
|
||||
{ interestXid: partycentral.id, activityTypeName: 'Soaring Glider' },
|
||||
{ interestXid: sweatmode.id, activityTypeName: 'Speedway Racer' },
|
||||
{ interestXid: aqua.id, activityTypeName: 'Aerial Surfing' },
|
||||
{ interestXid: foodie.id, activityTypeName: 'Wine Tasting' },
|
||||
{ interestXid: trackracer.id, activityTypeName: 'Track Racer' },
|
||||
{ interestXid: thermalGliding.id, activityTypeName: 'Thermal Gliding' },
|
||||
],
|
||||
skipDuplicates: true,
|
||||
});
|
||||
@@ -133,6 +153,43 @@ async function main() {
|
||||
skipDuplicates: true, // prevents error if already seeded
|
||||
});
|
||||
|
||||
// ✅ Company types data
|
||||
await prisma.companyTypes.upsert({
|
||||
where: { companyTypeName: 'Proprietory' },
|
||||
update: {},
|
||||
create: { companyTypeName: 'Proprietory', displayOrder: 1 },
|
||||
});
|
||||
|
||||
await prisma.companyTypes.upsert({
|
||||
where: { companyTypeName: 'One Person Company' },
|
||||
update: {},
|
||||
create: { companyTypeName: 'One Person Company', displayOrder: 2 },
|
||||
});
|
||||
|
||||
await prisma.companyTypes.upsert({
|
||||
where: { companyTypeName: 'Limited Liability Partnership' },
|
||||
update: {},
|
||||
create: { companyTypeName: 'Limited Liability Partnership', displayOrder: 3 },
|
||||
});
|
||||
|
||||
await prisma.companyTypes.upsert({
|
||||
where: { companyTypeName: 'Partnership Firm' },
|
||||
update: {},
|
||||
create: { companyTypeName: 'Partnership Firm', displayOrder: 4 },
|
||||
});
|
||||
|
||||
await prisma.companyTypes.upsert({
|
||||
where: { companyTypeName: 'Private Limited, Public Limited' },
|
||||
update: {},
|
||||
create: { companyTypeName: 'Private Limited, Public Limited', displayOrder: 5 },
|
||||
});
|
||||
|
||||
await prisma.companyTypes.upsert({
|
||||
where: { companyTypeName: 'Non-Profit Organisation' },
|
||||
update: {},
|
||||
create: { companyTypeName: 'Non-Profit Organisation', displayOrder: 6 },
|
||||
});
|
||||
|
||||
// ✅ Food Types
|
||||
await prisma.foodTypes.createMany({
|
||||
data: [
|
||||
|
||||
@@ -88,6 +88,7 @@ functions:
|
||||
- ${file(./serverless/functions/host.yml)}
|
||||
- ${file(./serverless/functions/minglaradmin.yml)}
|
||||
- ${file(./serverless/functions/prepopulate.yml)}
|
||||
- ${file(./serverless/functions/pqq.yml)}
|
||||
|
||||
plugins:
|
||||
- serverless-offline
|
||||
@@ -161,7 +161,7 @@ getPQQ_LastUpdatedQuestion:
|
||||
path: /host/Activity_Hub/OnBoarding/get-latest-pqq-question-details
|
||||
method: get
|
||||
|
||||
getAllActivityType:
|
||||
prePopulateNewActivity:
|
||||
handler: src/modules/host/handlers/Activity_Hub/OnBoarding/getAllActivityType.handler
|
||||
memorySize: 384
|
||||
package:
|
||||
@@ -174,7 +174,7 @@ getAllActivityType:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Activity_Hub/OnBoarding/get-activity-type
|
||||
path: /host/Activity_Hub/OnBoarding/prepopulate-new-activity
|
||||
method: get
|
||||
|
||||
showSuggestion:
|
||||
@@ -330,6 +330,23 @@ updatePQQ_LastAnswer:
|
||||
path: /host/Activity_Hub/OnBoarding/submit-final-pqq-answer
|
||||
method: post
|
||||
|
||||
|
||||
submitPQQForReview:
|
||||
handler: src/modules/host/handlers/Activity_Hub/OnBoarding/submitPQQForReview.handler
|
||||
memorySize: 384
|
||||
package:
|
||||
patterns:
|
||||
- 'src/modules/host/handlers/Activity_Hub/OnBoarding/submitPQQForReview.*'
|
||||
- 'src/modules/host/services/**'
|
||||
- ${file(./serverless/patterns/base.yml):pattern1}
|
||||
- ${file(./serverless/patterns/base.yml):pattern2}
|
||||
- ${file(./serverless/patterns/base.yml):pattern3}
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Activity_Hub/OnBoarding/submit-pqq-for-review
|
||||
method: patch
|
||||
|
||||
getAllPQQwithSubmittedAns:
|
||||
handler: src/modules/host/handlers/Activity_Hub/OnBoarding/getAllPQQwithSubmittedAns.handler
|
||||
memorySize: 512
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# Minglar Admin Module Functions
|
||||
# Admin dashboard and management endpoints
|
||||
|
||||
|
||||
|
||||
minglarRegistration:
|
||||
handler: src/modules/minglaradmin/handlers/registration.handler
|
||||
memorySize: 384
|
||||
@@ -96,7 +94,6 @@ prepopulateRole:
|
||||
path: /minglaradmin/prepopulate-Roles
|
||||
method: get
|
||||
|
||||
|
||||
getHostDetailsById:
|
||||
handler: src/modules/minglaradmin/handlers/hosthub/hosts/getByIdHostDetails.handler
|
||||
memorySize: 384
|
||||
@@ -283,8 +280,8 @@ assignAMToHost:
|
||||
path: /minglaradmin/hosthub/onboarding/assign-am
|
||||
method: patch
|
||||
|
||||
editAgreementDetails:
|
||||
handler: src/modules/minglaradmin/handlers/hosthub/onboarding/editAgreementDetails.handler
|
||||
editAgreementDetailsAndAccept:
|
||||
handler: src/modules/minglaradmin/handlers/hosthub/onboarding/editAgreementDetailsAndAccept.handler
|
||||
memorySize: 384
|
||||
package:
|
||||
patterns:
|
||||
@@ -296,9 +293,24 @@ editAgreementDetails:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /minglaradmin/hosthub/onboarding/edit-agreement
|
||||
path: /minglaradmin/hosthub/onboarding/edit-agreement-accept-host
|
||||
method: patch
|
||||
|
||||
getAllPqqQuesAnsForAM:
|
||||
handler: src/modules/host/handlers/Activity_Hub/OnBoarding/getAllPQQwithSubmittedAns.handler
|
||||
memorySize: 512
|
||||
package:
|
||||
patterns:
|
||||
- 'src/modules/host/handlers/Activity_Hub/OnBoarding/getAllPQQwithSubmittedAns**'
|
||||
- ${file(./serverless/patterns/base.yml):pattern1}
|
||||
- ${file(./serverless/patterns/base.yml):pattern2}
|
||||
- ${file(./serverless/patterns/base.yml):pattern3}
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /minglaradmin/hosthub/onboarding/get-all-pqq-ques-ans-for-am
|
||||
method: get
|
||||
|
||||
acceptHostApplication:
|
||||
handler: src/modules/minglaradmin/handlers/hosthub/hosts/acceptHostApplication.handler
|
||||
memorySize: 384
|
||||
@@ -328,15 +340,15 @@ RejectPQQByAM:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /minglaradmin/hosthub/hosts/reject-pqq-by-am
|
||||
path: /minglaradmin/hosthub/hosts/reject-pq-by-am
|
||||
method: patch
|
||||
|
||||
acceptHostApplicationMinglar:
|
||||
handler: src/modules/minglaradmin/handlers/hosthub/onboarding/acceptHostAppMinglar.handler
|
||||
acceptPQByAM:
|
||||
handler: src/modules/minglaradmin/handlers/hosthub/hosts/acceptPQByAM.handler
|
||||
memorySize: 384
|
||||
package:
|
||||
patterns:
|
||||
- 'src/modules/minglaradmin/handlers/hosthub/onboarding/**'
|
||||
- 'src/modules/minglaradmin/handlers/hosthub/hosts/acceptPQByAM**'
|
||||
- 'src/modules/minglaradmin/services/**'
|
||||
- ${file(./serverless/patterns/base.yml):pattern1}
|
||||
- ${file(./serverless/patterns/base.yml):pattern2}
|
||||
@@ -344,7 +356,7 @@ acceptHostApplicationMinglar:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /minglaradmin/hosthub/onboarding/accept-host-application-minglar
|
||||
path: /minglaradmin/hosthub/hosts/accept-pq-by-am
|
||||
method: patch
|
||||
|
||||
rejectHostApplication:
|
||||
@@ -361,7 +373,7 @@ rejectHostApplication:
|
||||
events:
|
||||
- httpApi:
|
||||
path: /minglaradmin/hosthub/onboarding/reject-host-application
|
||||
method: post
|
||||
method: patch
|
||||
|
||||
rejectHostApplicationAM:
|
||||
handler: src/modules/minglaradmin/handlers/hosthub/hosts/rejectHostApplicationAM.handler
|
||||
@@ -377,7 +389,7 @@ rejectHostApplicationAM:
|
||||
events:
|
||||
- httpApi:
|
||||
path: /minglaradmin/hosthub/hosts/reject-host-application-am
|
||||
method: post
|
||||
method: patch
|
||||
|
||||
addPQQSuggestion:
|
||||
handler: src/modules/minglaradmin/handlers/hosthub/hosts/addPQQSuggestion.handler
|
||||
@@ -394,3 +406,19 @@ addPQQSuggestion:
|
||||
- httpApi:
|
||||
path: /minglaradmin/hosthub/hosts/add-Pqq-suggestion
|
||||
method: post
|
||||
|
||||
getAllPQPDetailsForAM:
|
||||
handler: src/modules/minglaradmin/handlers/hosthub/pqp/getAllPQPDetailsForAM.handler
|
||||
memorySize: 384
|
||||
package:
|
||||
patterns:
|
||||
- 'src/modules/minglaradmin/handlers/hosthub/pqp/getAllPQPDetailsForAM**'
|
||||
- 'src/modules/minglaradmin/services/**'
|
||||
- ${file(./serverless/patterns/base.yml):pattern1}
|
||||
- ${file(./serverless/patterns/base.yml):pattern2}
|
||||
- ${file(./serverless/patterns/base.yml):pattern3}
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /minglaradmin/hosthub/pqp/pqp-details-for-am/{activityXid}
|
||||
method: get
|
||||
|
||||
29
serverless/functions/pqq.yml
Normal file
29
serverless/functions/pqq.yml
Normal file
@@ -0,0 +1,29 @@
|
||||
createActivityAndAllQuestionsEntry:
|
||||
handler: src/modules/host/handlers/Activity_Hub/OnBoarding/createActivityAndAllQuestionsEntry.handler
|
||||
memorySize: 384
|
||||
package:
|
||||
patterns:
|
||||
- 'src/modules/host/handlers/Activity_Hub/OnBoarding/createActivityAndAllQuestionsEntry**'
|
||||
- ${file(./serverless/patterns/base.yml):pattern1}
|
||||
- ${file(./serverless/patterns/base.yml):pattern2}
|
||||
- ${file(./serverless/patterns/base.yml):pattern3}
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Activity_Hub/OnBoarding/create-activity
|
||||
method: post
|
||||
|
||||
submitPQAnswer:
|
||||
handler: src/modules/host/handlers/Activity_Hub/OnBoarding/submitPQAnswer.handler
|
||||
memorySize: 384
|
||||
package:
|
||||
patterns:
|
||||
- 'src/modules/host/handlers/Activity_Hub/OnBoarding/submitPQAnswer**'
|
||||
- ${file(./serverless/patterns/base.yml):pattern1}
|
||||
- ${file(./serverless/patterns/base.yml):pattern2}
|
||||
- ${file(./serverless/patterns/base.yml):pattern3}
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Activity_Hub/OnBoarding/submit-pq-answer
|
||||
method: patch
|
||||
@@ -23,19 +23,16 @@ export const STEPPER = {
|
||||
REJECTED: 6
|
||||
}
|
||||
|
||||
export const LAST_QUESTION_ID = {
|
||||
Q_ID: 55
|
||||
}
|
||||
|
||||
export const ACTIVITY_INTERNAL_STATUS = {
|
||||
DRAFT_PQ: 'Draft - PQ',
|
||||
APPROVED: 'Approved',
|
||||
REJECTED: 'Rejected',
|
||||
DRAFT: 'Draft',
|
||||
UNDER_REVIEW: 'Under-Review',
|
||||
PQQ_FAILED: 'PQQ Failed',
|
||||
PQQ_TO_UPDATE: 'PQ To Update',
|
||||
PQQ_SUBMITTED: 'PQ Submitted'
|
||||
PQ_FAILED: 'PQ Failed',
|
||||
PQ_TO_UPDATE: 'PQ To Update',
|
||||
PQ_SUBMITTED: 'PQ Submitted',
|
||||
PQ_APPROVED: 'PQ Approved'
|
||||
}
|
||||
|
||||
export const ACTIVITY_DISPLAY_STATUS = {
|
||||
@@ -44,9 +41,10 @@ export const ACTIVITY_DISPLAY_STATUS = {
|
||||
REJECTED: 'Rejected',
|
||||
DRAFT: 'Draft',
|
||||
UNDER_REVIEW: 'Under-Review',
|
||||
PQQ_FAILED: 'PQQ Failed',
|
||||
PQ_FAILED: 'PQ Failed',
|
||||
ENHANCING: 'Enchancing',
|
||||
PQ_IN_REVIEW: 'PQ In Review'
|
||||
PQ_IN_REVIEW: 'PQ In Review',
|
||||
PQ_APPROVED: 'PQ Approved'
|
||||
}
|
||||
|
||||
export const ACTIVITY_AM_INTERNAL_STATUS = {
|
||||
@@ -55,9 +53,10 @@ export const ACTIVITY_AM_INTERNAL_STATUS = {
|
||||
REJECTED: 'Rejected',
|
||||
DRAFT: 'Draft',
|
||||
UNDER_REVIEW: 'Under-Review',
|
||||
PQQ_FAILED: 'PQQ Failed',
|
||||
PQQ_REJECTED: 'PQ Rejected',
|
||||
PQQ_TO_REVIEW: 'PQ To Review'
|
||||
PQ_FAILED: 'PQ Failed',
|
||||
PQ_REJECTED: 'PQ Rejected',
|
||||
PQ_TO_REVIEW: 'PQ To Review',
|
||||
PQ_APPROVED: 'PQ Approved'
|
||||
}
|
||||
|
||||
export const ACTIVITY_AM_DISPLAY_STATUS = {
|
||||
@@ -66,7 +65,9 @@ export const ACTIVITY_AM_DISPLAY_STATUS = {
|
||||
REJECTED: 'Rejected',
|
||||
DRAFT: 'Draft',
|
||||
UNDER_REVIEW: 'Under-Review',
|
||||
PQQ_FAILED: 'PQQ Failed',
|
||||
PQ_FAILED: 'PQ Failed',
|
||||
ENHANCING: 'Enchancing',
|
||||
NEW: 'New'
|
||||
NEW: 'New',
|
||||
PQ_APPROVED: 'PQ Approved',
|
||||
REVISED: 'Revised'
|
||||
}
|
||||
@@ -25,23 +25,35 @@ export const MINGLAR_INVITATION_STATUS = {
|
||||
INVITED: 'Invited',
|
||||
};
|
||||
|
||||
export const HOST_SUGGESTION_TITLES = {
|
||||
COMPANY_DETAILS: 'Complete Details',
|
||||
COMPANY_DOCUMENTATION: 'Company documentataion',
|
||||
COMPANY_SOCIAL_PROOF: 'Social Proof',
|
||||
ACTIVITY_INFORMATION: 'Activity Information',
|
||||
ACTIVITY_LOCATION: 'Activity Location',
|
||||
PICKUP_DROP_LOCATION: 'Pickup-Drop Location',
|
||||
NUMBER_OF_PEOPLE: 'Number of People',
|
||||
INCLUSION: 'Inclusion',
|
||||
TAX_SETUP: 'Tax Setup',
|
||||
ENERGY_LEVEL: 'Energy Level',
|
||||
ELIGIBILITY_CRITERIA: 'Eligibility Criteria',
|
||||
AMENITIES: 'Amenities',
|
||||
EXLUSIVE_NOTES: 'Exclusive Notes',
|
||||
CANCELLATION_POLICY: 'Cancellation Policy',
|
||||
DOs_AND_DONTs: 'Do’s and Dont’s',
|
||||
TIPS_FOR_USERS: 'Tips for Users',
|
||||
SUSTAINABILITY: 'Sustainability',
|
||||
TERMS_AND_CONDITION_FOR_USER: 'Terms and Conditions for User'
|
||||
};
|
||||
export const ACTIVITY_TRACK_TYPE = {
|
||||
PQ: 'PQ',
|
||||
ACTIVITY: 'Activity'
|
||||
}
|
||||
|
||||
export const ACTIVITY_TRACK_STATUS = {
|
||||
REJECTED_BY_AM: 'Rejected By AM',
|
||||
ACCEPTED_BY_AM: 'Accepted By AM',
|
||||
ENHANCING: 'Enhancing',
|
||||
PQ_SUBMITTED: 'PQ Submitted'
|
||||
}
|
||||
|
||||
// export const HOST_SUGGESTION_TITLES = {
|
||||
// COMPANY_DETAILS: 'Complete Details',
|
||||
// COMPANY_DOCUMENTATION: 'Company documentataion',
|
||||
// COMPANY_SOCIAL_PROOF: 'Social Proof',
|
||||
// ACTIVITY_INFORMATION: 'Activity Information',
|
||||
// ACTIVITY_LOCATION: 'Activity Location',
|
||||
// PICKUP_DROP_LOCATION: 'Pickup-Drop Location',
|
||||
// NUMBER_OF_PEOPLE: 'Number of People',
|
||||
// INCLUSION: 'Inclusion',
|
||||
// TAX_SETUP: 'Tax Setup',
|
||||
// ENERGY_LEVEL: 'Energy Level',
|
||||
// ELIGIBILITY_CRITERIA: 'Eligibility Criteria',
|
||||
// AMENITIES: 'Amenities',
|
||||
// EXLUSIVE_NOTES: 'Exclusive Notes',
|
||||
// CANCELLATION_POLICY: 'Cancellation Policy',
|
||||
// DOs_AND_DONTs: 'Do’s and Dont’s',
|
||||
// TIPS_FOR_USERS: 'Tips for Users',
|
||||
// SUSTAINABILITY: 'Sustainability',
|
||||
// TERMS_AND_CONDITION_FOR_USER: 'Terms and Conditions for User'
|
||||
// };
|
||||
|
||||
@@ -11,11 +11,6 @@ export const hostBankDetailsSchema = z.object({
|
||||
.nonempty("Account holder name is required")
|
||||
.min(2, { message: "Account holder name must be at least 2 characters" }),
|
||||
|
||||
ifscCode: z
|
||||
.string()
|
||||
.nonempty("IFSC code is required")
|
||||
.regex(/^[A-Z]{4}0[A-Z0-9]{6}$/, { message: "Invalid IFSC code format" }),
|
||||
|
||||
bankXid: z
|
||||
.number()
|
||||
.int({ message: "Bank ID must be an integer" })
|
||||
|
||||
@@ -6,20 +6,20 @@ export const parentCompanySchema = z.object({
|
||||
.max(100, "Parent company name cannot exceed 100 characters"),
|
||||
|
||||
address1: z.string()
|
||||
.min(1, "Address1 is required")
|
||||
.max(150, "Address1 cannot exceed 150 characters"),
|
||||
.max(150, "Address1 cannot exceed 150 characters")
|
||||
.optional(),
|
||||
|
||||
address2: z.string()
|
||||
.max(150, "Address2 cannot exceed 150 characters")
|
||||
.optional(),
|
||||
|
||||
cityXid: z.number().min(1, "City is required"),
|
||||
stateXid: z.number().min(1, "State is required"),
|
||||
countryXid: z.number().min(1, "Country is required"),
|
||||
cityXid: z.number().optional(),
|
||||
stateXid: z.number().optional(),
|
||||
countryXid: z.number().optional(),
|
||||
|
||||
pinCode: z.string()
|
||||
.min(4, "Pincode/Zipcode is required")
|
||||
.max(30, "Pincode cannot exceed 30 characters"),
|
||||
.max(30, "Pincode cannot exceed 30 characters")
|
||||
.optional(),
|
||||
|
||||
logoPath: z.string()
|
||||
.max(400, "Logo path cannot exceed 400 characters")
|
||||
@@ -45,15 +45,15 @@ export const parentCompanySchema = z.object({
|
||||
message: "Formation date must be a valid date",
|
||||
}),
|
||||
|
||||
companyType: z.string()
|
||||
.min(1, "Company type is required")
|
||||
.max(30, "Company type cannot exceed 30 characters"),
|
||||
companyTypeXid: z.number()
|
||||
.min(1, "Company type XID is required"),
|
||||
|
||||
websiteUrl: z.string().nullable().optional(),
|
||||
instagramUrl: z.string().nullable().optional(),
|
||||
facebookUrl: z.string().nullable().optional(),
|
||||
linkedinUrl: z.string().nullable().optional(),
|
||||
twitterUrl: z.string().nullable().optional(),
|
||||
|
||||
websiteUrl: z.string().url().max(80, "Website URL cannot exceed 80 characters").optional(),
|
||||
instagramUrl: z.string().url().max(80, "Instagram URL cannot exceed 80 characters").optional(),
|
||||
facebookUrl: z.string().url().max(80, "Facebook URL cannot exceed 80 characters").optional(),
|
||||
linkedinUrl: z.string().url().max(80, "LinkedIn URL cannot exceed 80 characters").optional(),
|
||||
twitterUrl: z.string().url().max(80, "Twitter URL cannot exceed 80 characters").optional(),
|
||||
});
|
||||
|
||||
|
||||
@@ -106,15 +106,20 @@ export const hostCompanyDetailsSchema = z.object({
|
||||
message: "Formation date must be a valid date",
|
||||
}),
|
||||
|
||||
companyType: z.string()
|
||||
.min(1, "Company type is required")
|
||||
.max(30, "Company type cannot exceed 30 characters"),
|
||||
companyTypeXid: z.number()
|
||||
.int("Company type must be a valid integer")
|
||||
.min(1, "Company type is required"),
|
||||
|
||||
|
||||
referencedBy: z.string()
|
||||
.optional(),
|
||||
|
||||
websiteUrl: z.string().nullable().optional(),
|
||||
instagramUrl: z.string().nullable().optional(),
|
||||
facebookUrl: z.string().nullable().optional(),
|
||||
linkedinUrl: z.string().nullable().optional(),
|
||||
twitterUrl: z.string().nullable().optional(),
|
||||
|
||||
websiteUrl: z.string().url().max(50, "Website URL cannot exceed 50 characters").optional(),
|
||||
instagramUrl: z.string().url().max(80, "Instagram URL cannot exceed 80 characters").optional(),
|
||||
facebookUrl: z.string().url().max(80, "Facebook URL cannot exceed 80 characters").optional(),
|
||||
linkedinUrl: z.string().url().max(80, "LinkedIn URL cannot exceed 80 characters").optional(),
|
||||
twitterUrl: z.string().url().max(80, "Twitter URL cannot exceed 80 characters").optional(),
|
||||
|
||||
parentCompany: parentCompanySchema.optional(),
|
||||
});
|
||||
|
||||
@@ -90,5 +90,6 @@ export class AddPaymentDetailsDTO {
|
||||
this.accountHolderName = accountHolderName;
|
||||
this.ifscCode = ifscCode;
|
||||
this.hostXid = hostXid;
|
||||
this.currencyXid = currencyXid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||
import {
|
||||
APIGatewayProxyEvent,
|
||||
APIGatewayProxyResult,
|
||||
Context,
|
||||
} from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { HostService } from '../../../services/host.service';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const hostService = new HostService(prismaService);
|
||||
|
||||
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.',
|
||||
);
|
||||
}
|
||||
|
||||
// Verify token and get user info
|
||||
const userInfo = await verifyHostToken(token);
|
||||
|
||||
let body: any = {};
|
||||
try {
|
||||
body = event.body ? JSON.parse(event.body) : {};
|
||||
} catch (err) {
|
||||
throw new ApiError(400, 'Invalid JSON in request body');
|
||||
}
|
||||
|
||||
const { activityTypeXid, frequenciesXid } = body;
|
||||
|
||||
if (!activityTypeXid || !frequenciesXid) {
|
||||
throw new ApiError(400, 'activityType and frequency ID is required');
|
||||
}
|
||||
|
||||
// Get all host applications from service based on user role
|
||||
const createdData = await hostService.createActivityAndAllQuestionsEntry(userInfo.id, activityTypeXid, frequenciesXid);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: 'Activity created successfully',
|
||||
data: createdData
|
||||
}),
|
||||
};
|
||||
},
|
||||
);
|
||||
@@ -1,4 +1,4 @@
|
||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
||||
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
||||
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { HostService } from '../../../services/host.service';
|
||||
import { string } from 'zod';
|
||||
import { paginationService } from '../../../../../common/utils/pagination/pagination.service';
|
||||
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
@@ -29,11 +29,18 @@ export const handler = safeHandler(async (
|
||||
// Verify token and get user info
|
||||
const userInfo = await verifyHostToken(token);
|
||||
|
||||
// Get pagination params from event
|
||||
const paginationParams = paginationService.getPaginationFromEvent(event);
|
||||
const paginationOptions = paginationService.parsePaginationParams(paginationParams);
|
||||
|
||||
// Read optional search query (supports ?search= or ?q=)
|
||||
const search = event.queryStringParameters?.search || event.queryStringParameters?.q || undefined;
|
||||
|
||||
const data = await hostService.getAllHostActivity(search ? String(search) : undefined, Number(userInfo.id));
|
||||
const result = await hostService.getAllHostActivity(
|
||||
search ? String(search) : undefined,
|
||||
Number(userInfo.id),
|
||||
paginationOptions
|
||||
);
|
||||
|
||||
|
||||
return {
|
||||
@@ -45,8 +52,7 @@ export const handler = safeHandler(async (
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: 'Data retrieved successfully',
|
||||
data,
|
||||
|
||||
...result,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { PrePopulateService } from '../../../../prepopulate/services/prepopulate.service';
|
||||
import { HostService } from '../../../services/host.service';
|
||||
import { verifyMinglarAdminHostToken } from '@/common/middlewares/jwt/authForMinglarAdmin&Host';
|
||||
import { verifyMinglarAdminHostToken } from '../../../../../common/middlewares/jwt/authForMinglarAdminHost';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const hostService = new HostService(prismaService);
|
||||
@@ -23,7 +21,15 @@ export const handler = safeHandler(async (
|
||||
// Authenticate user using the shared authForHost function
|
||||
await verifyMinglarAdminHostToken(token);
|
||||
|
||||
const result = await hostService.getAllPQQQuesAndSubmittedAns();
|
||||
const activity_xid = event.queryStringParameters?.activity_xid
|
||||
? Number(event.queryStringParameters.activity_xid)
|
||||
: null;
|
||||
|
||||
if (!activity_xid) {
|
||||
throw new ApiError(409, "Activity ID is required")
|
||||
}
|
||||
|
||||
const result = await hostService.getAllPQQQuesAndSubmittedAns(Number(activity_xid));
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import config from '@/config/config';
|
||||
import config from '../../../../../config/config';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
||||
import AWS from 'aws-sdk';
|
||||
import Busboy from 'busboy';
|
||||
@@ -8,48 +8,36 @@ import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHo
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { HostService } from '../../../services/host.service';
|
||||
import { LAST_QUESTION_ID } from '@/common/utils/constants/host.constant';
|
||||
|
||||
const prisma = new PrismaService();
|
||||
const pqqService = new HostService(prisma);
|
||||
const hostService = new HostService(prisma);
|
||||
|
||||
const s3 = new AWS.S3({ region: config.aws.region });
|
||||
|
||||
// Function to extract S3 key from URL
|
||||
// Extract S3 key from URL
|
||||
function getS3KeyFromUrl(url: string): string {
|
||||
const bucketBaseUrl = `https://${config.aws.bucketName}.s3.${config.aws.region}.amazonaws.com/`;
|
||||
return url.replace(bucketBaseUrl, '');
|
||||
}
|
||||
|
||||
// Function to delete file from S3
|
||||
// Delete file from S3
|
||||
async function deleteFromS3(s3Key: string): Promise<void> {
|
||||
try {
|
||||
await s3.deleteObject({
|
||||
Bucket: config.aws.bucketName,
|
||||
Key: s3Key,
|
||||
}).promise();
|
||||
console.log(`✅ File deleted from S3: ${s3Key}`);
|
||||
} catch (error) {
|
||||
console.error(`❌ Error deleting file from S3: ${s3Key}`, error);
|
||||
// Don't throw error here, continue with upload
|
||||
console.log(`✅ Deleted from S3: ${s3Key}`);
|
||||
} catch (err) {
|
||||
console.error(`❌ Failed to delete from S3: ${s3Key}`, err);
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadToS3(buffer: Buffer, mimeType: string, originalName: string, prefix: string, existingUrl?: string): Promise<string> {
|
||||
let s3Key: string;
|
||||
|
||||
// If existing URL provided, use the same S3 key to replace the file
|
||||
if (existingUrl) {
|
||||
s3Key = getS3KeyFromUrl(existingUrl);
|
||||
// Delete existing file first
|
||||
await deleteFromS3(s3Key);
|
||||
} else {
|
||||
// Generate new unique key for new file
|
||||
// Upload new file
|
||||
async function uploadToS3(buffer: Buffer, mimeType: string, originalName: string, prefix: string): Promise<string> {
|
||||
const uniqueKey = `${crypto.randomUUID()}_${originalName}`;
|
||||
s3Key = `${prefix}/${uniqueKey}`;
|
||||
}
|
||||
const s3Key = `${prefix}/${uniqueKey}`;
|
||||
|
||||
// Upload new file (replaces existing if same key)
|
||||
await s3.upload({
|
||||
Bucket: config.aws.bucketName,
|
||||
Key: s3Key,
|
||||
@@ -58,253 +46,160 @@ async function uploadToS3(buffer: Buffer, mimeType: string, originalName: string
|
||||
ACL: 'private'
|
||||
}).promise();
|
||||
|
||||
console.log(`✅ File uploaded to S3: ${s3Key}`);
|
||||
console.log(`✅ Uploaded to S3: ${s3Key}`);
|
||||
return `https://${config.aws.bucketName}.s3.${config.aws.region}.amazonaws.com/${s3Key}`;
|
||||
}
|
||||
|
||||
export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
|
||||
try {
|
||||
// 1) Auth
|
||||
// AUTH
|
||||
const token = event.headers['x-auth-token'] || event.headers['X-Auth-Token'];
|
||||
if (!token) throw new ApiError(401, 'Missing token.');
|
||||
if (!token) throw new ApiError(401, 'Missing token');
|
||||
|
||||
const user = await verifyHostToken(token);
|
||||
|
||||
// 2) Content-Type check
|
||||
// Content-Type
|
||||
const contentType = event.headers["content-type"] || event.headers["Content-Type"];
|
||||
if (!contentType?.startsWith("multipart/form-data"))
|
||||
throw new ApiError(400, "Content-Type must be multipart/form-data");
|
||||
|
||||
if (!event.isBase64Encoded)
|
||||
throw new ApiError(400, "Body must be base64 encoded");
|
||||
if (!event.isBase64Encoded) throw new ApiError(400, "Body must be base64 encoded");
|
||||
|
||||
const bodyBuffer = Buffer.from(event.body!, "base64");
|
||||
|
||||
const fields: any = {};
|
||||
const files: Array<{ buffer: Buffer; mimeType: string; fileName: string; fieldName: string }> = [];
|
||||
|
||||
// 3) Parse multipart data
|
||||
// Parse multipart
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const bb = Busboy({ headers: { 'content-type': contentType } });
|
||||
|
||||
bb.on('file', (fieldname, file, info) => {
|
||||
const { filename, mimeType } = info;
|
||||
|
||||
// Skip if no filename (empty file field)
|
||||
if (!filename) {
|
||||
file.resume();
|
||||
return;
|
||||
}
|
||||
if (!filename) return file.resume();
|
||||
|
||||
const chunks: Buffer[] = [];
|
||||
let totalSize = 0;
|
||||
const MAX_SIZE = 5 * 1024 * 1024; // 5 MB
|
||||
let size = 0;
|
||||
|
||||
file.on('data', chunk => {
|
||||
size += chunk.length;
|
||||
if (size > 5 * 1024 * 1024)
|
||||
return reject(new ApiError(400, `File ${filename} exceeds 5MB limit`));
|
||||
|
||||
file.on('data', (chunk) => {
|
||||
totalSize += chunk.length;
|
||||
if (totalSize > MAX_SIZE) {
|
||||
file.resume();
|
||||
return reject(new ApiError(400, `File ${filename} exceeds 5MB limit.`));
|
||||
}
|
||||
chunks.push(chunk);
|
||||
});
|
||||
|
||||
file.on('end', () => {
|
||||
// Only add file if we have data
|
||||
if (chunks.length > 0) {
|
||||
files.push({
|
||||
buffer: Buffer.concat(chunks),
|
||||
mimeType,
|
||||
fileName: filename,
|
||||
fieldName: fieldname,
|
||||
fieldName: fieldname
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
file.on('error', (err) => {
|
||||
reject(new ApiError(400, `File upload error: ${err.message}`));
|
||||
});
|
||||
});
|
||||
|
||||
bb.on('field', (fieldname, val) => {
|
||||
// Handle empty or null values
|
||||
if (val === '' || val === 'null' || val === 'undefined') {
|
||||
fields[fieldname] = null;
|
||||
} else {
|
||||
try {
|
||||
fields[fieldname] = JSON.parse(val);
|
||||
} catch {
|
||||
fields[fieldname] = val;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
bb.on('close', () => {
|
||||
console.log("✅ Busboy parsing completed");
|
||||
console.log("📌 Fields:", fields);
|
||||
console.log("📁 Files:", files.length);
|
||||
resolve();
|
||||
});
|
||||
|
||||
bb.on('error', (err) => {
|
||||
console.error("❌ Busboy error:", err);
|
||||
reject(new ApiError(400, `Multipart parsing error: ${err.message}`));
|
||||
try { fields[fieldname] = JSON.parse(val); }
|
||||
catch { fields[fieldname] = val; }
|
||||
});
|
||||
|
||||
bb.on('close', resolve);
|
||||
bb.on('error', err => reject(new ApiError(400, err.message)));
|
||||
bb.end(bodyBuffer);
|
||||
});
|
||||
|
||||
// 4) Extract required fields - only activityXid, pqqQuestionXid, pqqAnswerXid are required
|
||||
// Required fields
|
||||
const activityXid = Number(fields.activityXid);
|
||||
const pqqQuestionXid = Number(fields.pqqQuestionXid);
|
||||
const pqqAnswerXid = Number(fields.pqqAnswerXid);
|
||||
|
||||
// Comments and files are optional
|
||||
const comments = fields.comments || null;
|
||||
|
||||
// Validate required fields
|
||||
if (!activityXid || isNaN(activityXid)) throw new ApiError(400, "Valid activityXid is required");
|
||||
if (!pqqQuestionXid || isNaN(pqqQuestionXid)) throw new ApiError(400, "Valid pqqQuestionXid is required");
|
||||
if (pqqQuestionXid !== LAST_QUESTION_ID.Q_ID) throw new ApiError(400, "Wrong question id.")
|
||||
if (!pqqAnswerXid || isNaN(pqqAnswerXid)) throw new ApiError(400, "Valid pqqAnswerXid is required");
|
||||
|
||||
// console.log(`📝 Processing - Activity: ${activityXid}, Question: ${pqqQuestionXid}, Answer: ${pqqAnswerXid}`);
|
||||
// console.log(`💬 Comments: ${comments ? 'Provided' : 'Not provided'}`);
|
||||
// console.log(`📎 Files: ${files.length}`);
|
||||
|
||||
// 5) UPSERT: Check if header already exists for this combination
|
||||
const existingHeader = await pqqService.findHeaderByCompositeKey(
|
||||
activityXid,
|
||||
pqqQuestionXid,
|
||||
pqqAnswerXid
|
||||
);
|
||||
if (!activityXid || !pqqQuestionXid || !pqqAnswerXid)
|
||||
throw new ApiError(400, "Missing required fields");
|
||||
|
||||
// UPSERT header
|
||||
const existingHeader = await hostService.findHeaderByCompositeKey(activityXid, pqqQuestionXid);
|
||||
let header;
|
||||
|
||||
if (existingHeader) {
|
||||
console.log("🔄 Updating existing PQQ header");
|
||||
// Update existing header (comments can be null)
|
||||
header = await pqqService.updateHeader(
|
||||
existingHeader.id,
|
||||
comments
|
||||
);
|
||||
header = await hostService.updateHeader(existingHeader.id, pqqAnswerXid, comments);
|
||||
} else {
|
||||
console.log("🆕 Creating new PQQ header");
|
||||
// Create new header (comments can be null)
|
||||
header = await pqqService.createHeader(
|
||||
activityXid,
|
||||
pqqQuestionXid,
|
||||
pqqAnswerXid,
|
||||
comments
|
||||
);
|
||||
header = await hostService.createHeader(activityXid, pqqQuestionXid, pqqAnswerXid, comments);
|
||||
}
|
||||
// Calculate score after answer submission
|
||||
const score = await pqqService.calculatePqqScoreForUser(activityXid);
|
||||
|
||||
// SCORE
|
||||
const score = await hostService.calculatePqqScoreForUser(activityXid);
|
||||
|
||||
// 6) Get existing supporting files for this header
|
||||
const existingSupportingFiles = await pqqService.getSupportingFilesByHeaderId(header.id);
|
||||
console.log(`📁 Found ${existingSupportingFiles.length} existing supporting files`);
|
||||
// Existing supporting files
|
||||
const existingSupportingFiles = await hostService.getSupportingFilesByHeaderId(header.id);
|
||||
|
||||
// 7) Handle file UPSERT - only if files are provided
|
||||
const uploadedFiles: any[] = [];
|
||||
// Read deletedFiles from frontend
|
||||
const deletedFiles = Array.isArray(fields.deletedFiles) ? fields.deletedFiles : [];
|
||||
|
||||
const deleteResults = [];
|
||||
const addResults = [];
|
||||
|
||||
// DELETE explicitly requested files (Case 3)
|
||||
if (deletedFiles.length > 0) {
|
||||
for (const del of deletedFiles) {
|
||||
const id = Number(del.id);
|
||||
const record = existingSupportingFiles.find(f => f.id === id);
|
||||
if (!record) continue;
|
||||
|
||||
// Delete from S3
|
||||
if (record.mediaFileName) {
|
||||
const key = getS3KeyFromUrl(record.mediaFileName);
|
||||
await deleteFromS3(key);
|
||||
}
|
||||
|
||||
// Delete from DB
|
||||
await hostService.deleteSupportingFile(record.id);
|
||||
deleteResults.push({ id: record.id, deleted: true });
|
||||
}
|
||||
}
|
||||
|
||||
// ADD new uploaded files (Case 1 + Case 3 new files)
|
||||
if (files.length > 0) {
|
||||
console.log("📤 Processing file uploads...");
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
const existingFile = existingSupportingFiles[i] || null;
|
||||
|
||||
for (const file of files) {
|
||||
const url = await uploadToS3(
|
||||
file.buffer,
|
||||
file.mimeType,
|
||||
file.fileName,
|
||||
`ActivityOnboarding/supportings/${activityXid}`,
|
||||
existingFile ? existingFile.mediaFileName : undefined
|
||||
`ActivityOnboarding/supportings/${activityXid}`
|
||||
);
|
||||
|
||||
let supporting;
|
||||
if (existingFile) {
|
||||
// Update existing supporting file record
|
||||
supporting = await pqqService.updateSupportingFile(
|
||||
existingFile.id,
|
||||
file.mimeType,
|
||||
url
|
||||
);
|
||||
console.log(`🔄 Updated supporting file: ${existingFile.id}`);
|
||||
} else {
|
||||
// Create new supporting file record
|
||||
supporting = await pqqService.addSupportingFile(
|
||||
header.id,
|
||||
file.mimeType,
|
||||
url
|
||||
);
|
||||
console.log(`🆕 Created new supporting file: ${supporting.id}`);
|
||||
}
|
||||
|
||||
uploadedFiles.push(supporting);
|
||||
}
|
||||
|
||||
// 8) Delete any remaining existing files that weren't replaced
|
||||
if (existingSupportingFiles.length > files.length) {
|
||||
const filesToDelete = existingSupportingFiles.slice(files.length);
|
||||
console.log(`🗑️ Deleting ${filesToDelete.length} unused supporting files`);
|
||||
|
||||
for (const fileToDelete of filesToDelete) {
|
||||
await pqqService.deleteSupportingFile(fileToDelete.id);
|
||||
// Also delete from S3
|
||||
const s3Key = getS3KeyFromUrl(fileToDelete.mediaFileName);
|
||||
await deleteFromS3(s3Key);
|
||||
console.log(`🗑️ Deleted supporting file: ${fileToDelete.id}`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log("📭 No files provided in request");
|
||||
|
||||
// If no files provided but existing files exist, delete them (cleanup)
|
||||
if (existingSupportingFiles.length > 0) {
|
||||
console.log(`🗑️ No new files provided, deleting ${existingSupportingFiles.length} existing files`);
|
||||
for (const fileToDelete of existingSupportingFiles) {
|
||||
await pqqService.deleteSupportingFile(fileToDelete.id);
|
||||
const s3Key = getS3KeyFromUrl(fileToDelete.mediaFileName);
|
||||
await deleteFromS3(s3Key);
|
||||
console.log(`🗑️ Deleted supporting file: ${fileToDelete.id}`);
|
||||
}
|
||||
const newRec = await hostService.addSupportingFile(header.id, file.mimeType, url);
|
||||
addResults.push(newRec);
|
||||
}
|
||||
}
|
||||
|
||||
// 9) Prepare response
|
||||
const responseMessage = existingHeader ? "PQQ answer updated successfully" : "PQQ answer submitted successfully";
|
||||
const getAllUpdatedQuestionResponse = await hostService.getAllPQUpdatedResponse(activityXid)
|
||||
|
||||
// CASE 2 — NO deletion & NO new files => DO NOTHING to existing files
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Access-Control-Allow-Origin": "*"
|
||||
},
|
||||
headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" },
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: responseMessage,
|
||||
message: existingHeader ? "PQQ answer updated successfully" : "PQQ answer submitted successfully",
|
||||
data: {
|
||||
headerId: header.id,
|
||||
activityXid,
|
||||
pqqQuestionXid,
|
||||
pqqAnswerXid,
|
||||
comments: comments,
|
||||
comments,
|
||||
score,
|
||||
files: {
|
||||
uploaded: uploadedFiles,
|
||||
total: uploadedFiles.length
|
||||
},
|
||||
operation: existingHeader ? 'updated' : 'created',
|
||||
fileOperation: files.length > 0 ?
|
||||
(existingSupportingFiles.length > 0 ? 'replaced' : 'added') :
|
||||
(existingSupportingFiles.length > 0 ? 'removed' : 'unchanged')
|
||||
getAllUpdatedQuestionResponse
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
} catch (error: any) {
|
||||
console.error("❌ Error in submitPqqAnswer:", error);
|
||||
throw error;
|
||||
} catch (err: any) {
|
||||
console.error("❌ Error:", err);
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
@@ -1,10 +1,9 @@
|
||||
import { verifyMinglarAdminHostToken } from '../../../../../common/middlewares/jwt/authForMinglarAdminHost';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
||||
import { HostService } from '../../../services/host.service';
|
||||
import { verifyMinglarAdminHostToken } from '@/common/middlewares/jwt/authForMinglarAdmin&Host';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const hostService = new HostService(prismaService);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
||||
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||
import { HostService } from '../../../services/host.service';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
@@ -29,15 +29,18 @@ export const handler = safeHandler(async (
|
||||
if (!activity_xid || isNaN(activity_xid)) {
|
||||
throw new ApiError(400, "Activity id is required and must be a number.");
|
||||
}
|
||||
let result = null;
|
||||
|
||||
// Fetch user with their HostHeader stepper info
|
||||
const pqqQuestionDetails = await hostService.getLatestQuestionDetailsPQQ(activity_xid);
|
||||
|
||||
const result = {
|
||||
if (pqqQuestionDetails) {
|
||||
result = {
|
||||
pqqQuestionXid: pqqQuestionDetails.pqqQuestionXid,
|
||||
pqqAnswerXid: pqqQuestionDetails.pqqAnswerXid,
|
||||
pqqSubCategoryXid: pqqQuestionDetails.pqqQuestions.pqqSubCategoryXid,
|
||||
categoryXid: pqqQuestionDetails.pqqQuestions.pqqSubCategories.categoryXid
|
||||
pqqAnswerXid: pqqQuestionDetails.pqqAnswerXid || null,
|
||||
pqqSubCategoryXid: pqqQuestionDetails.pqqQuestions.pqqSubCategoryXid || null,
|
||||
categoryXid: pqqQuestionDetails.pqqQuestions.pqqSubCategories.categoryXid || null
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
||||
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
|
||||
@@ -0,0 +1,301 @@
|
||||
import config from '../../../../../config/config';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
||||
import AWS from 'aws-sdk';
|
||||
import Busboy from 'busboy';
|
||||
import crypto from 'crypto';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { HostService } from '../../../services/host.service';
|
||||
|
||||
const prisma = new PrismaService();
|
||||
const hostService = new HostService(prisma);
|
||||
|
||||
const s3 = new AWS.S3({ region: config.aws.region });
|
||||
|
||||
// Function to extract S3 key from URL
|
||||
function getS3KeyFromUrl(url: string): string {
|
||||
const bucketBaseUrl = `https://${config.aws.bucketName}.s3.${config.aws.region}.amazonaws.com/`;
|
||||
return url.replace(bucketBaseUrl, '');
|
||||
}
|
||||
|
||||
// Function to delete file from S3
|
||||
async function deleteFromS3(s3Key: string): Promise<void> {
|
||||
try {
|
||||
await s3.deleteObject({
|
||||
Bucket: config.aws.bucketName,
|
||||
Key: s3Key,
|
||||
}).promise();
|
||||
console.log(`✅ File deleted from S3: ${s3Key}`);
|
||||
} catch (error) {
|
||||
console.error(`❌ Error deleting file from S3: ${s3Key}`, error);
|
||||
// continue — we don't want S3 deletion failure to crash the whole request
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadToS3(buffer: Buffer, mimeType: string, originalName: string, prefix: string, existingUrl?: string): Promise<string> {
|
||||
// We intentionally do NOT reuse old key. If existingUrl is provided we delete old file and create a new random key.
|
||||
if (existingUrl) {
|
||||
try {
|
||||
const oldKey = getS3KeyFromUrl(existingUrl);
|
||||
await deleteFromS3(oldKey);
|
||||
} catch (err) {
|
||||
console.warn('Warning deleting existingUrl before upload', err);
|
||||
}
|
||||
}
|
||||
|
||||
const uniqueKey = `${crypto.randomUUID()}_${originalName}`;
|
||||
const s3Key = `${prefix}/${uniqueKey}`;
|
||||
|
||||
await s3.upload({
|
||||
Bucket: config.aws.bucketName,
|
||||
Key: s3Key,
|
||||
Body: buffer,
|
||||
ContentType: mimeType,
|
||||
ACL: 'private'
|
||||
}).promise();
|
||||
|
||||
console.log(`✅ File uploaded to S3: ${s3Key}`);
|
||||
return `https://${config.aws.bucketName}.s3.${config.aws.region}.amazonaws.com/${s3Key}`;
|
||||
}
|
||||
|
||||
export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
|
||||
try {
|
||||
// 1) Auth
|
||||
const token = event.headers['x-auth-token'] || event.headers['X-Auth-Token'];
|
||||
if (!token) throw new ApiError(401, 'Missing token.');
|
||||
const user = await verifyHostToken(token);
|
||||
|
||||
// 2) Content-Type check
|
||||
const contentType = event.headers["content-type"] || event.headers["Content-Type"];
|
||||
if (!contentType?.includes("multipart/form-data"))
|
||||
throw new ApiError(400, "Content-Type must be multipart/form-data");
|
||||
|
||||
// 3) Body decoding
|
||||
const bodyBuffer = event.isBase64Encoded
|
||||
? Buffer.from(event.body!, "base64")
|
||||
: Buffer.from(event.body!, "binary");
|
||||
|
||||
const fields: any = {};
|
||||
const files: Array<{ buffer: Buffer; mimeType: string; fileName: string; fieldName: string }> = [];
|
||||
|
||||
// 4) Parse multipart data
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const bb = Busboy({ headers: { 'content-type': contentType } });
|
||||
|
||||
bb.on('file', (fieldname, file, info) => {
|
||||
const { filename, mimeType } = info;
|
||||
|
||||
if (!filename) {
|
||||
file.resume();
|
||||
return;
|
||||
}
|
||||
|
||||
const chunks: Buffer[] = [];
|
||||
let size = 0;
|
||||
const MAX_SIZE = 5 * 1024 * 1024;
|
||||
|
||||
file.on("data", (chunk) => {
|
||||
size += chunk.length;
|
||||
if (size > MAX_SIZE) {
|
||||
file.destroy(new Error(`File ${filename} exceeds 5MB limit.`));
|
||||
return;
|
||||
}
|
||||
chunks.push(chunk);
|
||||
});
|
||||
|
||||
file.on("end", () => {
|
||||
if (chunks.length > 0) {
|
||||
files.push({
|
||||
buffer: Buffer.concat(chunks),
|
||||
mimeType,
|
||||
fileName: filename,
|
||||
fieldName: fieldname,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
file.on("error", (err) =>
|
||||
reject(new ApiError(400, `File upload error: ${err.message}`))
|
||||
);
|
||||
});
|
||||
|
||||
bb.on("field", (fieldname, val) => {
|
||||
console.log(`FIELD RAW: ${fieldname} =`, val);
|
||||
if (val === '' || val === 'null' || val === 'undefined') fields[fieldname] = null;
|
||||
else {
|
||||
try {
|
||||
const cleaned = val.trim();
|
||||
|
||||
// If it starts and ends with quotes, remove them
|
||||
const withoutQuotes =
|
||||
(cleaned.startsWith('"') && cleaned.endsWith('"'))
|
||||
? cleaned.slice(1, -1)
|
||||
: cleaned;
|
||||
|
||||
fields[fieldname] = JSON.parse(withoutQuotes);
|
||||
} catch {
|
||||
fields[fieldname] = val;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
bb.on("close", () => resolve());
|
||||
bb.on("error", (err) =>
|
||||
reject(new ApiError(400, `Multipart parsing error: ${err.message}`))
|
||||
);
|
||||
|
||||
// IMPORTANT FIX for HTTP API
|
||||
bb.write(bodyBuffer);
|
||||
bb.end();
|
||||
});
|
||||
|
||||
// 5) Extract required fields
|
||||
const activityXid = Number(fields.activityXid);
|
||||
const pqqQuestionXid = Number(fields.pqqQuestionXid);
|
||||
const pqqAnswerXid = Number(fields.pqqAnswerXid);
|
||||
const comments = fields.comments || null;
|
||||
|
||||
if (!activityXid || isNaN(activityXid)) throw new ApiError(400, "Valid activityXid is required");
|
||||
if (!pqqQuestionXid || isNaN(pqqQuestionXid)) throw new ApiError(400, "Valid pqqQuestionXid is required");
|
||||
if (!pqqAnswerXid || isNaN(pqqAnswerXid)) throw new ApiError(400, "Valid pqqAnswerXid is required");
|
||||
|
||||
// 6) UPSERT header
|
||||
const existingHeader = await hostService.findHeaderByCompositeKey(
|
||||
activityXid,
|
||||
pqqQuestionXid,
|
||||
);
|
||||
|
||||
let header;
|
||||
if (existingHeader) {
|
||||
console.log("🔄 Updating existing PQQ header");
|
||||
header = await hostService.updateHeader(
|
||||
existingHeader.id,
|
||||
pqqAnswerXid,
|
||||
comments
|
||||
);
|
||||
} else {
|
||||
console.log("🆕 Creating new PQQ header");
|
||||
header = await hostService.createHeader(
|
||||
activityXid,
|
||||
pqqQuestionXid,
|
||||
pqqAnswerXid,
|
||||
comments
|
||||
);
|
||||
}
|
||||
|
||||
// 7) Get existing supporting files
|
||||
const existingSupportingFiles = await hostService.getSupportingFilesByHeaderId(header.id);
|
||||
console.log(`📁 Found ${existingSupportingFiles.length} existing supporting files`);
|
||||
|
||||
// 8) Parse incoming control fields
|
||||
// fields.deletedFiles should be array like [{ id: number, url: string }, ...] or null
|
||||
const deletedFiles: Array<{ id: number; url?: string }> = Array.isArray(fields.deletedFiles) ? fields.deletedFiles : [];
|
||||
// fields.existingFiles can be an array of urls; we accept it but do not require it
|
||||
const existingFilesFromFront: string[] = Array.isArray(fields.existingFiles) ? fields.existingFiles : [];
|
||||
|
||||
// Prepare response trackers
|
||||
const deletedResults: Array<{ id: number; success: boolean; reason?: string }> = [];
|
||||
const addedResults: Array<any> = [];
|
||||
|
||||
// 9) Handle explicit deletions (ONLY delete ids provided in deletedFiles)
|
||||
if (deletedFiles.length > 0) {
|
||||
console.log(`🗑️ Processing ${deletedFiles.length} explicit deletions`);
|
||||
// Build a map of existing supporting files by id for quick lookup
|
||||
const existingById = new Map<number, any>();
|
||||
for (const f of existingSupportingFiles) {
|
||||
existingById.set(f.id, f);
|
||||
}
|
||||
|
||||
for (const del of deletedFiles) {
|
||||
const id = Number(del.id);
|
||||
if (!id || !existingById.has(id)) {
|
||||
deletedResults.push({ id, success: false, reason: 'Not found or invalid id' });
|
||||
continue;
|
||||
}
|
||||
|
||||
const record = existingById.get(id);
|
||||
try {
|
||||
// delete from s3
|
||||
if (record.mediaFileName) {
|
||||
const s3Key = getS3KeyFromUrl(record.mediaFileName);
|
||||
await deleteFromS3(s3Key);
|
||||
}
|
||||
|
||||
// delete DB record
|
||||
await hostService.deleteSupportingFile(record.id);
|
||||
|
||||
deletedResults.push({ id: record.id, success: true });
|
||||
console.log(`🗑️ Deleted supporting file record ${record.id}`);
|
||||
} catch (err: any) {
|
||||
console.error(`❌ Failed to delete supporting file id ${id}`, err);
|
||||
deletedResults.push({ id, success: false, reason: err.message || 'delete failed' });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log('ℹ️ No explicit deletions requested (deletedFiles empty)');
|
||||
}
|
||||
|
||||
// 10) Handle new uploaded files (these are ALWAYS added as new rows)
|
||||
if (files.length > 0) {
|
||||
console.log(`📤 Processing ${files.length} uploaded new file(s)`);
|
||||
for (const file of files) {
|
||||
try {
|
||||
const url = await uploadToS3(
|
||||
file.buffer,
|
||||
file.mimeType,
|
||||
file.fileName,
|
||||
`ActivityOnboarding/supportings/${activityXid}`
|
||||
);
|
||||
|
||||
// create DB record
|
||||
const supporting = await hostService.addSupportingFile(
|
||||
header.id,
|
||||
file.mimeType,
|
||||
url
|
||||
);
|
||||
|
||||
addedResults.push(supporting);
|
||||
console.log(`🆕 Created new supporting file record: ${supporting.id}`);
|
||||
} catch (err: any) {
|
||||
console.error('❌ Error uploading/creating supporting file', err);
|
||||
// push failure result but continue processing other files
|
||||
addedResults.push({ success: false, reason: err.message || 'upload/create failed' });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log('📭 No new files uploaded in request');
|
||||
}
|
||||
|
||||
// NOTE: We DO NOT delete or modify existing supporting files that were not listed in deletedFiles.
|
||||
// This satisfies your Case 2: "if no files are provided, do not touch existing supporting files".
|
||||
|
||||
const allPQPQuestionAnswerResponse = await hostService.getAllPQUpdatedResponse(activityXid)
|
||||
|
||||
// 11) Compose response
|
||||
const responseMessage = existingHeader ? "PQQ answer updated successfully" : "PQQ answer submitted successfully";
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Access-Control-Allow-Origin": "*"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: responseMessage,
|
||||
data: {
|
||||
responseOfUpdatedData: allPQPQuestionAnswerResponse,
|
||||
operation: existingHeader ? 'updated' : 'created',
|
||||
// summary label for UI convenience:
|
||||
fileOperation: (deletedResults.length > 0 || addedResults.length > 0) ? 'modified' : 'unchanged'
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
} catch (error: any) {
|
||||
console.error("❌ Error in submitPqqAnswer:", error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { HostService } from '../../../services/host.service';
|
||||
|
||||
const prisma = new PrismaService();
|
||||
const pqqService = new HostService(prisma);
|
||||
|
||||
export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
|
||||
try {
|
||||
// 1) Auth
|
||||
const token = event.headers['x-auth-token'] || event.headers['X-Auth-Token'];
|
||||
if (!token) throw new ApiError(401, 'Missing token.');
|
||||
const user = await verifyHostToken(token);
|
||||
|
||||
const activity_xid = event.queryStringParameters?.activity_xid
|
||||
? Number(event.queryStringParameters.activity_xid)
|
||||
: null;
|
||||
|
||||
await pqqService.submitpqqforreview(Number(activity_xid), Number(user.id))
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Access-Control-Allow-Origin": "*"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: "Your PQQ has been submitted for review.",
|
||||
data: null
|
||||
})
|
||||
};
|
||||
|
||||
} catch (error: any) {
|
||||
console.error("❌ Error in submitPqqAnswer:", error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
@@ -1,10 +1,10 @@
|
||||
import config from '@/config/config';
|
||||
import config from '../../../../../config/config';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
||||
import AWS from 'aws-sdk';
|
||||
import Busboy from 'busboy';
|
||||
import crypto from 'crypto';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
||||
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { HostService } from '../../../services/host.service';
|
||||
@@ -30,34 +30,24 @@ async function deleteFromS3(s3Key: string): Promise<void> {
|
||||
console.log(`✅ File deleted from S3: ${s3Key}`);
|
||||
} catch (error) {
|
||||
console.error(`❌ Error deleting file from S3: ${s3Key}`, error);
|
||||
// Don't throw error here, continue with upload
|
||||
// continue — we don't want S3 deletion failure to crash the whole request
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadToS3(buffer: Buffer, mimeType: string, originalName: string, prefix: string, existingUrl?: string): Promise<string> {
|
||||
let s3Key: string;
|
||||
|
||||
// If existing URL provided, use the same S3 key to replace the file
|
||||
// if (existingUrl) {
|
||||
// s3Key = getS3KeyFromUrl(existingUrl);
|
||||
// // Delete existing file first
|
||||
// await deleteFromS3(s3Key);
|
||||
// } else {
|
||||
// // Generate new unique key for new file
|
||||
// const uniqueKey = `${crypto.randomUUID()}_${originalName}`;
|
||||
// s3Key = `${prefix}/${uniqueKey}`;
|
||||
// }
|
||||
// We intentionally do NOT reuse old key. If existingUrl is provided we delete old file and create a new random key.
|
||||
if (existingUrl) {
|
||||
// Delete old file, but DO NOT reuse its name
|
||||
try {
|
||||
const oldKey = getS3KeyFromUrl(existingUrl);
|
||||
await deleteFromS3(oldKey);
|
||||
} catch (err) {
|
||||
console.warn('Warning deleting existingUrl before upload', err);
|
||||
}
|
||||
}
|
||||
|
||||
// Create new key always
|
||||
const uniqueKey = `${crypto.randomUUID()}_${originalName}`;
|
||||
s3Key = `${prefix}/${uniqueKey}`;
|
||||
const s3Key = `${prefix}/${uniqueKey}`;
|
||||
|
||||
// Upload new file (replaces existing if same key)
|
||||
await s3.upload({
|
||||
Bucket: config.aws.bucketName,
|
||||
Key: s3Key,
|
||||
@@ -82,7 +72,7 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
||||
if (!contentType?.includes("multipart/form-data"))
|
||||
throw new ApiError(400, "Content-Type must be multipart/form-data");
|
||||
|
||||
// 3) Body decoding (FIXED – same as addCompanyDetails)
|
||||
// 3) Body decoding
|
||||
const bodyBuffer = event.isBase64Encoded
|
||||
? Buffer.from(event.body!, "base64")
|
||||
: Buffer.from(event.body!, "binary");
|
||||
@@ -90,7 +80,7 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
||||
const fields: any = {};
|
||||
const files: Array<{ buffer: Buffer; mimeType: string; fileName: string; fieldName: string }> = [];
|
||||
|
||||
// 4) Parse multipart data (FIXED – using bb.write + bb.end exactly like working lambda)
|
||||
// 4) Parse multipart data
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const bb = Busboy({ headers: { 'content-type': contentType } });
|
||||
|
||||
@@ -152,41 +142,32 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
||||
bb.end();
|
||||
});
|
||||
|
||||
// 4) Extract required fields - only activityXid, pqqQuestionXid, pqqAnswerXid are required
|
||||
// 5) Extract required fields
|
||||
const activityXid = Number(fields.activityXid);
|
||||
const pqqQuestionXid = Number(fields.pqqQuestionXid);
|
||||
const pqqAnswerXid = Number(fields.pqqAnswerXid);
|
||||
|
||||
// Comments and files are optional
|
||||
const comments = fields.comments || null;
|
||||
|
||||
// Validate required fields
|
||||
if (!activityXid || isNaN(activityXid)) throw new ApiError(400, "Valid activityXid is required");
|
||||
if (!pqqQuestionXid || isNaN(pqqQuestionXid)) throw new ApiError(400, "Valid pqqQuestionXid is required");
|
||||
if (!pqqAnswerXid || isNaN(pqqAnswerXid)) throw new ApiError(400, "Valid pqqAnswerXid is required");
|
||||
|
||||
// console.log(`📝 Processing - Activity: ${activityXid}, Question: ${pqqQuestionXid}, Answer: ${pqqAnswerXid}`);
|
||||
// console.log(`💬 Comments: ${comments ? 'Provided' : 'Not provided'}`);
|
||||
// console.log(`📎 Files: ${files.length}`);
|
||||
|
||||
// 5) UPSERT: Check if header already exists for this combination
|
||||
// 6) UPSERT header
|
||||
const existingHeader = await pqqService.findHeaderByCompositeKey(
|
||||
activityXid,
|
||||
pqqQuestionXid,
|
||||
pqqAnswerXid
|
||||
);
|
||||
|
||||
let header;
|
||||
if (existingHeader) {
|
||||
console.log("🔄 Updating existing PQQ header");
|
||||
// Update existing header (comments can be null)
|
||||
header = await pqqService.updateHeader(
|
||||
existingHeader.id,
|
||||
pqqAnswerXid,
|
||||
comments
|
||||
);
|
||||
} else {
|
||||
console.log("🆕 Creating new PQQ header");
|
||||
// Create new header (comments can be null)
|
||||
header = await pqqService.createHeader(
|
||||
activityXid,
|
||||
pqqQuestionXid,
|
||||
@@ -195,79 +176,93 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
||||
);
|
||||
}
|
||||
|
||||
// 6) Get existing supporting files for this header
|
||||
// 7) Get existing supporting files
|
||||
const existingSupportingFiles = await pqqService.getSupportingFilesByHeaderId(header.id);
|
||||
console.log(`📁 Found ${existingSupportingFiles.length} existing supporting files`);
|
||||
|
||||
// 7) Handle file UPSERT - only if files are provided
|
||||
const uploadedFiles: any[] = [];
|
||||
// 8) Parse incoming control fields
|
||||
// fields.deletedFiles should be array like [{ id: number, url: string }, ...] or null
|
||||
const deletedFiles: Array<{ id: number; url?: string }> = Array.isArray(fields.deletedFiles) ? fields.deletedFiles : [];
|
||||
// fields.existingFiles can be an array of urls; we accept it but do not require it
|
||||
const existingFilesFromFront: string[] = Array.isArray(fields.existingFiles) ? fields.existingFiles : [];
|
||||
|
||||
// Prepare response trackers
|
||||
const deletedResults: Array<{ id: number; success: boolean; reason?: string }> = [];
|
||||
const addedResults: Array<any> = [];
|
||||
|
||||
// 9) Handle explicit deletions (ONLY delete ids provided in deletedFiles)
|
||||
if (deletedFiles.length > 0) {
|
||||
console.log(`🗑️ Processing ${deletedFiles.length} explicit deletions`);
|
||||
// Build a map of existing supporting files by id for quick lookup
|
||||
const existingById = new Map<number, any>();
|
||||
for (const f of existingSupportingFiles) {
|
||||
existingById.set(f.id, f);
|
||||
}
|
||||
|
||||
for (const del of deletedFiles) {
|
||||
const id = Number(del.id);
|
||||
if (!id || !existingById.has(id)) {
|
||||
deletedResults.push({ id, success: false, reason: 'Not found or invalid id' });
|
||||
continue;
|
||||
}
|
||||
|
||||
const record = existingById.get(id);
|
||||
try {
|
||||
// delete from s3
|
||||
if (record.mediaFileName) {
|
||||
const s3Key = getS3KeyFromUrl(record.mediaFileName);
|
||||
await deleteFromS3(s3Key);
|
||||
}
|
||||
|
||||
// delete DB record
|
||||
await pqqService.deleteSupportingFile(record.id);
|
||||
|
||||
deletedResults.push({ id: record.id, success: true });
|
||||
console.log(`🗑️ Deleted supporting file record ${record.id}`);
|
||||
} catch (err: any) {
|
||||
console.error(`❌ Failed to delete supporting file id ${id}`, err);
|
||||
deletedResults.push({ id, success: false, reason: err.message || 'delete failed' });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log('ℹ️ No explicit deletions requested (deletedFiles empty)');
|
||||
}
|
||||
|
||||
// 10) Handle new uploaded files (these are ALWAYS added as new rows)
|
||||
if (files.length > 0) {
|
||||
console.log("📤 Processing file uploads...");
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
const existingFile = existingSupportingFiles[i] || null;
|
||||
|
||||
console.log(`📤 Processing ${files.length} uploaded new file(s)`);
|
||||
for (const file of files) {
|
||||
try {
|
||||
const url = await uploadToS3(
|
||||
file.buffer,
|
||||
file.mimeType,
|
||||
file.fileName,
|
||||
`ActivityOnboarding/supportings/${activityXid}`,
|
||||
existingFile ? existingFile.mediaFileName : undefined
|
||||
`ActivityOnboarding/supportings/${activityXid}`
|
||||
);
|
||||
|
||||
let supporting;
|
||||
if (existingFile) {
|
||||
// Update existing supporting file record
|
||||
supporting = await pqqService.updateSupportingFile(
|
||||
existingFile.id,
|
||||
file.mimeType,
|
||||
url
|
||||
);
|
||||
console.log(`🔄 Updated supporting file: ${existingFile.id}`);
|
||||
} else {
|
||||
// Create new supporting file record
|
||||
supporting = await pqqService.addSupportingFile(
|
||||
// create DB record
|
||||
const supporting = await pqqService.addSupportingFile(
|
||||
header.id,
|
||||
file.mimeType,
|
||||
url
|
||||
);
|
||||
console.log(`🆕 Created new supporting file: ${supporting.id}`);
|
||||
}
|
||||
|
||||
uploadedFiles.push(supporting);
|
||||
}
|
||||
|
||||
// 8) Delete any remaining existing files that weren't replaced
|
||||
if (existingSupportingFiles.length > files.length) {
|
||||
const filesToDelete = existingSupportingFiles.slice(files.length);
|
||||
console.log(`🗑️ Deleting ${filesToDelete.length} unused supporting files`);
|
||||
|
||||
for (const fileToDelete of filesToDelete) {
|
||||
await pqqService.deleteSupportingFile(fileToDelete.id);
|
||||
// Also delete from S3
|
||||
const s3Key = getS3KeyFromUrl(fileToDelete.mediaFileName);
|
||||
await deleteFromS3(s3Key);
|
||||
console.log(`🗑️ Deleted supporting file: ${fileToDelete.id}`);
|
||||
addedResults.push(supporting);
|
||||
console.log(`🆕 Created new supporting file record: ${supporting.id}`);
|
||||
} catch (err: any) {
|
||||
console.error('❌ Error uploading/creating supporting file', err);
|
||||
// push failure result but continue processing other files
|
||||
addedResults.push({ success: false, reason: err.message || 'upload/create failed' });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log("📭 No files provided in request");
|
||||
|
||||
// If no files provided but existing files exist, delete them (cleanup)
|
||||
if (existingSupportingFiles.length > 0) {
|
||||
console.log(`🗑️ No new files provided, deleting ${existingSupportingFiles.length} existing files`);
|
||||
for (const fileToDelete of existingSupportingFiles) {
|
||||
await pqqService.deleteSupportingFile(fileToDelete.id);
|
||||
const s3Key = getS3KeyFromUrl(fileToDelete.mediaFileName);
|
||||
await deleteFromS3(s3Key);
|
||||
console.log(`🗑️ Deleted supporting file: ${fileToDelete.id}`);
|
||||
}
|
||||
}
|
||||
console.log('📭 No new files uploaded in request');
|
||||
}
|
||||
|
||||
// 9) Prepare response
|
||||
// NOTE: We DO NOT delete or modify existing supporting files that were not listed in deletedFiles.
|
||||
// This satisfies your Case 2: "if no files are provided, do not touch existing supporting files".
|
||||
|
||||
// 11) Compose response
|
||||
const responseMessage = existingHeader ? "PQQ answer updated successfully" : "PQQ answer submitted successfully";
|
||||
|
||||
return {
|
||||
@@ -284,15 +279,15 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
||||
activityXid,
|
||||
pqqQuestionXid,
|
||||
pqqAnswerXid,
|
||||
comments: comments,
|
||||
comments,
|
||||
files: {
|
||||
uploaded: uploadedFiles,
|
||||
total: uploadedFiles.length
|
||||
added: addedResults,
|
||||
deleted: deletedResults,
|
||||
existingKeptCount: (existingSupportingFiles.length - deletedResults.filter(d => d.success).length)
|
||||
},
|
||||
operation: existingHeader ? 'updated' : 'created',
|
||||
fileOperation: files.length > 0 ?
|
||||
(existingSupportingFiles.length > 0 ? 'replaced' : 'added') :
|
||||
(existingSupportingFiles.length > 0 ? 'removed' : 'unchanged')
|
||||
// summary label for UI convenience:
|
||||
fileOperation: (deletedResults.length > 0 || addedResults.length > 0) ? 'modified' : 'unchanged'
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
||||
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
||||
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
|
||||
@@ -3,7 +3,7 @@ import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { HostService } from '../../../services/host.service';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
||||
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const hostService = new HostService(prismaService);
|
||||
|
||||
@@ -40,15 +40,6 @@ export const handler = safeHandler(async (
|
||||
throw new ApiError(401, 'Invalid credentials');
|
||||
}
|
||||
|
||||
const matchPassword = await bcrypt.compare(
|
||||
userPassword,
|
||||
loginForHost.userPassword
|
||||
);
|
||||
|
||||
if (!matchPassword) {
|
||||
throw new ApiError(401, 'Invalid credentials');
|
||||
}
|
||||
|
||||
const generateTokenForHost = await tokenService.generateAuthToken(
|
||||
loginForHost.id
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { MinglarService } from '../../../../minglaradmin/services/minglar.service';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
||||
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import * as bcrypt from 'bcryptjs';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { ROLE } from '../../../../../common/utils/constants/common.constant';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import * as bcrypt from 'bcryptjs';
|
||||
import { OtpGeneratorSixDigit } from '../../../../../common/utils/helper/OtpGenerator';
|
||||
import { encryptUserId } from '../../../../../common/utils/helper/CodeGenerator';
|
||||
import { OtpGeneratorSixDigit } from '../../../../../common/utils/helper/OtpGenerator';
|
||||
import { HostService } from '../../../services/host.service';
|
||||
import { sendOtpEmailForHost } from '../../../services/sendOTPEmail.service';
|
||||
import { ROLE } from '../../../../../common/utils/constants/common.constant';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const hostService = new HostService(prismaService);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// modules/host/handlers/addCompanyDetails.ts
|
||||
import config from '@/config/config';
|
||||
import config from '../../../../../config/config';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
||||
import AWS from 'aws-sdk';
|
||||
import Busboy from 'busboy';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
||||
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import {
|
||||
@@ -50,6 +50,25 @@ function cleanEmptyStrings(obj: any) {
|
||||
return cleaned;
|
||||
}
|
||||
|
||||
function getS3KeyFromUrl(url: string): string {
|
||||
const base = `https://${config.aws.bucketName}.s3.${config.aws.region}.amazonaws.com/`;
|
||||
return url.replace(base, "");
|
||||
}
|
||||
|
||||
async function deleteFromS3(key: string) {
|
||||
try {
|
||||
await s3.deleteObject({
|
||||
Bucket: config.aws.bucketName,
|
||||
Key: key
|
||||
}).promise();
|
||||
|
||||
console.log("✅ Deleted from S3:", key);
|
||||
} catch (err) {
|
||||
console.error("❌ Failed to delete from S3:", key, err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
|
||||
try {
|
||||
|
||||
@@ -112,6 +131,9 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
||||
bb.end();
|
||||
});
|
||||
|
||||
const deletedFiles = normalizeJsonField(fields, "deletedFiles") || [];
|
||||
const parentDeletedFiles = normalizeJsonField(fields, "parentDeletedFiles") || [];
|
||||
|
||||
/** 4) Extract and clean isDraft flag */
|
||||
const isDraft = fields.isDraft === 'true' || fields.isDraft === true;
|
||||
|
||||
@@ -178,13 +200,8 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
||||
const file = files.find((f) => f.fieldName === doc.fieldName);
|
||||
|
||||
// In DRAFT mode → allow missing documents
|
||||
if (isDraft && !file) {
|
||||
return { ...doc, file: null };
|
||||
}
|
||||
|
||||
// In FINAL mode → file must exist
|
||||
if (!file) {
|
||||
throw new ApiError(400, `File not found for field: ${doc.fieldName}`);
|
||||
return { ...doc, file: null };
|
||||
}
|
||||
|
||||
return { ...doc, file };
|
||||
@@ -213,6 +230,63 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
||||
parsedParentCompany = parsedCompany.parentCompany || null;
|
||||
}
|
||||
|
||||
/** 9.5) DELETE DOCUMENTS IF REQUESTED **/
|
||||
if (Array.isArray(deletedFiles) && deletedFiles.length > 0) {
|
||||
console.log(`🗑️ Deleting ${deletedFiles.length} documents...`);
|
||||
|
||||
for (const del of deletedFiles) {
|
||||
const id = Number(del.id);
|
||||
const url = del.url;
|
||||
|
||||
if (!id || !url) {
|
||||
console.log("❌ Invalid delete entry:", del);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Extract S3 key
|
||||
const s3Key = getS3KeyFromUrl(url);
|
||||
|
||||
// Delete from S3
|
||||
await deleteFromS3(s3Key);
|
||||
|
||||
// Delete from DB
|
||||
await prisma.hostDocuments.delete({
|
||||
where: { id }
|
||||
});
|
||||
|
||||
console.log(`🗑️ Deleted host document ID ${id}`);
|
||||
}
|
||||
}
|
||||
|
||||
/** 9.6) DELETE PARENT DOCUMENTS **/
|
||||
if (parsedCompany.isSubsidairy && Array.isArray(parentDeletedFiles) && parentDeletedFiles.length > 0) {
|
||||
console.log(`🗑️ Deleting ${parentDeletedFiles.length} PARENT documents...`);
|
||||
|
||||
for (const del of parentDeletedFiles) {
|
||||
const id = Number(del.id);
|
||||
const url = del.url;
|
||||
|
||||
if (!id || !url) {
|
||||
console.log("⚠️ Invalid parent delete entry:", del);
|
||||
continue;
|
||||
}
|
||||
|
||||
const s3Key = getS3KeyFromUrl(url);
|
||||
|
||||
// Delete S3
|
||||
await deleteFromS3(s3Key);
|
||||
|
||||
// Delete DB
|
||||
await prisma.hostParenetDocuments.delete({
|
||||
where: { id }
|
||||
});
|
||||
|
||||
console.log(`🗑️ Deleted PARENT document ID ${id}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 11) UPLOAD DOCUMENTS */
|
||||
async function uploadToS3(buffer, mimeType, originalName, folderType, documentTypeXid?, fieldName?) {
|
||||
const ext = originalName.split('.').pop() || 'jpg';
|
||||
@@ -249,7 +323,7 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
||||
/** Upload host docs */
|
||||
const uploadedHostDocs: Array<any> = [];
|
||||
for (const doc of hostDocs) {
|
||||
if (isDraft && !doc.file) continue;
|
||||
if (!doc.file) continue;
|
||||
|
||||
const path = await uploadToS3(
|
||||
doc.file.buffer,
|
||||
@@ -270,7 +344,7 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
||||
/** Upload parent docs */
|
||||
const uploadedParentDocs: Array<any> = [];
|
||||
for (const doc of parentDocs) {
|
||||
if (!doc.file && isDraft) continue; // skip missing files in draft mode
|
||||
if (!doc.file) continue; // skip missing files in draft mode
|
||||
|
||||
const path = await uploadToS3(
|
||||
doc.file.buffer,
|
||||
|
||||
@@ -3,8 +3,8 @@ import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { HostService } from '../../../services/host.service';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
||||
import { hostBankDetailsSchema } from '@/common/utils/validation/host/addPaymentDetails.validation';
|
||||
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||
import { hostBankDetailsSchema } from '../../../../../common/utils/validation/host/addPaymentDetails.validation';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const hostService = new HostService(prismaService);
|
||||
@@ -33,7 +33,7 @@ export const handler = safeHandler(async (
|
||||
}
|
||||
|
||||
// Parse request body
|
||||
let body: { bankXid?: number; bankBranchXid?: number; accountNumber?: string; confirmAccountNumber?: string; accountHolderName?: string; ifscCode?: string; currencyXid?: number };
|
||||
let body: { bankXid?: number; bankBranchXid?: number; accountNumber?: string; confirmAccountNumber?: string; accountHolderName?: string; currencyXid?: number };
|
||||
|
||||
try {
|
||||
body = event.body ? JSON.parse(event.body) : {};
|
||||
@@ -54,7 +54,16 @@ export const handler = safeHandler(async (
|
||||
|
||||
const validatedData = validationResult.data;
|
||||
|
||||
await hostService.addPaymentDetails(validatedData);
|
||||
// Fetch IFSC code from bank branch
|
||||
const bankBranch = await hostService.getBankBranchById(validatedData.bankBranchXid);
|
||||
if (!bankBranch) {
|
||||
throw new ApiError(404, 'Bank branch not found');
|
||||
}
|
||||
|
||||
await hostService.addPaymentDetails({
|
||||
...validatedData,
|
||||
ifscCode: bankBranch.ifscCode,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
|
||||
@@ -26,7 +26,7 @@ export const handler = safeHandler(async (
|
||||
}
|
||||
|
||||
// Fetch user with their HostHeader stepper info
|
||||
const host = await hostService.getHostById(userId);
|
||||
const host = await hostService.getHostIdByUserXid(userId);
|
||||
|
||||
if (!host) {
|
||||
throw new ApiError(404, 'Host record not found');
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { verifyMinglarAdminHostToken } from '@/common/middlewares/jwt/authForMinglarAdmin&Host';
|
||||
import { verifyMinglarAdminHostToken } from '../../../common/middlewares/jwt/authForMinglarAdminHost';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,9 @@
|
||||
import { verifyMinglarAdminToken } from '../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||
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';
|
||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../common/utils/helper/ApiError';
|
||||
import { verifyHostToken } from '../../../common/middlewares/jwt/authForHost';
|
||||
import { verifyMinglarAdminToken } from '@/common/middlewares/jwt/authForMinglarAdmin';
|
||||
import { MinglarService } from '../services/minglar.service';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
|
||||
@@ -3,11 +3,11 @@ import {
|
||||
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';
|
||||
import ApiError from '../../../common/utils/helper/ApiError';
|
||||
import { verifyMinglarAdminToken } from '../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../common/utils/helper/ApiError';
|
||||
import { MinglarService } from '../services/minglar.service';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
|
||||
@@ -3,8 +3,8 @@ import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { verifyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { sendEmailToHostForApprovedApplication } from '../../../services/approvalMailtoHost.service';
|
||||
import { MinglarService } from '../../../services/minglar.service';
|
||||
import { sendEmailToHostForApprovedApplication } from '../../../services/approvalMailtoHost.service'
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { verifyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||
import { MinglarService } from '../../../services/minglar.service';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
|
||||
export const handler = safeHandler(async (
|
||||
event: APIGatewayProxyEvent,
|
||||
context?: Context
|
||||
): Promise<APIGatewayProxyResult> => {
|
||||
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.');
|
||||
|
||||
const userInfo = await verifyMinglarAdminToken(token);
|
||||
|
||||
const activityId = event.pathParameters?.activityId;
|
||||
|
||||
if (!activityId) {
|
||||
throw new ApiError(400, 'activityId is required');
|
||||
}
|
||||
|
||||
await minglarService.acceptPQByAM(
|
||||
Number(activityId),
|
||||
Number(userInfo.id)
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: 201,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: 'Approved PQ successfully',
|
||||
data: null,
|
||||
}),
|
||||
};
|
||||
});
|
||||
@@ -1,10 +1,10 @@
|
||||
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';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { verifyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||
import { HOST_SUGGESTION_TITLES } from '../../../../../common/utils/constants/minglar.constant';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { MinglarService } from '../../../services/minglar.service';
|
||||
// import { HOST_SUGGESTION_TITLES } from '../../../../../common/utils/constants/minglar.constant';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
@@ -67,10 +67,10 @@ export const handler = safeHandler(async (
|
||||
}
|
||||
|
||||
// Validate title is one of the allowed types
|
||||
const allowedTitles = Object.values(HOST_SUGGESTION_TITLES);
|
||||
if (!allowedTitles.includes(title)) {
|
||||
throw new ApiError(400, `Invalid title. Allowed values: ${allowedTitles.join(', ')}`);
|
||||
}
|
||||
// const allowedTitles = Object.values(HOST_SUGGESTION_TITLES);
|
||||
// if (!allowedTitles.includes(title)) {
|
||||
// throw new ApiError(400, `Invalid title. Allowed values: ${allowedTitles.join(', ')}`);
|
||||
// }
|
||||
|
||||
// Add suggestion using service
|
||||
await minglarService.addPqqSuggestion(title, comments, activity_pqq_header_xid,user.id);
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
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';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { verifyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||
import { HOST_SUGGESTION_TITLES } from '../../../../../common/utils/constants/minglar.constant';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { MinglarService } from '../../../services/minglar.service';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
@@ -13,6 +12,7 @@ interface AddSuggestionBody {
|
||||
hostXid: number;
|
||||
title: string;
|
||||
comments: string;
|
||||
isParent: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +52,7 @@ export const handler = safeHandler(async (
|
||||
throw new ApiError(400, 'Invalid JSON in request body');
|
||||
}
|
||||
|
||||
const { hostXid, title, comments } = body;
|
||||
const { hostXid, title, comments, isParent } = body;
|
||||
|
||||
// Validate required fields
|
||||
if (!hostXid) {
|
||||
@@ -68,13 +68,13 @@ export const handler = safeHandler(async (
|
||||
}
|
||||
|
||||
// Validate title is one of the allowed types
|
||||
const allowedTitles = Object.values(HOST_SUGGESTION_TITLES);
|
||||
if (!allowedTitles.includes(title)) {
|
||||
throw new ApiError(400, `Invalid title. Allowed values: ${allowedTitles.join(', ')}`);
|
||||
}
|
||||
// const allowedTitles = Object.values(HOST_SUGGESTION_TITLES);
|
||||
// if (!allowedTitles.includes(title)) {
|
||||
// throw new ApiError(400, `Invalid title. Allowed values: ${allowedTitles.join(', ')}`);
|
||||
// }
|
||||
|
||||
// Add suggestion using service
|
||||
await minglarService.addHostSuggestion(hostXid, title, comments, user.id);
|
||||
await minglarService.addHostSuggestion(hostXid, title, comments, user.id, isParent);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
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';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { verifyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { paginationService } from '../../../../../common/utils/pagination/pagination.service';
|
||||
import { MinglarService } from '../../../services/minglar.service';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
@@ -43,6 +43,7 @@ export const handler = safeHandler(async (
|
||||
// Parse pagination parameters
|
||||
const paginationParams = paginationService.getPaginationFromEvent(event);
|
||||
const paginationOptions = paginationService.parsePaginationParams(paginationParams);
|
||||
const applicationStatus = event.queryStringParameters?.applicationStatus || '';
|
||||
|
||||
// Get paginated host applications
|
||||
const { data, totalCount } = await minglarService.getAllHostApplications(
|
||||
@@ -51,7 +52,8 @@ export const handler = safeHandler(async (
|
||||
search,
|
||||
userStatus,
|
||||
paginationOptions,
|
||||
roleFilter
|
||||
roleFilter,
|
||||
applicationStatus
|
||||
);
|
||||
|
||||
// Create paginated response
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { verifyMinglarAdminHostToken } from '@/common/middlewares/jwt/authForMinglarAdmin&Host';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { verifyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { MinglarService } from '../../../services/minglar.service';
|
||||
import { PrismaService } from '@/common/database/prisma.service';
|
||||
import { safeHandler } from '@/common/utils/handlers/safeHandler';
|
||||
import ApiError from '@/common/utils/helper/ApiError';
|
||||
import { verifyMinglarAdminToken } from '@/common/middlewares/jwt/authForMinglarAdmin';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { verifyMinglarAdminToken } from '@/common/middlewares/jwt/authForMinglarAdmin';
|
||||
import { verifyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { verifyMinglarAdminToken } from '@/common/middlewares/jwt/authForMinglarAdmin';
|
||||
import { MinglarService } from '@/modules/minglaradmin/services/minglar.service';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { verifyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { MinglarService } from '../../../services/minglar.service';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
@@ -17,14 +17,7 @@ export const handler = safeHandler(async (
|
||||
|
||||
const userInfo = await verifyMinglarAdminToken(token);
|
||||
|
||||
let body: any = {};
|
||||
try {
|
||||
body = event.body ? JSON.parse(event.body) : {};
|
||||
} catch (err) {
|
||||
throw new ApiError(400, 'Invalid JSON in request body');
|
||||
}
|
||||
|
||||
const { activityId } = body;
|
||||
const activityId = event.pathParameters?.activityId;
|
||||
|
||||
if (!activityId) {
|
||||
throw new ApiError(400, 'activityId is required');
|
||||
@@ -32,6 +25,7 @@ export const handler = safeHandler(async (
|
||||
|
||||
await minglarService.rejectPQQbyAM(
|
||||
Number(activityId),
|
||||
Number(userInfo.id)
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -42,7 +36,7 @@ export const handler = safeHandler(async (
|
||||
},
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: 'Rejected successfully',
|
||||
message: 'Rejected PQ successfully',
|
||||
data: null,
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
import { verifyOnlyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { sendEmailToHostForMinglarApproval } from '../../../services/approvalMailtoHost.service';
|
||||
import { MinglarService } from '../../../services/minglar.service';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
|
||||
interface AddSuggestionBody {
|
||||
hostXid: number;
|
||||
title: string;
|
||||
comments: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add suggestion handler for host applications
|
||||
* Allows Minglar Admin, Co_Admin, and Account Manager to add suggestions
|
||||
* Types: Setup Profile, Review Account, Add Payment Details, Agreement
|
||||
*/
|
||||
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.');
|
||||
}
|
||||
|
||||
// Verify token and get user info
|
||||
const userInfo = await verifyOnlyMinglarAdminToken(token);
|
||||
|
||||
// Parse request body
|
||||
let body: AddSuggestionBody;
|
||||
|
||||
try {
|
||||
body = event.body ? JSON.parse(event.body) : {};
|
||||
} catch (error) {
|
||||
throw new ApiError(400, 'Invalid JSON in request body');
|
||||
}
|
||||
|
||||
const { hostXid } = body;
|
||||
|
||||
|
||||
// Add suggestion using service
|
||||
await minglarService.acceptHostApplicationMinglarAdmin(hostXid, userInfo.id);
|
||||
const hostDetails = await minglarService.getUserDetails(userInfo.id)
|
||||
if (!hostDetails?.emailAddress) {
|
||||
throw new ApiError(404, 'Host details or email address not found');
|
||||
}
|
||||
await sendEmailToHostForMinglarApproval(hostDetails.emailAddress)
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: 'Application accepted successfully',
|
||||
data: null,
|
||||
}),
|
||||
};
|
||||
});
|
||||
@@ -3,12 +3,11 @@ import {
|
||||
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';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { verifyOnlyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { sendAMEmailForHostAssign } from '../../../services/AMEmail.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { MinglarService } from '../../../services/minglar.service';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { verifyOnlyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
@@ -64,8 +64,9 @@ export const handler = safeHandler(async (
|
||||
payoutDurationFrequency
|
||||
} = body;
|
||||
|
||||
await minglarService.editAgreementDetails(
|
||||
await minglarService.acceptHostApplicationMinglarAdmin(
|
||||
host_xid,
|
||||
userInfo.id,
|
||||
agreementStartDate,
|
||||
duration,
|
||||
isCommisionBase,
|
||||
@@ -73,8 +74,8 @@ export const handler = safeHandler(async (
|
||||
amountPerBooking,
|
||||
durationFrequency,
|
||||
payoutDurationNum,
|
||||
payoutDurationFrequency
|
||||
);
|
||||
payoutDurationFrequency);
|
||||
// await sendEmailToHostForMinglarApproval(hostDetails.emailAddress)
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
@@ -1,10 +1,11 @@
|
||||
import { verifyMinglarAdminToken } from '@/common/middlewares/jwt/authForMinglarAdmin';
|
||||
import { verifyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { PrePopulateService } from '../../../../prepopulate/services/prepopulate.service';
|
||||
import { MinglarService } from '../../../services/minglar.service';
|
||||
import { paginationService } from '../../../../../common/utils/pagination/pagination.service';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
@@ -30,11 +31,18 @@ export const handler = safeHandler(async (
|
||||
|
||||
const hostXid = Number(event.pathParameters?.id)
|
||||
|
||||
// Get pagination params from event
|
||||
const paginationParams = paginationService.getPaginationFromEvent(event);
|
||||
const paginationOptions = paginationService.parsePaginationParams(paginationParams);
|
||||
|
||||
// Read optional search query (supports ?search= or ?q=)
|
||||
const search = event.queryStringParameters?.search || event.queryStringParameters?.q || undefined;
|
||||
|
||||
const data = await minglarService.getAllHostActivityForMinglar(search ? String(search) : undefined, hostXid);
|
||||
const result = await minglarService.getAllHostActivityForMinglar(
|
||||
search ? String(search) : undefined,
|
||||
hostXid,
|
||||
paginationOptions
|
||||
);
|
||||
|
||||
|
||||
return {
|
||||
@@ -46,7 +54,7 @@ export const handler = safeHandler(async (
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: 'Data retrieved successfully',
|
||||
data,
|
||||
...result,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { verifyOnlyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import {
|
||||
APIGatewayProxyEvent,
|
||||
APIGatewayProxyResult,
|
||||
Context,
|
||||
} from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { paginationService } from '../../../../../common/utils/pagination/pagination.service';
|
||||
import { MinglarService } from '../../../services/minglar.service';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
@@ -12,14 +17,19 @@ 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 (
|
||||
export const handler = safeHandler(
|
||||
async (
|
||||
event: APIGatewayProxyEvent,
|
||||
context?: Context
|
||||
context?: Context,
|
||||
): Promise<APIGatewayProxyResult> => {
|
||||
// Verify authentication token
|
||||
const token = event.headers['x-auth-token'] || event.headers['X-Auth-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.');
|
||||
throw new ApiError(
|
||||
401,
|
||||
'This is a protected route. Please provide a valid token.',
|
||||
);
|
||||
}
|
||||
|
||||
// Verify token and get user info
|
||||
@@ -28,15 +38,37 @@ export const handler = safeHandler(async (
|
||||
// Get user details including role
|
||||
const user = await prismaService.user.findUnique({
|
||||
where: { id: userInfo.id },
|
||||
select: { id: true, roleXid: true }
|
||||
select: { id: true, roleXid: true },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new ApiError(404, 'User not found');
|
||||
}
|
||||
|
||||
// Extract optional search query
|
||||
const queryParams = event.queryStringParameters || {};
|
||||
const search =
|
||||
(queryParams.search as string) ||
|
||||
(queryParams.q as string) ||
|
||||
undefined;
|
||||
|
||||
// Pagination
|
||||
const paginationParams = paginationService.getPaginationFromEvent(event);
|
||||
const paginationOptions =
|
||||
paginationService.parsePaginationParams(paginationParams);
|
||||
|
||||
// Get all host applications from service based on user role
|
||||
const hostApplications = await minglarService.getAllOnboardingHostApplications();
|
||||
const { data, totalCount } =
|
||||
await minglarService.getAllOnboardingHostApplications(
|
||||
paginationOptions,
|
||||
search,
|
||||
);
|
||||
|
||||
const paginatedResponse = paginationService.createPaginatedResponse(
|
||||
data,
|
||||
totalCount,
|
||||
paginationOptions,
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
@@ -47,7 +79,8 @@ export const handler = safeHandler(async (
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: 'Host applications retrieved successfully',
|
||||
data: hostApplications,
|
||||
...paginatedResponse,
|
||||
}),
|
||||
};
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,25 +1,35 @@
|
||||
import { verifyOnlyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import {
|
||||
APIGatewayProxyEvent,
|
||||
APIGatewayProxyResult,
|
||||
Context,
|
||||
} from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { verifyOnlyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { paginationService } from '../../../../../common/utils/pagination/pagination.service';
|
||||
import { MinglarService } from '../../../services/minglar.service';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
|
||||
/**
|
||||
* Get all host applications handler
|
||||
* Get all NEW host applications handler
|
||||
* Returns host details with status, submission date, and account manager info
|
||||
*/
|
||||
export const handler = safeHandler(async (
|
||||
export const handler = safeHandler(
|
||||
async (
|
||||
event: APIGatewayProxyEvent,
|
||||
context?: Context
|
||||
context?: Context,
|
||||
): Promise<APIGatewayProxyResult> => {
|
||||
// Verify authentication token
|
||||
const token = event.headers['x-auth-token'] || event.headers['X-Auth-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.');
|
||||
throw new ApiError(
|
||||
401,
|
||||
'This is a protected route. Please provide a valid token.',
|
||||
);
|
||||
}
|
||||
|
||||
// Verify token and get user info
|
||||
@@ -28,15 +38,37 @@ export const handler = safeHandler(async (
|
||||
// Get user details including role
|
||||
const user = await prismaService.user.findUnique({
|
||||
where: { id: userInfo.id },
|
||||
select: { id: true, roleXid: true }
|
||||
select: { id: true, roleXid: true },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new ApiError(404, 'User not found');
|
||||
}
|
||||
|
||||
// Extract optional search query
|
||||
const queryParams = event.queryStringParameters || {};
|
||||
const search =
|
||||
(queryParams.search as string) ||
|
||||
(queryParams.q as string) ||
|
||||
undefined;
|
||||
|
||||
// Pagination
|
||||
const paginationParams = paginationService.getPaginationFromEvent(event);
|
||||
const paginationOptions =
|
||||
paginationService.parsePaginationParams(paginationParams);
|
||||
|
||||
// Get all host applications from service based on user role
|
||||
const hostApplications = await minglarService.getAllOnboardingHostApplications_New();
|
||||
const { data, totalCount } =
|
||||
await minglarService.getAllOnboardingHostApplications_New(
|
||||
paginationOptions,
|
||||
search,
|
||||
);
|
||||
|
||||
const paginatedResponse = paginationService.createPaginatedResponse(
|
||||
data,
|
||||
totalCount,
|
||||
paginationOptions,
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
@@ -47,7 +79,8 @@ export const handler = safeHandler(async (
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: 'Host applications retrieved successfully',
|
||||
data: hostApplications,
|
||||
...paginatedResponse,
|
||||
}),
|
||||
};
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { verifyOnlyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { verifyOnlyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { MinglarService } from '../../../services/minglar.service';
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { MinglarService } from '../../../services/minglar.service';
|
||||
import { verifyMinglarAdminHostToken } from '../../../../../common/middlewares/jwt/authForMinglarAdminHost';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
|
||||
export const handler = safeHandler(async (
|
||||
event: APIGatewayProxyEvent,
|
||||
context?: Context
|
||||
): Promise<APIGatewayProxyResult> => {
|
||||
// Get host ID from path parameters
|
||||
const token = event.headers['x-auth-token'] || event.headers['X-Auth-Token']
|
||||
if (!token) {
|
||||
throw new ApiError(400, 'This is a protected route. Please provide a valid token.');
|
||||
}
|
||||
|
||||
await verifyMinglarAdminHostToken(token);
|
||||
|
||||
const activityXid = event.pathParameters?.activityXid;
|
||||
if (!activityXid) {
|
||||
throw new ApiError(
|
||||
400,
|
||||
'Host ID is required in path parameters.',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const pqpDetails = await minglarService.getAllPQPDetailsForAM(Number(activityXid));
|
||||
|
||||
if (!pqpDetails) {
|
||||
throw new ApiError(404, 'Record not found');
|
||||
}
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: 'PQ details retrieved successfully',
|
||||
data: pqpDetails,
|
||||
}),
|
||||
};
|
||||
});
|
||||
@@ -3,11 +3,11 @@ import {
|
||||
APIGatewayProxyResult,
|
||||
Context,
|
||||
} from 'aws-lambda';
|
||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
||||
import { PrismaService } from '../../../common/database/prisma.service';
|
||||
import ApiError from '../../../common/utils/helper/ApiError';
|
||||
import { ROLE } from '../../../common/utils/constants/common.constant';
|
||||
import { verifyMinglarAdminToken } from '../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||
import { ROLE } from '../../../common/utils/constants/common.constant';
|
||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../common/utils/helper/ApiError';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
export const handler = safeHandler(
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { ROLE, USER_STATUS } from '@/common/utils/constants/common.constant';
|
||||
import { ROLE, USER_STATUS } from '../../../common/utils/constants/common.constant';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../common/utils/helper/ApiError';
|
||||
import { generateOtpHelper } from '../../../common/utils/helper/sendOtp';
|
||||
import { sendOtpEmailForMinglarAdmin } from '../services/sendOTPEmail.service';
|
||||
import { MinglarService } from './../services/minglar.service';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { verifyOnlyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
|
||||
@@ -1,21 +1,31 @@
|
||||
import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { verifyOnlyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import {
|
||||
APIGatewayProxyEvent,
|
||||
APIGatewayProxyResult,
|
||||
Context,
|
||||
} from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { MinglarService } from '../../../services/minglar.service';
|
||||
import { paginationService } from '../../../../../common/utils/pagination/pagination.service';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
|
||||
export const handler = safeHandler(async (
|
||||
export const handler = safeHandler(
|
||||
async (
|
||||
event: APIGatewayProxyEvent,
|
||||
context?: Context
|
||||
context?: Context,
|
||||
): Promise<APIGatewayProxyResult> => {
|
||||
// Extract token from headers
|
||||
const token = event.headers['x-auth-token'] || event.headers['X-Auth-Token']
|
||||
const token =
|
||||
event.headers['x-auth-token'] || event.headers['X-Auth-Token'];
|
||||
if (!token) {
|
||||
throw new ApiError(400, 'This is a protected route. Please provide a valid token.');
|
||||
throw new ApiError(
|
||||
400,
|
||||
'This is a protected route. Please provide a valid token.',
|
||||
);
|
||||
}
|
||||
|
||||
// Authenticate user using the shared authForHost function
|
||||
@@ -24,7 +34,20 @@ export const handler = safeHandler(async (
|
||||
// Extract search parameter from query string
|
||||
const search = event.queryStringParameters?.search || '';
|
||||
|
||||
const result = await minglarService.getAllInvitationDetails(search);
|
||||
const paginationParams = paginationService.getPaginationFromEvent(event);
|
||||
const paginationOptions =
|
||||
paginationService.parsePaginationParams(paginationParams);
|
||||
|
||||
const { data, totalCount } = await minglarService.getAllInvitationDetails(
|
||||
search,
|
||||
paginationOptions,
|
||||
);
|
||||
|
||||
const paginatedResponse = paginationService.createPaginatedResponse(
|
||||
data,
|
||||
totalCount,
|
||||
paginationOptions,
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
@@ -35,8 +58,8 @@ export const handler = safeHandler(async (
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: 'Data retrieved successfully',
|
||||
data: result,
|
||||
...paginatedResponse,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,21 +1,31 @@
|
||||
import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { verifyOnlyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import {
|
||||
APIGatewayProxyEvent,
|
||||
APIGatewayProxyResult,
|
||||
Context,
|
||||
} from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { MinglarService } from '../../../services/minglar.service';
|
||||
import { paginationService } from '../../../../../common/utils/pagination/pagination.service';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
|
||||
export const handler = safeHandler(async (
|
||||
export const handler = safeHandler(
|
||||
async (
|
||||
event: APIGatewayProxyEvent,
|
||||
context?: Context
|
||||
context?: Context,
|
||||
): Promise<APIGatewayProxyResult> => {
|
||||
// Extract token from headers
|
||||
const token = event.headers['x-auth-token'] || event.headers['X-Auth-Token']
|
||||
const token =
|
||||
event.headers['x-auth-token'] || event.headers['X-Auth-Token'];
|
||||
if (!token) {
|
||||
throw new ApiError(400, 'This is a protected route. Please provide a valid token.');
|
||||
throw new ApiError(
|
||||
400,
|
||||
'This is a protected route. Please provide a valid token.',
|
||||
);
|
||||
}
|
||||
|
||||
// Authenticate user using the shared authForHost function
|
||||
@@ -24,7 +34,19 @@ export const handler = safeHandler(async (
|
||||
// Extract search parameter from query string
|
||||
const search = event.queryStringParameters?.search || '';
|
||||
|
||||
const response = await minglarService.getAllInvitedCoadminAndAM(search);
|
||||
// Pagination
|
||||
const paginationParams = paginationService.getPaginationFromEvent(event);
|
||||
const paginationOptions =
|
||||
paginationService.parsePaginationParams(paginationParams);
|
||||
|
||||
const { data, totalCount } =
|
||||
await minglarService.getAllInvitedCoadminAndAM(search, paginationOptions);
|
||||
|
||||
const paginatedResponse = paginationService.createPaginatedResponse(
|
||||
data,
|
||||
totalCount,
|
||||
paginationOptions,
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
@@ -35,8 +57,8 @@ export const handler = safeHandler(async (
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: 'Data retrieved successfully',
|
||||
data: response,
|
||||
...paginatedResponse,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
},
|
||||
);
|
||||
@@ -1,5 +1,4 @@
|
||||
import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { MINGLAR_INVITATION_STATUS } from '@/common/utils/constants/minglar.constant';
|
||||
import { verifyOnlyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { ROLE } from '../../../../../common/utils/constants/common.constant';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// modules/minglar/handlers/updateProfile.ts
|
||||
import config from '@/config/config';
|
||||
import config from '../../../config/config';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import AWS from 'aws-sdk';
|
||||
import { PrismaService } from '../../../common/database/prisma.service';
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,9 @@
|
||||
import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { verifyMinglarAdminHostToken } from '../../../common/middlewares/jwt/authForMinglarAdminHost';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../common/utils/helper/ApiError';
|
||||
import { PrePopulateService } from '../services/prepopulate.service';
|
||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const prePopulateService = new PrePopulateService(prismaService);
|
||||
@@ -20,7 +19,7 @@ export const handler = safeHandler(async (
|
||||
}
|
||||
|
||||
// Authenticate user using the shared authForHost function
|
||||
await verifyHostToken(token);
|
||||
await verifyMinglarAdminHostToken(token);
|
||||
|
||||
const bankDetails = await prePopulateService.getAllBankDetails();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { verifyMinglarAdminHostToken } from '@/common/middlewares/jwt/authForMinglarAdmin&Host';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../common/database/prisma.service';
|
||||
import { verifyMinglarAdminHostToken } from '../../../common/middlewares/jwt/authForMinglarAdminHost';
|
||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../common/utils/helper/ApiError';
|
||||
import { PrePopulateService } from '../services/prepopulate.service';
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../common/database/prisma.service';
|
||||
import { verifyMinglarAdminHostToken } from '../../../common/middlewares/jwt/authForMinglarAdminHost';
|
||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../common/utils/helper/ApiError';
|
||||
import { PrePopulateService } from '../services/prepopulate.service';
|
||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const prePopulateService = new PrePopulateService(prismaService);
|
||||
@@ -20,7 +19,7 @@ export const handler = safeHandler(async (
|
||||
}
|
||||
|
||||
// Authenticate user using the shared authForHost function
|
||||
await verifyHostToken(token);
|
||||
await verifyMinglarAdminHostToken(token);
|
||||
|
||||
const result = await prePopulateService.getAllFrequencies();
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../common/database/prisma.service';
|
||||
import { verifyMinglarAdminHostToken } from '../../../common/middlewares/jwt/authForMinglarAdminHost';
|
||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../common/utils/helper/ApiError';
|
||||
import { PrePopulateService } from '../services/prepopulate.service';
|
||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const prePopulateService = new PrePopulateService(prismaService);
|
||||
@@ -20,7 +19,7 @@ export const handler = safeHandler(async (
|
||||
}
|
||||
|
||||
// Authenticate user using the shared authForHost function
|
||||
await verifyHostToken(token);
|
||||
await verifyMinglarAdminHostToken(token);
|
||||
|
||||
const result = await prePopulateService.getAllPQQQuesAndAns();
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from "aws-lambda";
|
||||
import { PrismaService } from "../../../common/database/prisma.service";
|
||||
import { verifyMinglarAdminHostToken } from "../../../common/middlewares/jwt/authForMinglarAdminHost";
|
||||
import { safeHandler } from "../../../common/utils/handlers/safeHandler";
|
||||
import ApiError from "../../../common/utils/helper/ApiError";
|
||||
import { PrePopulateService } from "../services/prepopulate.service";
|
||||
import { verifyHostToken } from "@/common/middlewares/jwt/authForHost";
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const prePopulateService = new PrePopulateService(prismaService);
|
||||
@@ -26,7 +26,7 @@ export const handler = safeHandler(async (
|
||||
}
|
||||
|
||||
// 2) Authenticate user
|
||||
await verifyHostToken(token);
|
||||
await verifyMinglarAdminHostToken(token);
|
||||
|
||||
// 3) Get bankXid from query params
|
||||
const bankXid = Number(event.queryStringParameters?.bankXid);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from "aws-lambda";
|
||||
import { PrismaService } from "../../../common/database/prisma.service";
|
||||
import { verifyMinglarAdminHostToken } from "../../../common/middlewares/jwt/authForMinglarAdminHost";
|
||||
import { safeHandler } from "../../../common/utils/handlers/safeHandler";
|
||||
import ApiError from "../../../common/utils/helper/ApiError";
|
||||
import { PrePopulateService } from "../services/prepopulate.service";
|
||||
import { verifyHostToken } from "@/common/middlewares/jwt/authForHost";
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const prePopulateService = new PrePopulateService(prismaService);
|
||||
@@ -26,7 +26,7 @@ export const handler = safeHandler(async (
|
||||
}
|
||||
|
||||
// 2) Authenticate user
|
||||
await verifyHostToken(token);
|
||||
await verifyMinglarAdminHostToken(token);
|
||||
|
||||
// 3) Get bankXid from query params
|
||||
const stateXid = Number(event.queryStringParameters?.stateXid);
|
||||
|
||||
@@ -11,15 +11,11 @@ export class PrePopulateService {
|
||||
isActive: true,
|
||||
deletedAt: null,
|
||||
},
|
||||
include: {
|
||||
BankBranches: {
|
||||
select: {
|
||||
id: true,
|
||||
branchAddress: true,
|
||||
ifscCode: true,
|
||||
},
|
||||
},
|
||||
bankName: true,
|
||||
},
|
||||
orderBy: { bankName: 'asc' }
|
||||
});
|
||||
}
|
||||
|
||||
@@ -28,7 +24,6 @@ export class PrePopulateService {
|
||||
where: {
|
||||
bankXid,
|
||||
isActive: true,
|
||||
deletedAt: null
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
@@ -60,37 +55,60 @@ export class PrePopulateService {
|
||||
isActive: true,
|
||||
deletedAt: null,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
currencyName: true,
|
||||
currencySymbol: true,
|
||||
},
|
||||
orderBy: { currencyName: 'asc' }
|
||||
});
|
||||
}
|
||||
|
||||
async getAllPQQQuesAndAns() {
|
||||
return await this.prisma.pQQCategories.findMany({
|
||||
where: { isActive: true },
|
||||
include: {
|
||||
select: {
|
||||
id: true,
|
||||
categoryName: true,
|
||||
displayOrder: true,
|
||||
pqqsubCategories: {
|
||||
include: {
|
||||
where: { isActive: true },
|
||||
select: {
|
||||
id: true,
|
||||
subCategoryName: true,
|
||||
categoryXid: true,
|
||||
displayOrder: true,
|
||||
questions: {
|
||||
include: {
|
||||
where: { isActive: true },
|
||||
select: {
|
||||
id: true,
|
||||
questionName: true,
|
||||
maxPoints: true,
|
||||
displayOrder: true,
|
||||
PQQAnswers: {
|
||||
orderBy: {
|
||||
displayOrder: 'asc'
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: {
|
||||
displayOrder: 'asc'
|
||||
where: { isActive: true },
|
||||
orderBy: { displayOrder: 'asc' },
|
||||
select: {
|
||||
id: true,
|
||||
answerName: true,
|
||||
answerPoints: true,
|
||||
displayOrder: true
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: { displayOrder: 'asc' }
|
||||
}
|
||||
},
|
||||
orderBy: { displayOrder: 'asc' }
|
||||
},
|
||||
orderBy: { displayOrder: 'asc' },
|
||||
},
|
||||
},
|
||||
orderBy: { displayOrder: 'asc' },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async getAllDocumentTypeWithCountryStateCity() {
|
||||
const [documentDetails, countryDetails, stateDetails] =
|
||||
const [documentDetails, countryDetails, stateDetails, companyTypeDetails] =
|
||||
await this.prisma.$transaction([
|
||||
this.prisma.documentType.findMany({
|
||||
where: { isActive: true, isVisible: true },
|
||||
@@ -101,10 +119,15 @@ export class PrePopulateService {
|
||||
}),
|
||||
this.prisma.states.findMany({
|
||||
where: { isActive: true },
|
||||
orderBy: { stateName: 'asc' }
|
||||
}),
|
||||
this.prisma.companyTypes.findMany({
|
||||
where: { isActive: true },
|
||||
orderBy: { companyTypeName: 'asc' }
|
||||
}),
|
||||
]);
|
||||
|
||||
return { documentDetails, countryDetails, stateDetails };
|
||||
return { documentDetails, countryDetails, stateDetails, companyTypeDetails };
|
||||
}
|
||||
|
||||
async getAllFrequencies() {
|
||||
|
||||
Reference in New Issue
Block a user