Compare commits
113 Commits
validation
...
swagger
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3937be710b | ||
| cab4408dc8 | |||
| be65a6c021 | |||
|
|
f13e90ce39 | ||
|
|
5a223f126f | ||
|
|
2e4f318684 | ||
|
|
53785bd5f2 | ||
| c9b507f969 | |||
| 91871d1f44 | |||
| 05e48063c9 | |||
| a906dc5635 | |||
| 8ec8cf4854 | |||
| fab7642302 | |||
| 4d3796c5f3 | |||
| 2f3c531c56 | |||
| a2907929d4 | |||
|
|
ef2b23ef83 | ||
| 2767d29d79 | |||
| 46daec00ce | |||
| 43e494780d | |||
| 0da18b18f7 | |||
| b5304b3c26 | |||
| 82340c2918 | |||
|
|
31c312eb3c | ||
| b8f5f92c98 | |||
| 3652d851f7 | |||
|
|
6166075967 | ||
|
|
b6cb5831c2 | ||
|
|
a39cc1c3c8 | ||
|
|
ae76618f7a | ||
| e957fc5c50 | |||
|
|
856db687c3 | ||
| a020a28993 | |||
|
|
f6e01ac9e3 | ||
| 1a520ae9e1 | |||
| d5d6951e64 | |||
| bbd55562af | |||
|
|
76970c914e | ||
| 9abadba8f5 | |||
| 747566497c | |||
| 6c3e5ccd60 | |||
| ca9ba601ad | |||
| eab6565e12 | |||
|
|
61737235a4 | ||
| 6a84876518 | |||
| d8fb4b242d | |||
|
|
844bbf9618 | ||
| 51b053310f | |||
|
|
cdae23ec6c | ||
| 06010ef6e8 | |||
| 7b9763c668 | |||
| 4c1a04d043 | |||
|
|
ecf45c3e7c | ||
|
|
20a931ab27 | ||
| 6a84fbc0c3 | |||
| 9fc8336bd9 | |||
| b049146664 | |||
| 963f84681c | |||
| 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 |
44
.env.example
Normal file
44
.env.example
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# Environment Configuration Template
|
||||||
|
# Copy this file to .env.dev, .env.test, or .env.uat and fill in the values
|
||||||
|
|
||||||
|
# Database
|
||||||
|
DATABASE_URL=
|
||||||
|
DB_USERNAME=
|
||||||
|
DB_PASSWORD=
|
||||||
|
DB_DATABASE_NAME=
|
||||||
|
DB_HOSTNAME=
|
||||||
|
DB_PORT=5432
|
||||||
|
|
||||||
|
# Email Bypass (set to true for dev/test, false for production-like environments)
|
||||||
|
BY_PASS_EMAIL=
|
||||||
|
BYPASS_OTP=
|
||||||
|
|
||||||
|
# Brevo Email Configuration
|
||||||
|
BREVO_EMAIL_API_KEY=
|
||||||
|
BREVO_API_BASEURL=https://api.brevo.com
|
||||||
|
BREVO_FROM_EMAIL=
|
||||||
|
BREVO_SMTP_HOST=smtp-relay.brevo.com
|
||||||
|
BREVO_SMTP_PORT=587
|
||||||
|
BREVO_SMTP_USER=
|
||||||
|
BREVO_SMTP_PASS=
|
||||||
|
|
||||||
|
# JWT Configuration
|
||||||
|
REFRESH_TOKEN_SECRET=
|
||||||
|
JWT_SECRET=
|
||||||
|
JWT_ACCESS_EXPIRATION_MINUTES=30
|
||||||
|
JWT_REFRESH_EXPIRATION_DAYS=7
|
||||||
|
JWT_RESET_PASSWORD_EXPIRATION_MINUTES=15
|
||||||
|
JWT_VERIFY_EMAIL_EXPIRATION_MINUTES=15
|
||||||
|
|
||||||
|
# Security
|
||||||
|
SALT_ROUNDS=
|
||||||
|
NODE_ENV=
|
||||||
|
|
||||||
|
# AWS S3
|
||||||
|
S3_BUCKET_NAME=
|
||||||
|
|
||||||
|
# Admin Configuration
|
||||||
|
MINGLAR_ADMIN_NAME=
|
||||||
|
MINGLAR_ADMIN_EMAIL=
|
||||||
|
AM_INVITATION_LINK=
|
||||||
|
HOST_LINK=
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -40,10 +40,14 @@ lerna-debug.log*
|
|||||||
.env.test.local
|
.env.test.local
|
||||||
.env.production.local
|
.env.production.local
|
||||||
.env.local
|
.env.local
|
||||||
|
.env.dev
|
||||||
|
.env.test
|
||||||
|
.env.uat
|
||||||
|
|
||||||
# temp
|
# temp
|
||||||
.tmp
|
.tmp
|
||||||
.temp
|
.temp
|
||||||
|
undefined/
|
||||||
|
|
||||||
# Runtime data
|
# Runtime data
|
||||||
pids
|
pids
|
||||||
|
|||||||
490
LAMBDA_OPTIMIZATION_GUIDE.md
Normal file
490
LAMBDA_OPTIMIZATION_GUIDE.md
Normal file
@@ -0,0 +1,490 @@
|
|||||||
|
# AWS Lambda Bundle Size Optimization Guide
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This guide documents how to optimize AWS Lambda function bundle sizes when using:
|
||||||
|
- **Serverless Framework v4** (with built-in esbuild)
|
||||||
|
- **Prisma ORM** (with driver adapters)
|
||||||
|
- **NestJS** or any Node.js framework
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
Lambda functions can become bloated (25+ MB) due to:
|
||||||
|
1. **Prisma binary engines** (~50MB uncompressed)
|
||||||
|
2. **AWS SDK v3** being bundled (~5-10MB)
|
||||||
|
3. **Dependencies copied to node_modules** instead of being bundled
|
||||||
|
|
||||||
|
## Solution Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ Lambda Function │
|
||||||
|
│ ┌─────────────────────────────────────────────────┐ │
|
||||||
|
│ │ Your Code (bundled by esbuild) ~50-500 KB │ │
|
||||||
|
│ └─────────────────────────────────────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ▼ │
|
||||||
|
│ ┌─────────────────────────────────────────────────┐ │
|
||||||
|
│ │ Prisma Layer (shared) ~15 MB │ │
|
||||||
|
│ │ - @prisma/client │ │
|
||||||
|
│ │ - @prisma/adapter-pg │ │
|
||||||
|
│ │ - .prisma/client (generated) │ │
|
||||||
|
│ │ - pg driver │ │
|
||||||
|
│ └─────────────────────────────────────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ▼ │
|
||||||
|
│ ┌─────────────────────────────────────────────────┐ │
|
||||||
|
│ │ AWS Lambda Runtime │ │
|
||||||
|
│ │ - AWS SDK v3 (built-in for Node.js 18+) │ │
|
||||||
|
│ └─────────────────────────────────────────────────┘ │
|
||||||
|
└─────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step-by-Step Setup
|
||||||
|
|
||||||
|
### 1. Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
your-project/
|
||||||
|
├── serverless.yml
|
||||||
|
├── package.json
|
||||||
|
├── prisma/
|
||||||
|
│ └── schema.prisma
|
||||||
|
├── layers/
|
||||||
|
│ └── prisma/
|
||||||
|
│ └── nodejs/
|
||||||
|
│ └── package.json
|
||||||
|
├── src/
|
||||||
|
│ └── ... your code
|
||||||
|
└── build-prisma-layer.ps1 (or .sh for Linux/Mac)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Prisma Schema Configuration
|
||||||
|
|
||||||
|
**`prisma/schema.prisma`**
|
||||||
|
```prisma
|
||||||
|
generator client {
|
||||||
|
provider = "prisma-client-js"
|
||||||
|
// For Prisma 7+ with driver adapters, no binary targets needed
|
||||||
|
// The WASM-based query engine is used automatically
|
||||||
|
}
|
||||||
|
|
||||||
|
datasource db {
|
||||||
|
provider = "postgresql"
|
||||||
|
url = env("DATABASE_URL")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note**: Prisma 7+ uses WASM-based query compiler instead of binary engines when using driver adapters, which is much smaller.
|
||||||
|
|
||||||
|
### 3. Layer Package.json
|
||||||
|
|
||||||
|
**`layers/prisma/nodejs/package.json`**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "prisma-layer",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Lambda layer for Prisma with pg driver adapter",
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/client": "^7.0.0",
|
||||||
|
"@prisma/adapter-pg": "^7.0.0",
|
||||||
|
"pg": "^8.13.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Serverless Configuration
|
||||||
|
|
||||||
|
**`serverless.yml`**
|
||||||
|
```yaml
|
||||||
|
service: your-service-name
|
||||||
|
|
||||||
|
provider:
|
||||||
|
name: aws
|
||||||
|
runtime: nodejs22.x
|
||||||
|
region: your-region
|
||||||
|
memorySize: 512
|
||||||
|
# Apply Prisma layer to ALL functions
|
||||||
|
layers:
|
||||||
|
- !Ref PrismaLambdaLayer
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: ${env:DATABASE_URL}
|
||||||
|
# ... other env vars
|
||||||
|
|
||||||
|
# esbuild configuration (Serverless v4 built-in)
|
||||||
|
build:
|
||||||
|
esbuild:
|
||||||
|
bundle: true
|
||||||
|
minify: true
|
||||||
|
sourcemap: false
|
||||||
|
target: node20
|
||||||
|
platform: node
|
||||||
|
# Mark packages as external (not bundled into JS)
|
||||||
|
external:
|
||||||
|
- '@prisma/client'
|
||||||
|
- '@prisma/adapter-pg'
|
||||||
|
- '.prisma/client'
|
||||||
|
- '.prisma'
|
||||||
|
- 'pg'
|
||||||
|
- '@aws-sdk/*'
|
||||||
|
- '@smithy/*'
|
||||||
|
- '@aws-crypto/*'
|
||||||
|
# Exclude from npm install in zip (CRITICAL!)
|
||||||
|
exclude:
|
||||||
|
- 'aws-sdk'
|
||||||
|
- '@aws-sdk/*'
|
||||||
|
- '@smithy/*'
|
||||||
|
- '@aws-crypto/*'
|
||||||
|
- '@prisma/client'
|
||||||
|
- '@prisma/adapter-pg'
|
||||||
|
- '.prisma'
|
||||||
|
- '.prisma/client'
|
||||||
|
- 'pg'
|
||||||
|
- 'pg-*'
|
||||||
|
- 'postgres-*'
|
||||||
|
- 'pgpass'
|
||||||
|
- 'split2'
|
||||||
|
- 'xtend'
|
||||||
|
|
||||||
|
# Define the Prisma layer
|
||||||
|
layers:
|
||||||
|
prisma:
|
||||||
|
path: layers/prisma
|
||||||
|
name: ${self:service}-prisma-layer-${sls:stage}
|
||||||
|
description: Prisma client with pg driver adapter
|
||||||
|
compatibleRuntimes:
|
||||||
|
- nodejs22.x
|
||||||
|
retain: false
|
||||||
|
|
||||||
|
# Package configuration
|
||||||
|
package:
|
||||||
|
individually: true
|
||||||
|
patterns:
|
||||||
|
- '!node_modules/**'
|
||||||
|
- '!node_modules/@prisma/**'
|
||||||
|
- '!node_modules/.prisma/**'
|
||||||
|
- '!**/*.test.js'
|
||||||
|
- '!**/*.spec.js'
|
||||||
|
- '!**/test/**'
|
||||||
|
- '!**/__tests__/**'
|
||||||
|
- '!package-lock.json'
|
||||||
|
- '!yarn.lock'
|
||||||
|
- '!README.md'
|
||||||
|
- '!.git/**'
|
||||||
|
|
||||||
|
functions:
|
||||||
|
myFunction:
|
||||||
|
handler: src/handlers/myHandler.handler
|
||||||
|
events:
|
||||||
|
- httpApi:
|
||||||
|
path: /my-endpoint
|
||||||
|
method: get
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- serverless-offline
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Build Script for Prisma Layer
|
||||||
|
|
||||||
|
**Windows (PowerShell) - `build-prisma-layer.ps1`**
|
||||||
|
```powershell
|
||||||
|
# Build Prisma Lambda Layer
|
||||||
|
$layerPath = "layers\prisma\nodejs"
|
||||||
|
|
||||||
|
Write-Host "Building Prisma Lambda Layer..." -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# 1. Clean existing node_modules in layer
|
||||||
|
Write-Host "Cleaning layer node_modules..."
|
||||||
|
if (Test-Path "$layerPath\node_modules") {
|
||||||
|
Remove-Item -Recurse -Force "$layerPath\node_modules"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 2. Install dependencies in layer
|
||||||
|
Write-Host "Installing layer dependencies..."
|
||||||
|
Push-Location $layerPath
|
||||||
|
npm install --omit=dev
|
||||||
|
Pop-Location
|
||||||
|
|
||||||
|
# 3. Generate Prisma client
|
||||||
|
Write-Host "Generating Prisma client..."
|
||||||
|
npx prisma generate
|
||||||
|
|
||||||
|
# 4. Copy .prisma/client to layer
|
||||||
|
Write-Host "Copying generated Prisma client to layer..."
|
||||||
|
$sourcePrisma = "node_modules\.prisma"
|
||||||
|
$destPrisma = "$layerPath\node_modules\.prisma"
|
||||||
|
|
||||||
|
if (Test-Path $sourcePrisma) {
|
||||||
|
if (Test-Path $destPrisma) {
|
||||||
|
Remove-Item -Recurse -Force $destPrisma
|
||||||
|
}
|
||||||
|
Copy-Item -Recurse $sourcePrisma $destPrisma
|
||||||
|
Write-Host "Copied .prisma/client successfully!" -ForegroundColor Green
|
||||||
|
} else {
|
||||||
|
Write-Host "ERROR: .prisma folder not found. Run 'npx prisma generate' first." -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# 5. Show layer size
|
||||||
|
$layerSize = (Get-ChildItem "$layerPath\node_modules" -Recurse | Measure-Object -Property Length -Sum).Sum / 1MB
|
||||||
|
Write-Host "`nTotal layer size: $([math]::Round($layerSize, 2)) MB" -ForegroundColor Yellow
|
||||||
|
Write-Host "Prisma layer built successfully!" -ForegroundColor Green
|
||||||
|
```
|
||||||
|
|
||||||
|
**Linux/Mac (Bash) - `build-prisma-layer.sh`**
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
LAYER_PATH="layers/prisma/nodejs"
|
||||||
|
|
||||||
|
echo "Building Prisma Lambda Layer..."
|
||||||
|
|
||||||
|
# 1. Clean existing node_modules in layer
|
||||||
|
echo "Cleaning layer node_modules..."
|
||||||
|
rm -rf "$LAYER_PATH/node_modules"
|
||||||
|
|
||||||
|
# 2. Install dependencies in layer
|
||||||
|
echo "Installing layer dependencies..."
|
||||||
|
cd "$LAYER_PATH"
|
||||||
|
npm install --omit=dev
|
||||||
|
cd -
|
||||||
|
|
||||||
|
# 3. Generate Prisma client
|
||||||
|
echo "Generating Prisma client..."
|
||||||
|
npx prisma generate
|
||||||
|
|
||||||
|
# 4. Copy .prisma/client to layer
|
||||||
|
echo "Copying generated Prisma client to layer..."
|
||||||
|
if [ -d "node_modules/.prisma" ]; then
|
||||||
|
rm -rf "$LAYER_PATH/node_modules/.prisma"
|
||||||
|
cp -r "node_modules/.prisma" "$LAYER_PATH/node_modules/.prisma"
|
||||||
|
echo "Copied .prisma/client successfully!"
|
||||||
|
else
|
||||||
|
echo "ERROR: .prisma folder not found. Run 'npx prisma generate' first."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 5. Show layer size
|
||||||
|
LAYER_SIZE=$(du -sm "$LAYER_PATH/node_modules" | cut -f1)
|
||||||
|
echo "Total layer size: ${LAYER_SIZE} MB"
|
||||||
|
echo "Prisma layer built successfully!"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Prisma Client Usage
|
||||||
|
|
||||||
|
**`src/common/database/prisma.client.ts`**
|
||||||
|
```typescript
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
import { PrismaPg } from '@prisma/adapter-pg';
|
||||||
|
import { Pool } from 'pg';
|
||||||
|
|
||||||
|
// Connection pool for serverless
|
||||||
|
const pool = new Pool({
|
||||||
|
connectionString: process.env.DATABASE_URL,
|
||||||
|
max: 5, // Limit connections in Lambda
|
||||||
|
});
|
||||||
|
|
||||||
|
const adapter = new PrismaPg(pool);
|
||||||
|
|
||||||
|
// Single instance for Lambda warm starts
|
||||||
|
let prisma: PrismaClient;
|
||||||
|
|
||||||
|
export function getPrismaClient(): PrismaClient {
|
||||||
|
if (!prisma) {
|
||||||
|
prisma = new PrismaClient({
|
||||||
|
adapter,
|
||||||
|
log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return prisma;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { prisma };
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Deployment Workflow
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Build the Prisma layer (run after schema changes)
|
||||||
|
./build-prisma-layer.ps1 # Windows
|
||||||
|
# or
|
||||||
|
./build-prisma-layer.sh # Linux/Mac
|
||||||
|
|
||||||
|
# 2. Deploy
|
||||||
|
npx serverless deploy --stage=dev
|
||||||
|
|
||||||
|
# 3. Deploy single function (faster, uses existing layer)
|
||||||
|
npx serverless deploy function -f myFunction --stage=dev
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Configuration Explained
|
||||||
|
|
||||||
|
### esbuild `external` vs `exclude`
|
||||||
|
|
||||||
|
| Property | Purpose |
|
||||||
|
|----------|---------|
|
||||||
|
| `external` | Tells esbuild NOT to bundle these into the JS file. They become `require()` calls. |
|
||||||
|
| `exclude` | Tells Serverless NOT to `npm install` these packages into the function zip. |
|
||||||
|
|
||||||
|
**Both are required!**
|
||||||
|
- `external` alone = esbuild doesn't bundle, but Serverless still installs to node_modules
|
||||||
|
- `exclude` alone = Serverless doesn't install, but esbuild bundles the code
|
||||||
|
|
||||||
|
### Layer Reference
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# This creates a CloudFormation reference to the layer defined in the same stack
|
||||||
|
layers:
|
||||||
|
- !Ref PrismaLambdaLayer
|
||||||
|
```
|
||||||
|
|
||||||
|
The `PrismaLambdaLayer` name comes from the layer key (`prisma`) converted to PascalCase + `LambdaLayer`.
|
||||||
|
|
||||||
|
### Why Exclude pg-* packages?
|
||||||
|
|
||||||
|
When `pg` is external, its dependencies still get installed:
|
||||||
|
- `pg-connection-string`
|
||||||
|
- `pg-pool`
|
||||||
|
- `pg-protocol`
|
||||||
|
- `pg-types`
|
||||||
|
- etc.
|
||||||
|
|
||||||
|
These must all be in the `exclude` list to prevent duplication.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Expected Results
|
||||||
|
|
||||||
|
| Function Type | Before | After |
|
||||||
|
|---------------|--------|-------|
|
||||||
|
| Simple handlers | 25+ MB | **50-100 kB** |
|
||||||
|
| With validation (zod/yup) | 25+ MB | **300-500 kB** |
|
||||||
|
| With S3 uploads | 30+ MB | **1-2 MB** |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### 1. "Cannot find module '@prisma/client'"
|
||||||
|
|
||||||
|
**Cause**: Layer doesn't have the generated `.prisma/client`
|
||||||
|
|
||||||
|
**Fix**: Run `build-prisma-layer.ps1` to regenerate the layer
|
||||||
|
|
||||||
|
### 2. Function size still large
|
||||||
|
|
||||||
|
**Debug**: Extract and inspect the zip:
|
||||||
|
```powershell
|
||||||
|
Expand-Archive ".serverless\build\your-function.zip" -DestinationPath "extracted"
|
||||||
|
Get-ChildItem "extracted\node_modules" -Directory
|
||||||
|
```
|
||||||
|
|
||||||
|
If you see `@prisma` or `pg` folders, the `exclude` config isn't working.
|
||||||
|
|
||||||
|
### 3. "Cannot resolve CloudFormation reference"
|
||||||
|
|
||||||
|
**Cause**: Using `${cf:...}` reference before first deploy
|
||||||
|
|
||||||
|
**Fix**: Use `!Ref PrismaLambdaLayer` instead (works on first deploy)
|
||||||
|
|
||||||
|
### 4. Cold starts still slow
|
||||||
|
|
||||||
|
Consider:
|
||||||
|
- **Provisioned Concurrency**: Pre-warm instances
|
||||||
|
- **Reduce memory**: Sometimes lower memory = same speed, lower cost
|
||||||
|
- **Connection pooling**: Use tools like PgBouncer for RDS
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Additional Optimizations
|
||||||
|
|
||||||
|
### 1. Remove duplicate validation libraries
|
||||||
|
|
||||||
|
Pick ONE of: `zod`, `yup`, or `class-validator`. Don't use all three.
|
||||||
|
|
||||||
|
### 2. Tree-shake NestJS
|
||||||
|
|
||||||
|
If not using full NestJS, import only what you need:
|
||||||
|
```typescript
|
||||||
|
// Instead of
|
||||||
|
import { Controller, Get } from '@nestjs/common';
|
||||||
|
|
||||||
|
// For Lambda handlers, you might not need NestJS at all
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Use AWS SDK v3 selectively
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
external:
|
||||||
|
- '@aws-sdk/*' # Exclude all
|
||||||
|
```
|
||||||
|
|
||||||
|
Then in code:
|
||||||
|
```typescript
|
||||||
|
// AWS SDK v3 is available in Lambda runtime (Node.js 18+)
|
||||||
|
import { S3Client } from '@aws-sdk/client-s3';
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Minimal serverless.yml for Prisma + Lambda optimization
|
||||||
|
build:
|
||||||
|
esbuild:
|
||||||
|
bundle: true
|
||||||
|
minify: true
|
||||||
|
external:
|
||||||
|
- '@prisma/client'
|
||||||
|
- '@prisma/adapter-pg'
|
||||||
|
- '.prisma/client'
|
||||||
|
- '.prisma'
|
||||||
|
- 'pg'
|
||||||
|
- '@aws-sdk/*'
|
||||||
|
exclude:
|
||||||
|
- '@prisma/client'
|
||||||
|
- '@prisma/adapter-pg'
|
||||||
|
- '.prisma'
|
||||||
|
- '.prisma/client'
|
||||||
|
- 'pg'
|
||||||
|
- 'pg-*'
|
||||||
|
- 'postgres-*'
|
||||||
|
- 'pgpass'
|
||||||
|
- 'split2'
|
||||||
|
- 'xtend'
|
||||||
|
- '@aws-sdk/*'
|
||||||
|
|
||||||
|
layers:
|
||||||
|
prisma:
|
||||||
|
path: layers/prisma
|
||||||
|
name: ${self:service}-prisma-${sls:stage}
|
||||||
|
compatibleRuntimes:
|
||||||
|
- nodejs22.x
|
||||||
|
|
||||||
|
provider:
|
||||||
|
layers:
|
||||||
|
- !Ref PrismaLambdaLayer
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Version Compatibility
|
||||||
|
|
||||||
|
| Tool | Tested Version |
|
||||||
|
|------|----------------|
|
||||||
|
| Serverless Framework | v4.x |
|
||||||
|
| Prisma | v7.x |
|
||||||
|
| Node.js | 20.x, 22.x |
|
||||||
|
| AWS Lambda Runtime | nodejs20.x, nodejs22.x |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Last updated: December 2025*
|
||||||
51
build-prisma-layer.ps1
Normal file
51
build-prisma-layer.ps1
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
# Build Prisma Lambda Layer
|
||||||
|
# Run this script before deploying to ensure the layer has the generated client
|
||||||
|
|
||||||
|
$layerPath = "layers\prisma\nodejs"
|
||||||
|
|
||||||
|
Write-Host "Building Prisma Lambda Layer..." -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# 1. Clean existing node_modules in layer
|
||||||
|
Write-Host "Cleaning layer node_modules..."
|
||||||
|
if (Test-Path "$layerPath\node_modules") {
|
||||||
|
Remove-Item -Recurse -Force "$layerPath\node_modules"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 2. Install dependencies in layer
|
||||||
|
Write-Host "Installing layer dependencies..."
|
||||||
|
Push-Location $layerPath
|
||||||
|
npm install --omit=dev
|
||||||
|
Pop-Location
|
||||||
|
|
||||||
|
# 3. Generate Prisma client into the layer
|
||||||
|
Write-Host "Generating Prisma client into layer..."
|
||||||
|
# Set the output directory for Prisma client
|
||||||
|
$env:PRISMA_GENERATE_DATAPROXY = "false"
|
||||||
|
|
||||||
|
# Generate client - this creates .prisma/client
|
||||||
|
npx prisma generate
|
||||||
|
|
||||||
|
# 4. Copy .prisma/client to layer
|
||||||
|
Write-Host "Copying generated Prisma client to layer..."
|
||||||
|
$sourcePrisma = "node_modules\.prisma"
|
||||||
|
$destPrisma = "$layerPath\node_modules\.prisma"
|
||||||
|
|
||||||
|
if (Test-Path $sourcePrisma) {
|
||||||
|
if (Test-Path $destPrisma) {
|
||||||
|
Remove-Item -Recurse -Force $destPrisma
|
||||||
|
}
|
||||||
|
Copy-Item -Recurse $sourcePrisma $destPrisma
|
||||||
|
Write-Host "Copied .prisma/client successfully!" -ForegroundColor Green
|
||||||
|
} else {
|
||||||
|
Write-Host "ERROR: .prisma folder not found. Run 'npx prisma generate' first." -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# 5. Show layer size
|
||||||
|
Write-Host "`nLayer contents:"
|
||||||
|
Get-ChildItem "$layerPath\node_modules" -Directory | Select-Object Name
|
||||||
|
$layerSize = (Get-ChildItem "$layerPath\node_modules" -Recurse | Measure-Object -Property Length -Sum).Sum / 1MB
|
||||||
|
Write-Host "`nTotal layer size: $([math]::Round($layerSize, 2)) MB" -ForegroundColor Yellow
|
||||||
|
|
||||||
|
Write-Host "`nPrisma layer built successfully!" -ForegroundColor Green
|
||||||
|
Write-Host "Run 'serverless deploy' to deploy with the updated layer."
|
||||||
238
layers/prisma/nodejs/package-lock.json
generated
Normal file
238
layers/prisma/nodejs/package-lock.json
generated
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
{
|
||||||
|
"name": "prisma-layer",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "prisma-layer",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/adapter-pg": "^7.0.1",
|
||||||
|
"@prisma/client": "^7.0.1",
|
||||||
|
"pg": "^8.13.0",
|
||||||
|
"zod": "^4.1.12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@prisma/adapter-pg": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/adapter-pg/-/adapter-pg-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-01GpPPhLMoDMF4ipgfZz0L87fla/TV/PBQcmHy+9vV1ml6gUoqF8dUIRNI5Yf2YKpOwzQg9sn8C7dYD1Yio9Ug==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/driver-adapter-utils": "7.0.1",
|
||||||
|
"pg": "^8.16.3",
|
||||||
|
"postgres-array": "3.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@prisma/client": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-O74T6xcfaGAq5gXwCAvfTLvI6fmC3and2g5yLRMkNjri1K8mSpEgclDNuUWs9xj5AwNEMQ88NeD3asI+sovm1g==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/client-runtime-utils": "7.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19 || ^22.12 || >=24.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"prisma": "*",
|
||||||
|
"typescript": ">=5.4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"prisma": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@prisma/client-runtime-utils": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/client-runtime-utils/-/client-runtime-utils-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-R26BVX9D/iw4toUmZKZf3jniM/9pMGHHdZN5LVP2L7HNiCQKNQQx/9LuMtjepbgRqSqQO3oHN0yzojHLnKTGEw==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
|
"node_modules/@prisma/debug": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-5+25XokVeAK2Z2C9W457AFw7Hk032Q3QI3G58KYKXPlpgxy+9FvV1+S1jqfJ2d4Nmq9LP/uACrM6OVhpJMSr8w==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
|
"node_modules/@prisma/driver-adapter-utils": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/driver-adapter-utils/-/driver-adapter-utils-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-sBbxm/yysHLLF2iMAB+qcX/nn3WFgsiC4DQNz0uM6BwGSIs8lIvgo0u8nR9nxe5gvFgKiIH8f4z2fgOEMeXc8w==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/debug": "7.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pg": {
|
||||||
|
"version": "8.16.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz",
|
||||||
|
"integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"pg-connection-string": "^2.9.1",
|
||||||
|
"pg-pool": "^3.10.1",
|
||||||
|
"pg-protocol": "^1.10.3",
|
||||||
|
"pg-types": "2.2.0",
|
||||||
|
"pgpass": "1.0.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 16.0.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"pg-cloudflare": "^1.2.7"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"pg-native": ">=3.0.1"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"pg-native": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pg-cloudflare": {
|
||||||
|
"version": "1.2.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz",
|
||||||
|
"integrity": "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"node_modules/pg-connection-string": {
|
||||||
|
"version": "2.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz",
|
||||||
|
"integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/pg-int8": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pg-pool": {
|
||||||
|
"version": "3.10.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.10.1.tgz",
|
||||||
|
"integrity": "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"pg": ">=8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pg-protocol": {
|
||||||
|
"version": "1.10.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz",
|
||||||
|
"integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/pg-types": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"pg-int8": "1.0.1",
|
||||||
|
"postgres-array": "~2.0.0",
|
||||||
|
"postgres-bytea": "~1.0.0",
|
||||||
|
"postgres-date": "~1.0.4",
|
||||||
|
"postgres-interval": "^1.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pg-types/node_modules/postgres-array": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pgpass": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"split2": "^4.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postgres-array": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postgres-bytea": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postgres-date": {
|
||||||
|
"version": "1.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
|
||||||
|
"integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postgres-interval": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"xtend": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/split2": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/xtend": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/zod": {
|
||||||
|
"version": "4.1.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz",
|
||||||
|
"integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
layers/prisma/nodejs/package.json
Normal file
11
layers/prisma/nodejs/package.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "prisma-layer",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Lambda layer for Prisma 7 with pg driver adapter and zod",
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/client": "^7.0.1",
|
||||||
|
"@prisma/adapter-pg": "^7.0.1",
|
||||||
|
"pg": "^8.13.0",
|
||||||
|
"zod": "^4.1.12"
|
||||||
|
}
|
||||||
|
}
|
||||||
38
package-lock.json
generated
38
package-lock.json
generated
@@ -46,7 +46,7 @@
|
|||||||
"prisma": "^7.0.1",
|
"prisma": "^7.0.1",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rxjs": "^7.8.1",
|
"rxjs": "^7.8.1",
|
||||||
"serverless": "4.17.0",
|
"serverless": "4.24.0",
|
||||||
"swagger-ui-express": "^5.0.0",
|
"swagger-ui-express": "^5.0.0",
|
||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"uuid": "^13.0.0",
|
"uuid": "^13.0.0",
|
||||||
@@ -75,6 +75,7 @@
|
|||||||
"serverless-offline": "^14.4.0",
|
"serverless-offline": "^14.4.0",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"supertest": "^6.3.4",
|
"supertest": "^6.3.4",
|
||||||
|
"swagger-ui-express": "^5.0.1",
|
||||||
"ts-jest": "^29.1.2",
|
"ts-jest": "^29.1.2",
|
||||||
"ts-loader": "^9.5.1",
|
"ts-loader": "^9.5.1",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
@@ -6564,6 +6565,7 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
|
||||||
"integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
|
"integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -8329,6 +8331,7 @@
|
|||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz",
|
||||||
"integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==",
|
"integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -8359,6 +8362,7 @@
|
|||||||
"version": "0.7.2",
|
"version": "0.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
|
||||||
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
|
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -8369,6 +8373,7 @@
|
|||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
|
||||||
"integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
|
"integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -9379,6 +9384,7 @@
|
|||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
|
||||||
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
|
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -9422,6 +9428,7 @@
|
|||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz",
|
||||||
"integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==",
|
"integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -9447,6 +9454,7 @@
|
|||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
|
||||||
"integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
|
"integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -9468,6 +9476,7 @@
|
|||||||
"version": "0.7.0",
|
"version": "0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
|
||||||
"integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
|
"integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -9485,6 +9494,7 @@
|
|||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
|
||||||
"integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
|
"integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -9495,6 +9505,7 @@
|
|||||||
"version": "6.14.0",
|
"version": "6.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
||||||
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
|
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
|
||||||
|
"dev": true,
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -9511,6 +9522,7 @@
|
|||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz",
|
||||||
"integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
|
"integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -9527,6 +9539,7 @@
|
|||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
|
||||||
"integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
|
"integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -9773,6 +9786,7 @@
|
|||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
|
||||||
"integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
|
"integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -10016,6 +10030,7 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
|
||||||
"integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
|
"integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -10864,6 +10879,7 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
|
||||||
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
|
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
@@ -12437,6 +12453,7 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
|
||||||
"integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
|
"integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -12516,6 +12533,7 @@
|
|||||||
"version": "1.54.0",
|
"version": "1.54.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
||||||
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
@@ -12525,6 +12543,7 @@
|
|||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
|
||||||
"integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
|
"integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -12709,6 +12728,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
|
||||||
"integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
|
"integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -12944,6 +12964,7 @@
|
|||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||||
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
@@ -14224,6 +14245,7 @@
|
|||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
|
||||||
"integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
|
"integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -14241,6 +14263,7 @@
|
|||||||
"version": "8.3.0",
|
"version": "8.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
|
||||||
"integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
|
"integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
@@ -14416,6 +14439,7 @@
|
|||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
|
||||||
"integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
|
"integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -14454,6 +14478,7 @@
|
|||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
|
||||||
"integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
|
"integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -14467,12 +14492,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/serverless": {
|
"node_modules/serverless": {
|
||||||
"version": "4.17.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/serverless/-/serverless-4.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/serverless/-/serverless-4.24.0.tgz",
|
||||||
"integrity": "sha512-hoZmipwyN/h7y9HwkWGlJ0YT06RFq7WNOD7fFEiPfnSnnUMVTzeNHq2BRrUlpHhf5s9srCHDc2wx5I06acfq1Q==",
|
"integrity": "sha512-bgxFQ6QyOGJC9IZjZIXo4m6bdWMl9I7HNZ4jrmwSpdePdsRd46igGRpSnhdYFOc71GNplhSOeoCibL94yCHfrg==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.8.3",
|
"axios": "^1.12.1",
|
||||||
"axios-proxy-builder": "^0.1.2",
|
"axios-proxy-builder": "^0.1.2",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"xml2js": "0.6.2"
|
"xml2js": "0.6.2"
|
||||||
@@ -15012,6 +15037,7 @@
|
|||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
||||||
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
|
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -15256,6 +15282,7 @@
|
|||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz",
|
||||||
"integrity": "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==",
|
"integrity": "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"swagger-ui-dist": ">=5.0.0"
|
"swagger-ui-dist": ">=5.0.0"
|
||||||
@@ -17031,6 +17058,7 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/write-file-atomic": {
|
"node_modules/write-file-atomic": {
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
"prisma": "^7.0.1",
|
"prisma": "^7.0.1",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rxjs": "^7.8.1",
|
"rxjs": "^7.8.1",
|
||||||
"serverless": "4.17.0",
|
"serverless": "4.24.0",
|
||||||
"swagger-ui-express": "^5.0.0",
|
"swagger-ui-express": "^5.0.0",
|
||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"uuid": "^13.0.0",
|
"uuid": "^13.0.0",
|
||||||
@@ -92,6 +92,7 @@
|
|||||||
"serverless-offline": "^14.4.0",
|
"serverless-offline": "^14.4.0",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"supertest": "^6.3.4",
|
"supertest": "^6.3.4",
|
||||||
|
"swagger-ui-express": "^5.0.1",
|
||||||
"ts-jest": "^29.1.2",
|
"ts-jest": "^29.1.2",
|
||||||
"ts-loader": "^9.5.1",
|
"ts-loader": "^9.5.1",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// prisma.ts
|
// prisma.ts
|
||||||
import { PrismaClient } from '@prisma/client';
|
// Re-export from the main singleton for consistency
|
||||||
|
import { prisma } from '../src/common/database/prisma.client';
|
||||||
|
|
||||||
// The DATABASE_URL environment variable will be automatically used
|
export { prisma };
|
||||||
export const prisma = new PrismaClient();
|
|
||||||
|
|
||||||
process.on('SIGINT', async () => {
|
process.on('SIGINT', async () => {
|
||||||
await prisma.$disconnect();
|
await prisma.$disconnect();
|
||||||
|
|||||||
@@ -66,6 +66,12 @@ model User {
|
|||||||
friendOf Friends[] @relation("FriendUser")
|
friendOf Friends[] @relation("FriendUser")
|
||||||
userAddressDetails UserAddressDetails[]
|
userAddressDetails UserAddressDetails[]
|
||||||
userDocuments UserDocuments[]
|
userDocuments UserDocuments[]
|
||||||
|
activityTracks ActivityTrack[]
|
||||||
|
// 🔹 Activities created by this user
|
||||||
|
createdActivities Activities[] @relation("UserActivities")
|
||||||
|
|
||||||
|
// 🔹 Activities where this user is Account Manager
|
||||||
|
managedActivities Activities[] @relation("ActivityAccountManager")
|
||||||
|
|
||||||
@@map("users")
|
@@map("users")
|
||||||
@@schema("usr")
|
@@schema("usr")
|
||||||
@@ -399,6 +405,7 @@ model FoodCuisines {
|
|||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
deletedAt DateTime? @map("deleted_at")
|
deletedAt DateTime? @map("deleted_at")
|
||||||
|
activityCuisines ActivityCuisine[]
|
||||||
|
|
||||||
@@map("food_cuisines")
|
@@map("food_cuisines")
|
||||||
@@schema("mst")
|
@@schema("mst")
|
||||||
@@ -406,11 +413,14 @@ model FoodCuisines {
|
|||||||
|
|
||||||
model CompanyTypes {
|
model CompanyTypes {
|
||||||
id Int @id @default(autoincrement())
|
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")
|
isActive Boolean @default(true) @map("is_active")
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
deletedAt DateTime? @map("deleted_at")
|
deletedAt DateTime? @map("deleted_at")
|
||||||
|
hostHeaders HostHeader[]
|
||||||
|
hostParents HostParent[]
|
||||||
|
|
||||||
@@map("company_types")
|
@@map("company_types")
|
||||||
@@schema("mst")
|
@@schema("mst")
|
||||||
@@ -436,7 +446,8 @@ model FoodTypes {
|
|||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
deletedAt DateTime? @map("deleted_at")
|
deletedAt DateTime? @map("deleted_at")
|
||||||
ActivityFoodDetails ActivityFoodDetails[]
|
ActivityFoodCost ActivityFoodCost[]
|
||||||
|
activityFoodTypes ActivityFoodTypes[]
|
||||||
|
|
||||||
@@map("food_types")
|
@@map("food_types")
|
||||||
@@schema("mst")
|
@@schema("mst")
|
||||||
@@ -610,6 +621,7 @@ model EnergyLevels {
|
|||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
energyLevelName String @map("energy_level_name") @db.VarChar(30)
|
energyLevelName String @map("energy_level_name") @db.VarChar(30)
|
||||||
energyIcon String @map("energy_icon") @db.VarChar(400)
|
energyIcon String @map("energy_icon") @db.VarChar(400)
|
||||||
|
energyColor String @map("energy_color") @db.VarChar(20)
|
||||||
isActive Boolean @default(true) @map("is_active")
|
isActive Boolean @default(true) @map("is_active")
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
@@ -664,12 +676,13 @@ model HostHeader {
|
|||||||
panNumber String? @map("pan_number") @db.VarChar(30)
|
panNumber String? @map("pan_number") @db.VarChar(30)
|
||||||
gstNumber String? @map("gst_number") @db.VarChar(30)
|
gstNumber String? @map("gst_number") @db.VarChar(30)
|
||||||
formationDate DateTime? @map("formation_date")
|
formationDate DateTime? @map("formation_date")
|
||||||
companyType String? @map("company_type") @db.VarChar(30)
|
companyTypeXid Int? @map("company_type_xid")
|
||||||
websiteUrl String? @map("website_url") @db.VarChar(50)
|
companyTypes CompanyTypes? @relation(fields: [companyTypeXid], references: [id], onDelete: Restrict)
|
||||||
instagramUrl String? @map("instagram_url") @db.VarChar(80)
|
websiteUrl String? @map("website_url") @db.VarChar(250)
|
||||||
facebookUrl String? @map("facebook_url") @db.VarChar(80)
|
instagramUrl String? @map("instagram_url") @db.VarChar(250)
|
||||||
linkedinUrl String? @map("linkedin_url") @db.VarChar(80)
|
facebookUrl String? @map("facebook_url") @db.VarChar(250)
|
||||||
twitterUrl String? @map("twitter_url") @db.VarChar(80)
|
linkedinUrl String? @map("linkedin_url") @db.VarChar(250)
|
||||||
|
twitterUrl String? @map("twitter_url") @db.VarChar(250)
|
||||||
currencyXid Int? @map("currency_xid")
|
currencyXid Int? @map("currency_xid")
|
||||||
currencies Currencies? @relation(fields: [currencyXid], references: [id], onDelete: Restrict)
|
currencies Currencies? @relation(fields: [currencyXid], references: [id], onDelete: Restrict)
|
||||||
stepper Int? @default(1) @map("stepper")
|
stepper Int? @default(1) @map("stepper")
|
||||||
@@ -691,6 +704,7 @@ model HostHeader {
|
|||||||
amountPerBooking Int? @map("amount_per_booking")
|
amountPerBooking Int? @map("amount_per_booking")
|
||||||
payoutDurationNum Int? @map("payout_duration_num")
|
payoutDurationNum Int? @map("payout_duration_num")
|
||||||
payoutDurationFrequency String? @map("payout_duration_frequency") @db.VarChar(20)
|
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")
|
isActive Boolean @default(true) @map("is_active")
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
@@ -780,17 +794,17 @@ model HostParent {
|
|||||||
countries Countries? @relation(fields: [countryXid], references: [id], onDelete: Restrict)
|
countries Countries? @relation(fields: [countryXid], references: [id], onDelete: Restrict)
|
||||||
pinCode String? @map("pin_code") @db.VarChar(30)
|
pinCode String? @map("pin_code") @db.VarChar(30)
|
||||||
logoPath String? @map("logo_path") @db.VarChar(400)
|
logoPath String? @map("logo_path") @db.VarChar(400)
|
||||||
isSubsidairy Boolean @default(false) @map("is_subsidairy")
|
|
||||||
registrationNumber String? @map("registration_number") @db.VarChar(30)
|
registrationNumber String? @map("registration_number") @db.VarChar(30)
|
||||||
panNumber String? @map("pan_number") @db.VarChar(30)
|
panNumber String? @map("pan_number") @db.VarChar(30)
|
||||||
gstNumber String? @map("gst_number") @db.VarChar(30)
|
gstNumber String? @map("gst_number") @db.VarChar(30)
|
||||||
formationDate DateTime? @map("formation_date")
|
formationDate DateTime? @map("formation_date")
|
||||||
companyType String? @map("company_type") @db.VarChar(30)
|
companyTypeXid Int? @map("company_type_xid")
|
||||||
websiteUrl String? @map("website_url") @db.VarChar(80)
|
companyTypes CompanyTypes? @relation(fields: [companyTypeXid], references: [id], onDelete: Restrict)
|
||||||
instagramUrl String? @map("instagram_url") @db.VarChar(80)
|
websiteUrl String? @map("website_url") @db.VarChar(250)
|
||||||
facebookUrl String? @map("facebook_url") @db.VarChar(80)
|
instagramUrl String? @map("instagram_url") @db.VarChar(250)
|
||||||
linkedinUrl String? @map("linkedin_url") @db.VarChar(80)
|
facebookUrl String? @map("facebook_url") @db.VarChar(250)
|
||||||
twitterUrl String? @map("twitter_url") @db.VarChar(80)
|
linkedinUrl String? @map("linkedin_url") @db.VarChar(250)
|
||||||
|
twitterUrl String? @map("twitter_url") @db.VarChar(250)
|
||||||
isActive Boolean @default(true) @map("is_active")
|
isActive Boolean @default(true) @map("is_active")
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
@@ -847,7 +861,7 @@ model Activities {
|
|||||||
frequency Frequencies? @relation(fields: [frequenciesXid], references: [id], onDelete: Restrict)
|
frequency Frequencies? @relation(fields: [frequenciesXid], references: [id], onDelete: Restrict)
|
||||||
activityRefNumber String? @map("activity_ref_number") @db.VarChar(30)
|
activityRefNumber String? @map("activity_ref_number") @db.VarChar(30)
|
||||||
activityTitle String? @map("activity_title") @db.VarChar(30)
|
activityTitle String? @map("activity_title") @db.VarChar(30)
|
||||||
activityDescription String? @map("activity_description") @db.VarChar(80)
|
activityDescription String? @map("activity_description") @db.VarChar(255)
|
||||||
checkInLat Float? @map("check_in_lat")
|
checkInLat Float? @map("check_in_lat")
|
||||||
checkInLong Float? @map("check_in_long")
|
checkInLong Float? @map("check_in_long")
|
||||||
checkInAddress String? @map("check_in_address") @db.VarChar(150)
|
checkInAddress String? @map("check_in_address") @db.VarChar(150)
|
||||||
@@ -870,6 +884,13 @@ model Activities {
|
|||||||
equipmentAvailable Boolean? @default(false) @map("equipment_available")
|
equipmentAvailable Boolean? @default(false) @map("equipment_available")
|
||||||
equipmentIsChargeable Boolean? @default(false) @map("equipment_is_chargeable")
|
equipmentIsChargeable Boolean? @default(false) @map("equipment_is_chargeable")
|
||||||
cancellationAvailable Boolean? @default(false) @map("cancellation_available")
|
cancellationAvailable Boolean? @default(false) @map("cancellation_available")
|
||||||
|
// 🔹 Creator / owner
|
||||||
|
userId Int?
|
||||||
|
user User? @relation("UserActivities", fields: [userId], references: [id])
|
||||||
|
|
||||||
|
// 🔹 Account Manager
|
||||||
|
accountManagerXid Int?
|
||||||
|
accountManager User? @relation("ActivityAccountManager", fields: [accountManagerXid], references: [id], onDelete: Restrict)
|
||||||
cancellationAllowedBeforeMins Int? @map("cancellation_allowed_before_mins")
|
cancellationAllowedBeforeMins Int? @map("cancellation_allowed_before_mins")
|
||||||
currencyXid Int? @map("currency_xid")
|
currencyXid Int? @map("currency_xid")
|
||||||
currencies Currencies? @relation(fields: [currencyXid], references: [id], onDelete: Restrict)
|
currencies Currencies? @relation(fields: [currencyXid], references: [id], onDelete: Restrict)
|
||||||
@@ -892,18 +913,19 @@ model Activities {
|
|||||||
ActivityEligibility ActivityEligibility[]
|
ActivityEligibility ActivityEligibility[]
|
||||||
ActivitySuggestions ActivitySuggestions[]
|
ActivitySuggestions ActivitySuggestions[]
|
||||||
ActivityAmDetails ActivityAmDetails[]
|
ActivityAmDetails ActivityAmDetails[]
|
||||||
ActivityPrices ActivityPrices[]
|
|
||||||
ActivityVenueArtifacts ActivityVenueArtifacts[]
|
|
||||||
ActivityPQQheader ActivityPQQheader[]
|
ActivityPQQheader ActivityPQQheader[]
|
||||||
ActivityAllowedEntry ActivityAllowedEntry[]
|
ActivityAllowedEntry ActivityAllowedEntry[]
|
||||||
ActivityFoodDetails ActivityFoodDetails[]
|
ActivityFoodCost ActivityFoodCost[]
|
||||||
ActivityEquipments ActivityEquipments[]
|
ActivityEquipments ActivityEquipments[]
|
||||||
ActivityNavigationModes ActivityNavigationModes[]
|
ActivityNavigationModes ActivityNavigationModes[]
|
||||||
ActivityPickUpDetails ActivityPickUpDetails[]
|
ActivityPickUpDetails ActivityPickUpDetails[]
|
||||||
ActivityAmenities ActivityAmenities[]
|
ActivityAmenities ActivityAmenities[]
|
||||||
ActivityEquipmentTaxes ActivityEquipmentTaxes[]
|
|
||||||
ScheduleHeader ScheduleHeader[]
|
ScheduleHeader ScheduleHeader[]
|
||||||
ItineraryActivities ItineraryActivities[]
|
ItineraryActivities ItineraryActivities[]
|
||||||
|
activityTracks ActivityTrack[]
|
||||||
|
activityFoodTypes ActivityFoodTypes[]
|
||||||
|
activityCuisines ActivityCuisine[]
|
||||||
|
activityPickUpTransports ActivityPickUpTransport[]
|
||||||
|
|
||||||
@@map("activities")
|
@@map("activities")
|
||||||
@@schema("act")
|
@@schema("act")
|
||||||
@@ -913,8 +935,7 @@ model ActivityOtherDetails {
|
|||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
activityXid Int @map("activity_xid")
|
activityXid Int @map("activity_xid")
|
||||||
activity Activities @relation(fields: [activityXid], references: [id], onDelete: Cascade)
|
activity Activities @relation(fields: [activityXid], references: [id], onDelete: Cascade)
|
||||||
foodCuisines String? @map("food_cuisines") @db.VarChar(30)
|
exclusiveNotes String? @map("exclusive_notes") @db.VarChar(500)
|
||||||
exclusiveNotes String? @map("exclusive_notes") @db.VarChar(50)
|
|
||||||
dosNotes String? @map("dos_notes") @db.VarChar(200)
|
dosNotes String? @map("dos_notes") @db.VarChar(200)
|
||||||
dontsNotes String? @map("donts_notes") @db.VarChar(200)
|
dontsNotes String? @map("donts_notes") @db.VarChar(200)
|
||||||
tipsNotes String? @map("tips_notes") @db.VarChar(100)
|
tipsNotes String? @map("tips_notes") @db.VarChar(100)
|
||||||
@@ -928,6 +949,25 @@ model ActivityOtherDetails {
|
|||||||
@@schema("act")
|
@@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 {
|
model ActivitiesMedia {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
activityXid Int @map("activity_xid")
|
activityXid Int @map("activity_xid")
|
||||||
@@ -961,6 +1001,8 @@ model ActivityVenues {
|
|||||||
deletedAt DateTime? @map("deleted_at")
|
deletedAt DateTime? @map("deleted_at")
|
||||||
ScheduleHeader ScheduleHeader[]
|
ScheduleHeader ScheduleHeader[]
|
||||||
ItineraryActivities ItineraryActivities[]
|
ItineraryActivities ItineraryActivities[]
|
||||||
|
ActivityPrices ActivityPrices[] // <-- Added opposite relation
|
||||||
|
ActivityVenueArtifacts ActivityVenueArtifacts[] // <-- Added opposite relation
|
||||||
|
|
||||||
@@map("activity_venues")
|
@@map("activity_venues")
|
||||||
@@schema("act")
|
@@schema("act")
|
||||||
@@ -1010,10 +1052,14 @@ model ActivityEligibility {
|
|||||||
weightRestrictionName String? @map("weight_restriction_name") @db.VarChar(30)
|
weightRestrictionName String? @map("weight_restriction_name") @db.VarChar(30)
|
||||||
weightEntered Int? @map("weight_entered")
|
weightEntered Int? @map("weight_entered")
|
||||||
weightIn String? @map("weight_in") @db.VarChar(30)
|
weightIn String? @map("weight_in") @db.VarChar(30)
|
||||||
|
minWeight Int? @map("min_weight")
|
||||||
|
maxWeight Int? @map("max_weight")
|
||||||
isHeightRestriction Boolean @default(false) @map("is_height_restriction")
|
isHeightRestriction Boolean @default(false) @map("is_height_restriction")
|
||||||
heightRestrictionName String? @map("height_restriction_name") @db.VarChar(30)
|
heightRestrictionName String? @map("height_restriction_name") @db.VarChar(30)
|
||||||
heightEntered Int? @map("height_entered")
|
heightEntered Int? @map("height_entered")
|
||||||
heightIn String? @map("height_in") @db.VarChar(30)
|
heightIn String? @map("height_in") @db.VarChar(30)
|
||||||
|
minHeight Int? @map("min_height")
|
||||||
|
maxHeight Int? @map("max_height")
|
||||||
isActive Boolean @default(true) @map("is_active")
|
isActive Boolean @default(true) @map("is_active")
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
@@ -1060,7 +1106,7 @@ model ActivityAmDetails {
|
|||||||
model ActivityPrices {
|
model ActivityPrices {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
activityVenueXid Int @map("activity_venue_xid")
|
activityVenueXid Int @map("activity_venue_xid")
|
||||||
activityVenue Activities @relation(fields: [activityVenueXid], references: [id], onDelete: Cascade)
|
activityVenue ActivityVenues @relation(fields: [activityVenueXid], references: [id], onDelete: Cascade)
|
||||||
noOfSession Int @map("no_of_session")
|
noOfSession Int @map("no_of_session")
|
||||||
isPackage Boolean @default(false) @map("is_package")
|
isPackage Boolean @default(false) @map("is_package")
|
||||||
sessionValidity Int @map("session_validity")
|
sessionValidity Int @map("session_validity")
|
||||||
@@ -1097,7 +1143,7 @@ model ActivityPriceTaxes {
|
|||||||
model ActivityVenueArtifacts {
|
model ActivityVenueArtifacts {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
activityVenueXid Int @map("activity_venue_xid")
|
activityVenueXid Int @map("activity_venue_xid")
|
||||||
activityVenue Activities @relation(fields: [activityVenueXid], references: [id], onDelete: Cascade)
|
activityVenue ActivityVenues @relation(fields: [activityVenueXid], references: [id], onDelete: Cascade)
|
||||||
mediaType String @map("media_type") @db.VarChar(30)
|
mediaType String @map("media_type") @db.VarChar(30)
|
||||||
mediaFileName String @map("media_file_name") @db.VarChar(400)
|
mediaFileName String @map("media_file_name") @db.VarChar(400)
|
||||||
isActive Boolean @default(true) @map("is_active")
|
isActive Boolean @default(true) @map("is_active")
|
||||||
@@ -1115,8 +1161,8 @@ model ActivityPQQheader {
|
|||||||
activity Activities @relation(fields: [activityXid], references: [id], onDelete: Cascade)
|
activity Activities @relation(fields: [activityXid], references: [id], onDelete: Cascade)
|
||||||
pqqQuestionXid Int @map("pqq_question_xid")
|
pqqQuestionXid Int @map("pqq_question_xid")
|
||||||
pqqQuestions PQQQuestions @relation(fields: [pqqQuestionXid], references: [id], onDelete: Restrict)
|
pqqQuestions PQQQuestions @relation(fields: [pqqQuestionXid], references: [id], onDelete: Restrict)
|
||||||
pqqAnswerXid Int @map("pqq_answer_xid")
|
pqqAnswerXid Int? @map("pqq_answer_xid")
|
||||||
pqqAnswers PQQAnswers @relation(fields: [pqqAnswerXid], references: [id], onDelete: Restrict)
|
pqqAnswers PQQAnswers? @relation(fields: [pqqAnswerXid], references: [id], onDelete: Restrict)
|
||||||
comments String? @map("comments") @db.VarChar(200)
|
comments String? @map("comments") @db.VarChar(200)
|
||||||
isActive Boolean @default(true) @map("is_active")
|
isActive Boolean @default(true) @map("is_active")
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
@@ -1178,12 +1224,10 @@ model ActivityAllowedEntry {
|
|||||||
@@schema("act")
|
@@schema("act")
|
||||||
}
|
}
|
||||||
|
|
||||||
model ActivityFoodDetails {
|
model ActivityFoodCost {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
activityXid Int @map("activity_xid")
|
activityXid Int @map("activity_xid")
|
||||||
activity Activities @relation(fields: [activityXid], references: [id], onDelete: Cascade)
|
activity Activities @relation(fields: [activityXid], references: [id], onDelete: Cascade)
|
||||||
foodTypeXid Int @map("food_type_xid")
|
|
||||||
foodType FoodTypes @relation(fields: [foodTypeXid], references: [id], onDelete: Restrict)
|
|
||||||
baseAmount Int @map("base_amount")
|
baseAmount Int @map("base_amount")
|
||||||
totalAmount Int @map("total_amount")
|
totalAmount Int @map("total_amount")
|
||||||
isActive Boolean @default(true) @map("is_active")
|
isActive Boolean @default(true) @map("is_active")
|
||||||
@@ -1191,15 +1235,47 @@ model ActivityFoodDetails {
|
|||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
deletedAt DateTime? @map("deleted_at")
|
deletedAt DateTime? @map("deleted_at")
|
||||||
ActivityFoodTaxes ActivityFoodTaxes[]
|
ActivityFoodTaxes ActivityFoodTaxes[]
|
||||||
|
foodTypes FoodTypes? @relation(fields: [foodTypesId], references: [id])
|
||||||
|
foodTypesId Int?
|
||||||
|
|
||||||
@@map("activity_food_details")
|
@@map("activity_food_cost")
|
||||||
|
@@schema("act")
|
||||||
|
}
|
||||||
|
|
||||||
|
model ActivityFoodTypes {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
activityXid Int @map("activity_xid")
|
||||||
|
activity Activities @relation(fields: [activityXid], references: [id], onDelete: Cascade)
|
||||||
|
foodTypeXid Int @map("food_type_xid")
|
||||||
|
foodType FoodTypes @relation(fields: [foodTypeXid], references: [id], onDelete: Restrict)
|
||||||
|
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_food_types")
|
||||||
|
@@schema("act")
|
||||||
|
}
|
||||||
|
|
||||||
|
model ActivityCuisine {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
activityXid Int @map("activity_xid")
|
||||||
|
activity Activities @relation(fields: [activityXid], references: [id], onDelete: Cascade)
|
||||||
|
foodCuisineXid Int @map("food_cuisine_xid")
|
||||||
|
foodCuisine FoodCuisines @relation(fields: [foodCuisineXid], references: [id], onDelete: Restrict)
|
||||||
|
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_cuisine")
|
||||||
@@schema("act")
|
@@schema("act")
|
||||||
}
|
}
|
||||||
|
|
||||||
model ActivityFoodTaxes {
|
model ActivityFoodTaxes {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
activityFoodDetailsXid Int @map("activity_food_details_xid")
|
activityFoodCostXid Int @map("activity_food_cost_xid")
|
||||||
activityFoodDetails ActivityFoodDetails @relation(fields: [activityFoodDetailsXid], references: [id], onDelete: Cascade)
|
activityFoodCost ActivityFoodCost @relation(fields: [activityFoodCostXid], references: [id], onDelete: Cascade)
|
||||||
taxXid Int @map("tax_xid")
|
taxXid Int @map("tax_xid")
|
||||||
taxes Taxes @relation(fields: [taxXid], references: [id], onDelete: Restrict)
|
taxes Taxes @relation(fields: [taxXid], references: [id], onDelete: Restrict)
|
||||||
taxPer Float @map("tax_per")
|
taxPer Float @map("tax_per")
|
||||||
@@ -1225,6 +1301,7 @@ model ActivityEquipments {
|
|||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
deletedAt DateTime? @map("deleted_at")
|
deletedAt DateTime? @map("deleted_at")
|
||||||
|
ActivityEquipmentTaxes ActivityEquipmentTaxes[]
|
||||||
|
|
||||||
@@map("activity_equipments")
|
@@map("activity_equipments")
|
||||||
@@schema("act")
|
@@schema("act")
|
||||||
@@ -1233,7 +1310,7 @@ model ActivityEquipments {
|
|||||||
model ActivityEquipmentTaxes {
|
model ActivityEquipmentTaxes {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
activityEquipmentXid Int @map("activity_equipment_xid")
|
activityEquipmentXid Int @map("activity_equipment_xid")
|
||||||
activityEquipment Activities @relation(fields: [activityEquipmentXid], references: [id], onDelete: Cascade)
|
activityEquipment ActivityEquipments @relation(fields: [activityEquipmentXid], references: [id], onDelete: Cascade)
|
||||||
taxXid Int @map("tax_xid")
|
taxXid Int @map("tax_xid")
|
||||||
taxes Taxes @relation(fields: [taxXid], references: [id], onDelete: Restrict)
|
taxes Taxes @relation(fields: [taxXid], references: [id], onDelete: Restrict)
|
||||||
taxPer Float @map("tax_per")
|
taxPer Float @map("tax_per")
|
||||||
@@ -1285,17 +1362,21 @@ model ActivityNavigationModesTaxes {
|
|||||||
|
|
||||||
model ActivityPickUpDetails {
|
model ActivityPickUpDetails {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
activityXid Int @map("activity_xid")
|
activityPickUpTransportXid Int @map("activity_pick_up_transport_xid")
|
||||||
activity Activities @relation(fields: [activityXid], references: [id], onDelete: Cascade)
|
activityPickUpTransport ActivityPickUpTransport @relation(fields: [activityPickUpTransportXid], references: [id], onDelete: Cascade)
|
||||||
isPickUp Boolean @default(false) @map("is_pick_up")
|
isPickUp Boolean @default(false) @map("is_pick_up")
|
||||||
locationLat Float? @map("location_lat")
|
locationLat Float? @map("location_lat")
|
||||||
locationLong Float? @map("location_long")
|
locationLong Float? @map("location_long")
|
||||||
locationAddress String? @map("location_address") @db.VarChar(150)
|
locationAddress String? @map("location_address") @db.VarChar(150)
|
||||||
|
transportBasePrice Int @map("transport_base_price")
|
||||||
|
transportTotalPrice Int @map("transport_total_price")
|
||||||
isActive Boolean @default(true) @map("is_active")
|
isActive Boolean @default(true) @map("is_active")
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
deletedAt DateTime? @map("deleted_at")
|
deletedAt DateTime? @map("deleted_at")
|
||||||
ActivityPickUpTransport ActivityPickUpTransport[]
|
activities Activities? @relation(fields: [activitiesId], references: [id])
|
||||||
|
activitiesId Int?
|
||||||
|
activityPickUpTransportTaxes ActivityPickUpTransportTaxes[]
|
||||||
|
|
||||||
@@map("activity_pick_up_details")
|
@@map("activity_pick_up_details")
|
||||||
@@schema("act")
|
@@schema("act")
|
||||||
@@ -1303,18 +1384,17 @@ model ActivityPickUpDetails {
|
|||||||
|
|
||||||
model ActivityPickUpTransport {
|
model ActivityPickUpTransport {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
activityPickUpDetailsXid Int @map("activity_pick_up_details_xid")
|
activityXid Int @map("activity_xid")
|
||||||
activityPickUpDetails ActivityPickUpDetails @relation(fields: [activityPickUpDetailsXid], references: [id], onDelete: Cascade)
|
activity Activities @relation(fields: [activityXid], references: [id], onDelete: Cascade)
|
||||||
transportModeXid Int @map("transport_mode_xid")
|
transportModeXid Int @map("transport_mode_xid")
|
||||||
transportMode TransportModes @relation(fields: [transportModeXid], references: [id], onDelete: Restrict)
|
transportMode TransportModes @relation(fields: [transportModeXid], references: [id], onDelete: Restrict)
|
||||||
isTransportModeChargeable Boolean @default(false) @map("is_transport_mode_chargeable")
|
isTransportModeChargeable Boolean @default(false) @map("is_transport_mode_chargeable")
|
||||||
transportBasePrice Int @map("transport_base_price")
|
|
||||||
transportTotalPrice Int @map("transport_total_price")
|
|
||||||
isActive Boolean @default(true) @map("is_active")
|
isActive Boolean @default(true) @map("is_active")
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
deletedAt DateTime? @map("deleted_at")
|
deletedAt DateTime? @map("deleted_at")
|
||||||
ActivityPickUpTransportTaxes ActivityPickUpTransportTaxes[]
|
|
||||||
|
pickupDetails ActivityPickUpDetails[]
|
||||||
|
|
||||||
@@map("activity_pick_up_transport")
|
@@map("activity_pick_up_transport")
|
||||||
@@schema("act")
|
@@schema("act")
|
||||||
@@ -1322,8 +1402,8 @@ model ActivityPickUpTransport {
|
|||||||
|
|
||||||
model ActivityPickUpTransportTaxes {
|
model ActivityPickUpTransportTaxes {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
activityPickUpTransportXid Int @map("activity_pick_up_transport_xid")
|
activityPickUpDetailsXid Int @map("activity_pick_up_details_xid")
|
||||||
activityPickUpTransport ActivityPickUpTransport @relation(fields: [activityPickUpTransportXid], references: [id], onDelete: Cascade)
|
activityPickUpDetails ActivityPickUpDetails @relation(fields: [activityPickUpDetailsXid], references: [id], onDelete: Cascade)
|
||||||
taxXid Int @map("tax_xid")
|
taxXid Int @map("tax_xid")
|
||||||
taxes Taxes @relation(fields: [taxXid], references: [id], onDelete: Restrict)
|
taxes Taxes @relation(fields: [taxXid], references: [id], onDelete: Restrict)
|
||||||
taxPer Float @map("tax_per")
|
taxPer Float @map("tax_per")
|
||||||
|
|||||||
173
prisma/seed.ts
173
prisma/seed.ts
@@ -1,6 +1,10 @@
|
|||||||
import { PrismaClient } from '@prisma/client';
|
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() {
|
async function main() {
|
||||||
// ✅ Countries
|
// ✅ Countries
|
||||||
@@ -29,11 +33,46 @@ async function main() {
|
|||||||
update: {},
|
update: {},
|
||||||
create: { countryXid: india.id, stateName: 'Maharashtra' },
|
create: { countryXid: india.id, stateName: 'Maharashtra' },
|
||||||
});
|
});
|
||||||
|
const uttarpradesh = await prisma.states.upsert({
|
||||||
|
where: { stateName: 'Uttar-Pradesh' },
|
||||||
|
update: {},
|
||||||
|
create: { countryXid: india.id, stateName: 'Uttar-Pradesh' },
|
||||||
|
});
|
||||||
|
const Rajasthan = await prisma.states.upsert({
|
||||||
|
where: { stateName: 'Rajasthan' },
|
||||||
|
update: {},
|
||||||
|
create: { countryXid: india.id, stateName: 'Rajasthan' },
|
||||||
|
});
|
||||||
|
const Uttarakhand = await prisma.states.upsert({
|
||||||
|
where: { stateName: 'Uttarakhand' },
|
||||||
|
update: {},
|
||||||
|
create: { countryXid: india.id, stateName: 'Uttarakhand' },
|
||||||
|
});
|
||||||
|
const HimachalPradesh = await prisma.states.upsert({
|
||||||
|
where: { stateName: 'Himachal Pradesh' },
|
||||||
|
update: {},
|
||||||
|
create: { countryXid: india.id, stateName: 'Himachal Pradesh' },
|
||||||
|
});
|
||||||
|
const Gujrat = await prisma.states.upsert({
|
||||||
|
where: { stateName: 'Gujrat' },
|
||||||
|
update: {},
|
||||||
|
create: { countryXid: india.id, stateName: 'Gujrat' },
|
||||||
|
});
|
||||||
|
|
||||||
// ✅ Cities
|
// ✅ Cities
|
||||||
await prisma.cities.createMany({
|
await prisma.cities.createMany({
|
||||||
data: [
|
data: [
|
||||||
{ stateXid: maharashtra.id, cityName: 'Mumbai' },
|
{ stateXid: maharashtra.id, cityName: 'Mumbai' },
|
||||||
|
{ stateXid: uttarpradesh.id, cityName: 'Azamgarh' },
|
||||||
|
{ stateXid: uttarpradesh.id, cityName: 'Lucknow' },
|
||||||
|
{ stateXid: uttarpradesh.id, cityName: 'Prayagraj' },
|
||||||
|
{ stateXid: Rajasthan.id, cityName: 'Jaipur' },
|
||||||
|
{ stateXid: Rajasthan.id, cityName: 'Jaisalmer' },
|
||||||
|
{ stateXid: Uttarakhand.id, cityName: 'Haridwar' },
|
||||||
|
{ stateXid: HimachalPradesh.id, cityName: 'Manali' },
|
||||||
|
{ stateXid: Gujrat.id, cityName: 'Surat' },
|
||||||
|
{ stateXid: Gujrat.id, cityName: 'Ahemdabad' },
|
||||||
|
{ stateXid: Gujrat.id, cityName: 'Rajkot' },
|
||||||
],
|
],
|
||||||
skipDuplicates: true,
|
skipDuplicates: true,
|
||||||
});
|
});
|
||||||
@@ -52,6 +91,21 @@ async function main() {
|
|||||||
update: {},
|
update: {},
|
||||||
create: { countryXid: india.id, bankName: 'HDFC Bank' },
|
create: { countryXid: india.id, bankName: 'HDFC Bank' },
|
||||||
});
|
});
|
||||||
|
const indianBank = await prisma.banks.upsert({
|
||||||
|
where: { bankName: 'Indian Bank' },
|
||||||
|
update: {},
|
||||||
|
create: { countryXid: india.id, bankName: 'Indian Bank' },
|
||||||
|
});
|
||||||
|
const Kotak = await prisma.banks.upsert({
|
||||||
|
where: { bankName: 'Kotak Bank' },
|
||||||
|
update: {},
|
||||||
|
create: { countryXid: india.id, bankName: 'Kotak Bank' },
|
||||||
|
});
|
||||||
|
const BOI = await prisma.banks.upsert({
|
||||||
|
where: { bankName: 'Bank of India' },
|
||||||
|
update: {},
|
||||||
|
create: { countryXid: india.id, bankName: 'Bank of India' },
|
||||||
|
});
|
||||||
|
|
||||||
// ✅ Bank Branches
|
// ✅ Bank Branches
|
||||||
await prisma.bankBranches.createMany({
|
await prisma.bankBranches.createMany({
|
||||||
@@ -63,6 +117,27 @@ async function main() {
|
|||||||
branchAddress: 'HDFC Fort Branch, Mumbai',
|
branchAddress: 'HDFC Fort Branch, Mumbai',
|
||||||
ifscCode: 'HDFC0001234',
|
ifscCode: 'HDFC0001234',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
bankXid: indianBank.id,
|
||||||
|
stateXid: maharashtra.id,
|
||||||
|
cityXid: (await prisma.cities.findFirst({ where: { cityName: 'Mumbai' } }))!.id,
|
||||||
|
branchAddress: 'Indian Bank Fort Branch, Mumbai',
|
||||||
|
ifscCode: 'IDIB0001234',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bankXid: Kotak.id,
|
||||||
|
stateXid: Uttarakhand.id,
|
||||||
|
cityXid: (await prisma.cities.findFirst({ where: { cityName: 'Haridwar' } }))!.id,
|
||||||
|
branchAddress: 'Kotak Fort Branch, Mumbai',
|
||||||
|
ifscCode: 'KTB0001234',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bankXid: BOI.id,
|
||||||
|
stateXid: uttarpradesh.id,
|
||||||
|
cityXid: (await prisma.cities.findFirst({ where: { cityName: 'Azamgarh' } }))!.id,
|
||||||
|
branchAddress: 'Bank of India Fort Branch, Mumbai',
|
||||||
|
ifscCode: 'BOI0001234',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
skipDuplicates: true,
|
skipDuplicates: true,
|
||||||
});
|
});
|
||||||
@@ -74,35 +149,51 @@ async function main() {
|
|||||||
create: { interestName: 'Chill and Zen', displayOrder: 1 },
|
create: { interestName: 'Chill and Zen', displayOrder: 1 },
|
||||||
});
|
});
|
||||||
const sweatmode = await prisma.interests.upsert({
|
const sweatmode = await prisma.interests.upsert({
|
||||||
where: { interestName: 'Sweat Mode' },
|
where: { interestName: 'Sweat Mode On' },
|
||||||
update: {},
|
update: {},
|
||||||
create: { interestName: 'Sweat Mode', displayOrder: 2 },
|
create: { interestName: 'Sweat Mode On', displayOrder: 2 },
|
||||||
});
|
});
|
||||||
const gameon = await prisma.interests.upsert({
|
const trackracer = await prisma.interests.upsert({
|
||||||
where: { interestName: 'Game On' },
|
where: { interestName: 'Track Racer' },
|
||||||
update: {},
|
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({
|
const partycentral = await prisma.interests.upsert({
|
||||||
where: { interestName: 'Party Central' },
|
where: { interestName: 'Party Central' },
|
||||||
update: {},
|
update: {},
|
||||||
create: { interestName: 'Party Central', displayOrder: 4 },
|
create: { interestName: 'Party Central', displayOrder: 6 },
|
||||||
});
|
});
|
||||||
const artsy = await prisma.interests.upsert({
|
const aqua = await prisma.interests.upsert({
|
||||||
where: { interestName: 'Artsy' },
|
where: { interestName: 'Aqua' },
|
||||||
update: {},
|
update: {},
|
||||||
create: { interestName: 'Artsy', displayOrder: 5 },
|
create: { interestName: 'Aqua', displayOrder: 7 },
|
||||||
});
|
});
|
||||||
const foodiediaries = await prisma.interests.upsert({
|
const foodie = await prisma.interests.upsert({
|
||||||
where: { interestName: 'Foodie Diaries' },
|
where: { interestName: 'Foodie' },
|
||||||
update: {},
|
update: {},
|
||||||
create: { interestName: 'Foodie Diaries', displayOrder: 6 },
|
create: { interestName: 'Foodie', displayOrder: 8 },
|
||||||
});
|
});
|
||||||
|
|
||||||
await prisma.activityTypes.createMany({
|
await prisma.activityTypes.createMany({
|
||||||
data: [
|
data: [
|
||||||
{ interestXid: chillandzen.id, activityTypeName: 'Cricket' },
|
{ interestXid: aqua.id, activityTypeName: 'Scuba-Diving' },
|
||||||
{ interestXid: chillandzen.id, activityTypeName: 'Football' },
|
{ 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,
|
skipDuplicates: true,
|
||||||
});
|
});
|
||||||
@@ -132,6 +223,58 @@ async function main() {
|
|||||||
],
|
],
|
||||||
skipDuplicates: true, // prevents error if already seeded
|
skipDuplicates: true, // prevents error if already seeded
|
||||||
});
|
});
|
||||||
|
// ✅ Energy Levels
|
||||||
|
await prisma.energyLevels.createMany({
|
||||||
|
data: [
|
||||||
|
{ energyLevelName: 'Low', energyIcon: '📶', energyColor: 'Red' },
|
||||||
|
{ energyLevelName: 'Medium', energyIcon: '📶', energyColor: 'Yellow' },
|
||||||
|
{ energyLevelName: 'High', energyIcon: '📶', energyColor: 'Green' },
|
||||||
|
],
|
||||||
|
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' },
|
||||||
|
update: {},
|
||||||
|
create: { companyTypeName: 'Private Limited', displayOrder: 5 },
|
||||||
|
});
|
||||||
|
|
||||||
|
await prisma.companyTypes.upsert({
|
||||||
|
where: { companyTypeName: 'Non-Profit Organisation' },
|
||||||
|
update: {},
|
||||||
|
create: { companyTypeName: 'Non-Profit Organisation', displayOrder: 6 },
|
||||||
|
});
|
||||||
|
|
||||||
|
await prisma.companyTypes.upsert({
|
||||||
|
where: { companyTypeName: 'Public Limited' },
|
||||||
|
update: {},
|
||||||
|
create: { companyTypeName: 'Public Limited', displayOrder: 7 },
|
||||||
|
});
|
||||||
|
|
||||||
// ✅ Food Types
|
// ✅ Food Types
|
||||||
await prisma.foodTypes.createMany({
|
await prisma.foodTypes.createMany({
|
||||||
|
|||||||
@@ -1,11 +1,28 @@
|
|||||||
service: minglarDev
|
service: minglar
|
||||||
|
|
||||||
|
useDotenv: true
|
||||||
|
|
||||||
|
params:
|
||||||
|
dev:
|
||||||
|
stage: dev
|
||||||
|
test:
|
||||||
|
stage: test
|
||||||
|
uat:
|
||||||
|
stage: uat
|
||||||
|
|
||||||
provider:
|
provider:
|
||||||
name: aws
|
name: aws
|
||||||
runtime: nodejs22.x
|
runtime: nodejs22.x
|
||||||
region: ap-south-1
|
region: ap-south-1
|
||||||
|
stage: ${opt:stage, 'dev'}
|
||||||
versionFunctions: false
|
versionFunctions: false
|
||||||
memorySize: 512
|
memorySize: 512
|
||||||
|
# Apply Prisma layer to all functions
|
||||||
|
# Reference the layer defined in this stack using CloudFormation Ref
|
||||||
|
layers:
|
||||||
|
# Use the exported stack output so deploy function works (expects a string ARN)
|
||||||
|
# For offline/local, fall back to an empty string so the CF lookup is optional.
|
||||||
|
- ${cf:${self:service}-${sls:stage}.PrismaLambdaLayerQualifiedArn, ''}
|
||||||
apiGateway:
|
apiGateway:
|
||||||
binaryMediaTypes:
|
binaryMediaTypes:
|
||||||
- '*/*'
|
- '*/*'
|
||||||
@@ -38,6 +55,8 @@ provider:
|
|||||||
S3_BUCKET_NAME: ${env:S3_BUCKET_NAME}
|
S3_BUCKET_NAME: ${env:S3_BUCKET_NAME}
|
||||||
MINGLAR_ADMIN_NAME: ${env:MINGLAR_ADMIN_NAME}
|
MINGLAR_ADMIN_NAME: ${env:MINGLAR_ADMIN_NAME}
|
||||||
MINGLAR_ADMIN_EMAIL: ${env:MINGLAR_ADMIN_EMAIL}
|
MINGLAR_ADMIN_EMAIL: ${env:MINGLAR_ADMIN_EMAIL}
|
||||||
|
AM_INVITATION_LINK: ${env:AM_INVITATION_LINK}
|
||||||
|
HOST_LINK: ${env:HOST_LINK}
|
||||||
|
|
||||||
iam:
|
iam:
|
||||||
role:
|
role:
|
||||||
@@ -53,25 +72,63 @@ provider:
|
|||||||
- 'arn:aws:s3:::${env:S3_BUCKET_NAME}/*'
|
- 'arn:aws:s3:::${env:S3_BUCKET_NAME}/*'
|
||||||
|
|
||||||
custom:
|
custom:
|
||||||
|
serverless-offline:
|
||||||
|
reloadHandler: true
|
||||||
|
httpPort: 3000
|
||||||
|
noPrependStageInUrl: true
|
||||||
|
|
||||||
|
build:
|
||||||
esbuild:
|
esbuild:
|
||||||
bundle: true
|
bundle: true
|
||||||
minify: true
|
minify: true
|
||||||
sourcemap: false
|
sourcemap: false
|
||||||
target: node20
|
target: node20
|
||||||
platform: node
|
platform: node
|
||||||
concurrency: 5
|
# Mark as external so they're not bundled into the JS
|
||||||
external:
|
external:
|
||||||
- '@prisma/client'
|
- '@prisma/client'
|
||||||
|
- '.prisma/client'
|
||||||
- '.prisma'
|
- '.prisma'
|
||||||
|
- '@prisma/adapter-pg'
|
||||||
|
- 'pg'
|
||||||
|
- 'zod'
|
||||||
|
- '@aws-sdk/*'
|
||||||
|
- '@smithy/*'
|
||||||
|
- '@aws-crypto/*'
|
||||||
|
# Exclude prevents npm install of these packages in the zip
|
||||||
exclude:
|
exclude:
|
||||||
- 'aws-sdk'
|
- 'aws-sdk'
|
||||||
serverless-offline:
|
- '@aws-sdk/*'
|
||||||
reloadHandler: true
|
- '@smithy/*'
|
||||||
|
- '@aws-crypto/*'
|
||||||
|
- '@prisma/adapter-pg'
|
||||||
|
- '@prisma/client'
|
||||||
|
- '.prisma'
|
||||||
|
- '.prisma/client'
|
||||||
|
- 'pg'
|
||||||
|
- 'zod'
|
||||||
|
- 'pg-*'
|
||||||
|
- 'postgres-*'
|
||||||
|
- 'pgpass'
|
||||||
|
- 'split2'
|
||||||
|
- 'xtend'
|
||||||
|
|
||||||
|
# Define layers
|
||||||
|
layers:
|
||||||
|
prisma:
|
||||||
|
path: layers/prisma
|
||||||
|
name: ${self:service}-prisma-layer-${sls:stage}
|
||||||
|
description: Prisma 7 client with pg driver adapter (no binary engines)
|
||||||
|
compatibleRuntimes:
|
||||||
|
- nodejs22.x
|
||||||
|
retain: false
|
||||||
|
|
||||||
package:
|
package:
|
||||||
individually: true
|
individually: true
|
||||||
patterns:
|
patterns:
|
||||||
- '!node_modules/**'
|
- '!node_modules/**'
|
||||||
|
- '!node_modules/@prisma/**'
|
||||||
|
- '!node_modules/.prisma/**'
|
||||||
- '!**/*.test.js'
|
- '!**/*.test.js'
|
||||||
- '!**/*.spec.js'
|
- '!**/*.spec.js'
|
||||||
- '!**/test/**'
|
- '!**/test/**'
|
||||||
@@ -88,6 +145,8 @@ functions:
|
|||||||
- ${file(./serverless/functions/host.yml)}
|
- ${file(./serverless/functions/host.yml)}
|
||||||
- ${file(./serverless/functions/minglaradmin.yml)}
|
- ${file(./serverless/functions/minglaradmin.yml)}
|
||||||
- ${file(./serverless/functions/prepopulate.yml)}
|
- ${file(./serverless/functions/prepopulate.yml)}
|
||||||
|
- ${file(./serverless/functions/pqq.yml)}
|
||||||
|
- ${file(./serverless/functions/swagger.yml)}
|
||||||
|
|
||||||
plugins:
|
plugins:
|
||||||
- serverless-offline
|
- serverless-offline
|
||||||
@@ -1,764 +0,0 @@
|
|||||||
service: minglarDev
|
|
||||||
|
|
||||||
provider:
|
|
||||||
name: aws
|
|
||||||
runtime: nodejs22.x
|
|
||||||
region: ap-south-1
|
|
||||||
versionFunctions: false
|
|
||||||
memorySize: 512 # Default memory for all functions (can be overridden per function)
|
|
||||||
apiGateway:
|
|
||||||
binaryMediaTypes:
|
|
||||||
- '*/*'
|
|
||||||
minimumCompressionSize: 1024
|
|
||||||
|
|
||||||
environment:
|
|
||||||
DATABASE_URL: ${env:DATABASE_URL}
|
|
||||||
DB_USERNAME: ${env:DB_USERNAME}
|
|
||||||
DB_PASSWORD: ${env:DB_PASSWORD}
|
|
||||||
DB_DATABASE_NAME: ${env:DB_DATABASE_NAME}
|
|
||||||
DB_HOSTNAME: ${env:DB_HOSTNAME}
|
|
||||||
DB_PORT: ${env:DB_PORT}
|
|
||||||
BY_PASS_EMAIL: ${env:BY_PASS_EMAIL}
|
|
||||||
BYPASS_OTP: ${env:BYPASS_OTP}
|
|
||||||
BREVO_EMAIL_API_KEY: ${env:BREVO_EMAIL_API_KEY}
|
|
||||||
BREVO_API_BASEURL: ${env:BREVO_API_BASEURL}
|
|
||||||
BREVO_FROM_EMAIL: ${env:BREVO_FROM_EMAIL}
|
|
||||||
BREVO_SMTP_HOST: ${env:BREVO_SMTP_HOST}
|
|
||||||
BREVO_SMTP_PORT: ${env:BREVO_SMTP_PORT}
|
|
||||||
BREVO_SMTP_USER: ${env:BREVO_SMTP_USER}
|
|
||||||
BREVO_SMTP_PASS: ${env:BREVO_SMTP_PASS}
|
|
||||||
REFRESH_TOKEN_SECRET: ${env:REFRESH_TOKEN_SECRET}
|
|
||||||
JWT_SECRET: ${env:JWT_SECRET}
|
|
||||||
SALT_ROUNDS: ${env:SALT_ROUNDS}
|
|
||||||
NODE_ENV: ${env:NODE_ENV}
|
|
||||||
S3_BUCKET_NAME: ${env:S3_BUCKET_NAME}
|
|
||||||
MINGLAR_ADMIN_NAME: ${env:MINGLAR_ADMIN_NAME}
|
|
||||||
MINGLAR_ADMIN_EMAIL: ${env:MINGLAR_ADMIN_EMAIL}
|
|
||||||
|
|
||||||
iam:
|
|
||||||
role:
|
|
||||||
statements:
|
|
||||||
- Effect: Allow
|
|
||||||
Action:
|
|
||||||
- s3:PutObject
|
|
||||||
- s3:GetObject
|
|
||||||
- s3:DeleteObject
|
|
||||||
- s3:ListBucket
|
|
||||||
Resource:
|
|
||||||
- 'arn:aws:s3:::${env:S3_BUCKET_NAME}'
|
|
||||||
- 'arn:aws:s3:::${env:S3_BUCKET_NAME}/*'
|
|
||||||
|
|
||||||
custom:
|
|
||||||
esbuild:
|
|
||||||
bundle: true
|
|
||||||
minify: true
|
|
||||||
sourcemap: false
|
|
||||||
target: node20
|
|
||||||
platform: node
|
|
||||||
concurrency: 5
|
|
||||||
external:
|
|
||||||
- '@prisma/client'
|
|
||||||
- '.prisma'
|
|
||||||
exclude:
|
|
||||||
- 'aws-sdk'
|
|
||||||
|
|
||||||
package:
|
|
||||||
individually: true
|
|
||||||
patterns:
|
|
||||||
- '!node_modules/**'
|
|
||||||
- '!**/*.test.js'
|
|
||||||
- '!**/*.spec.js'
|
|
||||||
- '!**/test/**'
|
|
||||||
- '!**/__tests__/**'
|
|
||||||
- '!package-lock.json'
|
|
||||||
- '!yarn.lock'
|
|
||||||
- '!README.md'
|
|
||||||
- '!*.config.js'
|
|
||||||
- '!.git/**'
|
|
||||||
- '!.github/**'
|
|
||||||
|
|
||||||
functions:
|
|
||||||
getHosts:
|
|
||||||
handler: src/modules/host/handlers/host.handler
|
|
||||||
memorySize: 384 # Lower memory for simple GET operations
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/host/handlers/host.*'
|
|
||||||
- 'src/modules/host/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /host
|
|
||||||
method: get
|
|
||||||
|
|
||||||
verifyOtp:
|
|
||||||
handler: src/modules/host/handlers/verifyOtp.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/host/handlers/verifyOtp.*'
|
|
||||||
- 'src/modules/host/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /host/verify-otp
|
|
||||||
method: post
|
|
||||||
|
|
||||||
loginForHost:
|
|
||||||
handler: src/modules/host/handlers/loginForHost.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/host/handlers/loginForHost.*'
|
|
||||||
- 'src/modules/host/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /host/login
|
|
||||||
method: post
|
|
||||||
|
|
||||||
registrationOfHost:
|
|
||||||
handler: src/modules/host/handlers/registration.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/host/handlers/registration.*'
|
|
||||||
- 'src/modules/host/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /host/registration
|
|
||||||
method: post
|
|
||||||
|
|
||||||
createPasswordForHost:
|
|
||||||
handler: src/modules/host/handlers/createPassword.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/host/handlers/createPassword.*'
|
|
||||||
- 'src/modules/host/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /host/create-password
|
|
||||||
method: post
|
|
||||||
|
|
||||||
addPaymentDetailsForHost:
|
|
||||||
handler: src/modules/host/handlers/addPaymentDetails.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/host/handlers/addPaymentDetails.*'
|
|
||||||
- 'src/modules/host/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /host/add-payment-details
|
|
||||||
method: post
|
|
||||||
|
|
||||||
addActivity:
|
|
||||||
handler: src/modules/host/handlers/addActivity.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/host/handlers/addActivity.*'
|
|
||||||
- 'src/modules/host/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /host/add-activity
|
|
||||||
method: post
|
|
||||||
|
|
||||||
getHostById:
|
|
||||||
handler: src/modules/host/handlers/getbyidhandler.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/host/handlers/getbyidhandler.*'
|
|
||||||
- 'src/modules/host/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /host/getById
|
|
||||||
method: get
|
|
||||||
|
|
||||||
getPQQQuestionDetailsById:
|
|
||||||
handler: src/modules/host/handlers/getByIdPQQ.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/host/handlers/getByIdPQQ.*'
|
|
||||||
- 'src/modules/host/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /host/get-pqq-question-details
|
|
||||||
method: get
|
|
||||||
|
|
||||||
getLatestPQQQuestionDetails:
|
|
||||||
handler: src/modules/host/handlers/getLatestQuestionDetailsPQQ.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/host/handlers/getLatestQuestionDetailsPQQ.*'
|
|
||||||
- 'src/modules/host/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /host/get-latest-pqq-question-details
|
|
||||||
method: get
|
|
||||||
|
|
||||||
getActivityTypes:
|
|
||||||
handler: src/modules/host/handlers/getActivity.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/host/handlers/getActivity.*'
|
|
||||||
- 'src/modules/host/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /host/get-activity
|
|
||||||
method: get
|
|
||||||
|
|
||||||
acceptMinglarAgreement:
|
|
||||||
handler: src/modules/host/handlers/acceptAgreement.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/host/handlers/acceptAgreement.*'
|
|
||||||
- 'src/modules/host/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /host/accept-agreement
|
|
||||||
method: patch
|
|
||||||
|
|
||||||
getStepperInfo:
|
|
||||||
handler: src/modules/host/handlers/getStepper.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/host/handlers/getStepper.*'
|
|
||||||
- 'src/common/utils/handlers/safeHandler.*'
|
|
||||||
- 'src/common/database/**'
|
|
||||||
- 'src/modules/host/services/**'
|
|
||||||
- 'common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /stepper
|
|
||||||
method: get
|
|
||||||
|
|
||||||
getSuggestion:
|
|
||||||
handler: src/modules/minglaradmin/handlers/getSuggestion.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/get-suggestion
|
|
||||||
method: get
|
|
||||||
|
|
||||||
minglarRegistration:
|
|
||||||
handler: src/modules/minglaradmin/handlers/registration.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/registration
|
|
||||||
method: post
|
|
||||||
|
|
||||||
minglarLoginForAdmin:
|
|
||||||
handler: src/modules/minglaradmin/handlers/loginForMinglar.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/login
|
|
||||||
method: post
|
|
||||||
|
|
||||||
minglarCreatePassword:
|
|
||||||
handler: src/modules/minglaradmin/handlers/createPassword.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/create-password
|
|
||||||
method: post
|
|
||||||
|
|
||||||
# Functions using AWS SDK - KEEP AS IS with higher memory
|
|
||||||
updateMinglarProfile:
|
|
||||||
handler: src/modules/minglaradmin/handlers/updateProfile.handler
|
|
||||||
memorySize: 512 # Higher memory for AWS SDK operations
|
|
||||||
timeout: 30
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/handlers/updateProfile.*'
|
|
||||||
- 'src/modules/minglaradmin/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
- 'node_modules/@aws-sdk/**'
|
|
||||||
- 'node_modules/@smithy/**'
|
|
||||||
- 'node_modules/tslib/**'
|
|
||||||
- 'node_modules/fast-xml-parser/**'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/update-profile
|
|
||||||
method: patch
|
|
||||||
|
|
||||||
prepopulateTeammate:
|
|
||||||
handler: src/modules/minglaradmin/handlers/prepopulateTeammate.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/prepopulate-Roles
|
|
||||||
method: get
|
|
||||||
|
|
||||||
inviteTeammate:
|
|
||||||
handler: src/modules/minglaradmin/handlers/inviteTeammate.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/invite-teammate
|
|
||||||
method: post
|
|
||||||
|
|
||||||
getAllHostApplication:
|
|
||||||
handler: src/modules/minglaradmin/handlers/getAllHostApplication.handler
|
|
||||||
memorySize: 512 # Higher memory for data-intensive operations
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/get-all-host-applications-am
|
|
||||||
method: get
|
|
||||||
|
|
||||||
getAllOnboardingHostApplications:
|
|
||||||
handler: src/modules/minglaradmin/handlers/getAllOnboardingHosts.handler
|
|
||||||
memorySize: 512 # Higher memory for data-intensive operations
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/get-all-host-applications-admin
|
|
||||||
method: get
|
|
||||||
|
|
||||||
getAllOnboardingHostApplications_New:
|
|
||||||
handler: src/modules/minglaradmin/handlers/getOnboardingNewApplications.handler
|
|
||||||
memorySize: 512 # Higher memory for data-intensive operations
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/get-all-host-applications-admin-new
|
|
||||||
method: get
|
|
||||||
|
|
||||||
getAllInvitationDetails:
|
|
||||||
handler: src/modules/minglaradmin/handlers/getAllInvitationDetails.handler
|
|
||||||
memorySize: 512
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/get-all-invitation-details
|
|
||||||
method: get
|
|
||||||
|
|
||||||
addSuggestion:
|
|
||||||
handler: src/modules/minglaradmin/handlers/addSuggestion.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/add-suggestion
|
|
||||||
method: post
|
|
||||||
|
|
||||||
getAllCoadminAndAMDetails:
|
|
||||||
handler: src/modules/minglaradmin/handlers/getAllCoadminAndAM.handler
|
|
||||||
memorySize: 512
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/get-all-coadmin-and-am-details
|
|
||||||
method: get
|
|
||||||
|
|
||||||
getAllInvitedCoadminAndAMDetails:
|
|
||||||
handler: src/modules/minglaradmin/handlers/getAllInvitedCoadminAndAM.handler
|
|
||||||
memorySize: 512
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/get-all-invited-coadmin-and-am
|
|
||||||
method: get
|
|
||||||
|
|
||||||
getAllBankAndCurrencyDetails:
|
|
||||||
handler: src/modules/prepopulate/handlers/getAllBankDetails.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /prepopulate/get-all-bank-currency-details
|
|
||||||
method: get
|
|
||||||
|
|
||||||
getCityByState:
|
|
||||||
handler: src/modules/prepopulate/handlers/getCityByState.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/prepopulate/handlers/getCityByState.*'
|
|
||||||
- 'src/modules/prepopulate/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /prepopulate/get-city-by-state
|
|
||||||
method: get
|
|
||||||
|
|
||||||
getBranchByBankXid:
|
|
||||||
handler: src/modules/prepopulate/handlers/getBranchByBank.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/prepopulate/handlers/getBranchByBank.*'
|
|
||||||
- 'src/modules/prepopulate/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /prepopulate/get-branch-by-bank
|
|
||||||
method: get
|
|
||||||
|
|
||||||
getAllDocumentCountryStateCityDetails:
|
|
||||||
handler: src/modules/prepopulate/handlers/getAllDocTypeWithCountryState.handler
|
|
||||||
memorySize: 512
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /prepopulate/get-all-doc-country
|
|
||||||
method: get
|
|
||||||
|
|
||||||
getAllPqqQuesAns:
|
|
||||||
handler: src/modules/prepopulate/handlers/getAllPQQQuesWithAns.handler
|
|
||||||
memorySize: 512
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /prepopulate/get-all-pqq-ques-ans
|
|
||||||
method: get
|
|
||||||
|
|
||||||
getFrequenciesOfActivity:
|
|
||||||
handler: src/modules/prepopulate/handlers/getAllFrequencies.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /prepopulate/get-all-Frequencies
|
|
||||||
method: get
|
|
||||||
|
|
||||||
assignAMToHost:
|
|
||||||
handler: src/modules/minglaradmin/handlers/assignAM.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/assign-am-to-host
|
|
||||||
method: patch
|
|
||||||
|
|
||||||
editAgreementDetails:
|
|
||||||
handler: src/modules/minglaradmin/handlers/editAgreementDetails.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/edit-agreement-details
|
|
||||||
method: patch
|
|
||||||
|
|
||||||
acceptHostApplication:
|
|
||||||
handler: src/modules/minglaradmin/handlers/acceptHostApplication.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/accept-host-application
|
|
||||||
method: patch
|
|
||||||
|
|
||||||
acceptHostApplicationMinglar:
|
|
||||||
handler: src/modules/minglaradmin/handlers/acceptHostAppMinglar.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/accept-host-application-minglar
|
|
||||||
method: patch
|
|
||||||
|
|
||||||
rejectHostApplication:
|
|
||||||
handler: src/modules/minglaradmin/handlers/rejectHostApplication.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/reject-host-application
|
|
||||||
method: patch
|
|
||||||
|
|
||||||
rejectHostApplicationAM:
|
|
||||||
handler: src/modules/minglaradmin/handlers/rejectHostApplicationAM.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglaradmin/reject-host-application-am
|
|
||||||
method: patch
|
|
||||||
|
|
||||||
# Functions using AWS SDK and S3 - KEEP AS IS with higher memory
|
|
||||||
addCompanyDetails:
|
|
||||||
handler: src/modules/host/handlers/addCompanyDetails.handler
|
|
||||||
memorySize: 512
|
|
||||||
timeout: 30
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/host/handlers/addCompanyDetails.*'
|
|
||||||
- 'src/modules/host/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
# Only include specific AWS SDK modules needed for S3
|
|
||||||
- 'node_modules/@aws-sdk/client-s3/**'
|
|
||||||
- 'node_modules/@aws-sdk/s3-request-presigner/**'
|
|
||||||
- 'node_modules/@aws-sdk/types/**'
|
|
||||||
- 'node_modules/@aws-sdk/middleware-logger/**'
|
|
||||||
- 'node_modules/@aws-sdk/util-utf8-node/**'
|
|
||||||
- 'node_modules/@aws-sdk/util-utf8-browser/**'
|
|
||||||
- 'node_modules/@smithy/**'
|
|
||||||
- 'node_modules/tslib/**'
|
|
||||||
# Remove these large/unnecessary packages:
|
|
||||||
- 'node_modules/fast-xml-parser/**' # Remove if not used
|
|
||||||
- 'node_modules/lambda-multipart-parser/**' # You're using busboy directly
|
|
||||||
- 'node_modules/busboy/**'
|
|
||||||
# Remove these AWS utility packages (included in main SDK):
|
|
||||||
- 'node_modules/@aws-crypto/**'
|
|
||||||
# - 'node_modules/uuid/**' # AWS SDK includes its own
|
|
||||||
# - 'node_modules/@aws/util-uri-escape/**'
|
|
||||||
# - 'node_modules/@aws/util-middleware/**'
|
|
||||||
- 'node_modules/@aws/smithy-client/**'
|
|
||||||
# - 'node_modules/@aws/lambda-invoke-store/**'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /host/add-company-details
|
|
||||||
method: patch
|
|
||||||
|
|
||||||
submitPqqAnswer:
|
|
||||||
handler: src/modules/host/handlers/submitPqqAns.handler
|
|
||||||
memorySize: 512
|
|
||||||
timeout: 30
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/host/handlers/submitPqqAns.*'
|
|
||||||
- 'src/modules/host/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
- 'node_modules/@aws-sdk/**'
|
|
||||||
- 'node_modules/@smithy/**'
|
|
||||||
- 'node_modules/tslib/**'
|
|
||||||
- 'node_modules/fast-xml-parser/**'
|
|
||||||
- 'node_modules/lambda-multipart-parser/**'
|
|
||||||
- 'node_modules/busboy/**'
|
|
||||||
- 'node_modules/@aws-crypto/**'
|
|
||||||
- 'node_modules/uuid/**'
|
|
||||||
- 'node_modules/@aws/util-uri-escape/**'
|
|
||||||
- 'node_modules/@aws/util-middleware/**'
|
|
||||||
- 'node_modules/@aws/smithy-client/**'
|
|
||||||
- 'node_modules/@aws/lambda-invoke-store/**'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /host/submit-pqq-ans
|
|
||||||
method: patch
|
|
||||||
|
|
||||||
submitFinalPqqAnswer:
|
|
||||||
handler: src/modules/host/handlers/getPQQScore.handler
|
|
||||||
memorySize: 512
|
|
||||||
timeout: 30
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/host/handlers/getPQQScore.*'
|
|
||||||
- 'src/modules/host/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
- 'node_modules/@aws-sdk/**'
|
|
||||||
- 'node_modules/@smithy/**'
|
|
||||||
- 'node_modules/tslib/**'
|
|
||||||
- 'node_modules/fast-xml-parser/**'
|
|
||||||
- 'node_modules/lambda-multipart-parser/**'
|
|
||||||
- 'node_modules/busboy/**'
|
|
||||||
- 'node_modules/@aws-crypto/**'
|
|
||||||
- 'node_modules/uuid/**'
|
|
||||||
- 'node_modules/@aws/util-uri-escape/**'
|
|
||||||
- 'node_modules/@aws/util-middleware/**'
|
|
||||||
- 'node_modules/@aws/smithy-client/**'
|
|
||||||
- 'node_modules/@aws/lambda-invoke-store/**'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /host/submit-final-pqq-ans
|
|
||||||
method: patch
|
|
||||||
|
|
||||||
addPQQSuggestion:
|
|
||||||
handler: src/modules/minglar/handlers/addPQQSuggestion.handler
|
|
||||||
memorySize: 384
|
|
||||||
package:
|
|
||||||
patterns:
|
|
||||||
- 'src/modules/minglaradmin/handlers/addPQQSuggestion.*'
|
|
||||||
- 'src/modules/minglaradmin/services/**'
|
|
||||||
- 'src/common/**'
|
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/**'
|
|
||||||
events:
|
|
||||||
- httpApi:
|
|
||||||
path: /minglar/add-Pqq-suggestion
|
|
||||||
method: post
|
|
||||||
@@ -161,7 +161,7 @@ getPQQ_LastUpdatedQuestion:
|
|||||||
path: /host/Activity_Hub/OnBoarding/get-latest-pqq-question-details
|
path: /host/Activity_Hub/OnBoarding/get-latest-pqq-question-details
|
||||||
method: get
|
method: get
|
||||||
|
|
||||||
getAllActivityType:
|
prePopulateNewActivity:
|
||||||
handler: src/modules/host/handlers/Activity_Hub/OnBoarding/getAllActivityType.handler
|
handler: src/modules/host/handlers/Activity_Hub/OnBoarding/getAllActivityType.handler
|
||||||
memorySize: 384
|
memorySize: 384
|
||||||
package:
|
package:
|
||||||
@@ -174,9 +174,26 @@ getAllActivityType:
|
|||||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||||
events:
|
events:
|
||||||
- httpApi:
|
- httpApi:
|
||||||
path: /host/Activity_Hub/OnBoarding/get-activity-type
|
path: /host/Activity_Hub/OnBoarding/prepopulate-new-activity
|
||||||
method: get
|
method: get
|
||||||
|
|
||||||
|
createNewActivity:
|
||||||
|
handler: src/modules/host/handlers/Activity_Hub/OnBoarding/CreateNewActivity.handler
|
||||||
|
memorySize: 1024
|
||||||
|
timeout: 30
|
||||||
|
package:
|
||||||
|
patterns:
|
||||||
|
- 'src/modules/host/handlers/Activity_Hub/OnBoarding/CreateNewActivity.*'
|
||||||
|
- '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/create-new-activity
|
||||||
|
method: patch
|
||||||
|
|
||||||
showSuggestion:
|
showSuggestion:
|
||||||
handler: src/modules/host/handlers/Host_Admin/onboarding/showSuggestion.handler
|
handler: src/modules/host/handlers/Host_Admin/onboarding/showSuggestion.handler
|
||||||
memorySize: 384
|
memorySize: 384
|
||||||
@@ -253,28 +270,6 @@ submitCompanyDetails:
|
|||||||
- 'src/modules/host/handlers/addCompanyDetails.*'
|
- 'src/modules/host/handlers/addCompanyDetails.*'
|
||||||
- 'src/modules/host/services/**'
|
- 'src/modules/host/services/**'
|
||||||
- 'src/common/**'
|
- 'src/common/**'
|
||||||
- 'node_modules/@prisma/client/**'
|
|
||||||
- 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
|
||||||
# Only include specific AWS SDK modules needed for S3
|
|
||||||
- 'node_modules/@aws-sdk/client-s3/**'
|
|
||||||
- 'node_modules/@aws-sdk/s3-request-presigner/**'
|
|
||||||
- 'node_modules/@aws-sdk/types/**'
|
|
||||||
- 'node_modules/@aws-sdk/middleware-logger/**'
|
|
||||||
- 'node_modules/@aws-sdk/util-utf8-node/**'
|
|
||||||
- 'node_modules/@aws-sdk/util-utf8-browser/**'
|
|
||||||
- 'node_modules/@smithy/**'
|
|
||||||
- 'node_modules/tslib/**'
|
|
||||||
# Remove these large/unnecessary packages:
|
|
||||||
- 'node_modules/fast-xml-parser/**' # Remove if not used
|
|
||||||
- 'node_modules/lambda-multipart-parser/**' # You're using busboy directly
|
|
||||||
- 'node_modules/busboy/**'
|
|
||||||
# Remove these AWS utility packages (included in main SDK):
|
|
||||||
- 'node_modules/@aws-crypto/**'
|
|
||||||
# - 'node_modules/uuid/**' # AWS SDK includes its own
|
|
||||||
# - 'node_modules/@aws/util-uri-escape/**'
|
|
||||||
# - 'node_modules/@aws/util-middleware/**'
|
|
||||||
- 'node_modules/@aws/smithy-client/**'
|
|
||||||
# - 'node_modules/@aws/lambda-invoke-store/**'
|
|
||||||
events:
|
events:
|
||||||
- httpApi:
|
- httpApi:
|
||||||
path: /host/Host_Admin/onboarding/add-company-details
|
path: /host/Host_Admin/onboarding/add-company-details
|
||||||
@@ -291,24 +286,6 @@ submitPQQ_Answer:
|
|||||||
- ${file(./serverless/patterns/base.yml):pattern2}
|
- ${file(./serverless/patterns/base.yml):pattern2}
|
||||||
- ${file(./serverless/patterns/base.yml):pattern3}
|
- ${file(./serverless/patterns/base.yml):pattern3}
|
||||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||||
- 'node_modules/@aws-sdk/client-s3/**'
|
|
||||||
- 'node_modules/@aws-sdk/s3-request-presigner/**'
|
|
||||||
- 'node_modules/@aws-sdk/types/**'
|
|
||||||
- 'node_modules/@aws-sdk/middleware-logger/**'
|
|
||||||
- 'node_modules/@aws-sdk/util-utf8-node/**'
|
|
||||||
- 'node_modules/@aws-sdk/util-utf8-browser/**'
|
|
||||||
- 'node_modules/@smithy/**'
|
|
||||||
- 'node_modules/tslib/**'
|
|
||||||
# Remove these large/unnecessary packages:
|
|
||||||
- 'node_modules/fast-xml-parser/**' # Remove if not used
|
|
||||||
- 'node_modules/lambda-multipart-parser/**' # You're using busboy directly
|
|
||||||
- 'node_modules/busboy/**'
|
|
||||||
# Remove these AWS utility packages (included in main SDK):
|
|
||||||
- 'node_modules/@aws-crypto/**'
|
|
||||||
# - 'node_modules/uuid/**' # AWS SDK includes its own
|
|
||||||
# - 'node_modules/@aws/util-uri-escape/**'
|
|
||||||
# - 'node_modules/@aws/util-middleware/**'
|
|
||||||
- 'node_modules/@aws/smithy-client/**'
|
|
||||||
events:
|
events:
|
||||||
- httpApi:
|
- httpApi:
|
||||||
path: /host/Activity_Hub/OnBoarding/submit-pqq-answer
|
path: /host/Activity_Hub/OnBoarding/submit-pqq-answer
|
||||||
@@ -330,6 +307,23 @@ updatePQQ_LastAnswer:
|
|||||||
path: /host/Activity_Hub/OnBoarding/submit-final-pqq-answer
|
path: /host/Activity_Hub/OnBoarding/submit-final-pqq-answer
|
||||||
method: post
|
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:
|
getAllPQQwithSubmittedAns:
|
||||||
handler: src/modules/host/handlers/Activity_Hub/OnBoarding/getAllPQQwithSubmittedAns.handler
|
handler: src/modules/host/handlers/Activity_Hub/OnBoarding/getAllPQQwithSubmittedAns.handler
|
||||||
memorySize: 512
|
memorySize: 512
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
# Minglar Admin Module Functions
|
# Minglar Admin Module Functions
|
||||||
# Admin dashboard and management endpoints
|
# Admin dashboard and management endpoints
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
minglarRegistration:
|
minglarRegistration:
|
||||||
handler: src/modules/minglaradmin/handlers/registration.handler
|
handler: src/modules/minglaradmin/handlers/registration.handler
|
||||||
memorySize: 384
|
memorySize: 384
|
||||||
@@ -60,22 +58,6 @@ updateMinglarProfile:
|
|||||||
- ${file(./serverless/patterns/base.yml):pattern2}
|
- ${file(./serverless/patterns/base.yml):pattern2}
|
||||||
- ${file(./serverless/patterns/base.yml):pattern3}
|
- ${file(./serverless/patterns/base.yml):pattern3}
|
||||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||||
- ${file(./serverless/patterns/aws-s3.yml):pattern1}
|
|
||||||
- ${file(./serverless/patterns/aws-s3.yml):pattern2}
|
|
||||||
- ${file(./serverless/patterns/aws-s3.yml):pattern3}
|
|
||||||
- ${file(./serverless/patterns/aws-s3.yml):pattern4}
|
|
||||||
- ${file(./serverless/patterns/aws-s3.yml):pattern5}
|
|
||||||
- ${file(./serverless/patterns/aws-s3.yml):pattern6}
|
|
||||||
- ${file(./serverless/patterns/aws-s3.yml):pattern7}
|
|
||||||
- ${file(./serverless/patterns/aws-s3.yml):pattern8}
|
|
||||||
- ${file(./serverless/patterns/aws-s3.yml):pattern9}
|
|
||||||
- ${file(./serverless/patterns/aws-s3.yml):pattern10}
|
|
||||||
- ${file(./serverless/patterns/aws-s3.yml):pattern11}
|
|
||||||
- ${file(./serverless/patterns/aws-s3.yml):pattern12}
|
|
||||||
- ${file(./serverless/patterns/aws-s3.yml):pattern13}
|
|
||||||
- ${file(./serverless/patterns/aws-s3.yml):pattern14}
|
|
||||||
- ${file(./serverless/patterns/aws-s3.yml):pattern15}
|
|
||||||
- ${file(./serverless/patterns/aws-s3.yml):pattern16}
|
|
||||||
events:
|
events:
|
||||||
- httpApi:
|
- httpApi:
|
||||||
path: /minglaradmin/update-profile
|
path: /minglaradmin/update-profile
|
||||||
@@ -96,7 +78,6 @@ prepopulateRole:
|
|||||||
path: /minglaradmin/prepopulate-Roles
|
path: /minglaradmin/prepopulate-Roles
|
||||||
method: get
|
method: get
|
||||||
|
|
||||||
|
|
||||||
getHostDetailsById:
|
getHostDetailsById:
|
||||||
handler: src/modules/minglaradmin/handlers/hosthub/hosts/getByIdHostDetails.handler
|
handler: src/modules/minglaradmin/handlers/hosthub/hosts/getByIdHostDetails.handler
|
||||||
memorySize: 384
|
memorySize: 384
|
||||||
@@ -283,8 +264,8 @@ assignAMToHost:
|
|||||||
path: /minglaradmin/hosthub/onboarding/assign-am
|
path: /minglaradmin/hosthub/onboarding/assign-am
|
||||||
method: patch
|
method: patch
|
||||||
|
|
||||||
editAgreementDetails:
|
editAgreementDetailsAndAccept:
|
||||||
handler: src/modules/minglaradmin/handlers/hosthub/onboarding/editAgreementDetails.handler
|
handler: src/modules/minglaradmin/handlers/hosthub/onboarding/editAgreementDetailsAndAccept.handler
|
||||||
memorySize: 384
|
memorySize: 384
|
||||||
package:
|
package:
|
||||||
patterns:
|
patterns:
|
||||||
@@ -296,9 +277,24 @@ editAgreementDetails:
|
|||||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||||
events:
|
events:
|
||||||
- httpApi:
|
- httpApi:
|
||||||
path: /minglaradmin/hosthub/onboarding/edit-agreement
|
path: /minglaradmin/hosthub/onboarding/edit-agreement-accept-host
|
||||||
method: patch
|
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:
|
acceptHostApplication:
|
||||||
handler: src/modules/minglaradmin/handlers/hosthub/hosts/acceptHostApplication.handler
|
handler: src/modules/minglaradmin/handlers/hosthub/hosts/acceptHostApplication.handler
|
||||||
memorySize: 384
|
memorySize: 384
|
||||||
@@ -328,15 +324,15 @@ RejectPQQByAM:
|
|||||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||||
events:
|
events:
|
||||||
- httpApi:
|
- httpApi:
|
||||||
path: /minglaradmin/hosthub/hosts/reject-pqq-by-am
|
path: /minglaradmin/hosthub/hosts/reject-pq-by-am
|
||||||
method: patch
|
method: patch
|
||||||
|
|
||||||
acceptHostApplicationMinglar:
|
acceptPQByAM:
|
||||||
handler: src/modules/minglaradmin/handlers/hosthub/onboarding/acceptHostAppMinglar.handler
|
handler: src/modules/minglaradmin/handlers/hosthub/hosts/acceptPQByAM.handler
|
||||||
memorySize: 384
|
memorySize: 384
|
||||||
package:
|
package:
|
||||||
patterns:
|
patterns:
|
||||||
- 'src/modules/minglaradmin/handlers/hosthub/onboarding/**'
|
- 'src/modules/minglaradmin/handlers/hosthub/hosts/acceptPQByAM**'
|
||||||
- 'src/modules/minglaradmin/services/**'
|
- 'src/modules/minglaradmin/services/**'
|
||||||
- ${file(./serverless/patterns/base.yml):pattern1}
|
- ${file(./serverless/patterns/base.yml):pattern1}
|
||||||
- ${file(./serverless/patterns/base.yml):pattern2}
|
- ${file(./serverless/patterns/base.yml):pattern2}
|
||||||
@@ -344,7 +340,7 @@ acceptHostApplicationMinglar:
|
|||||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||||
events:
|
events:
|
||||||
- httpApi:
|
- httpApi:
|
||||||
path: /minglaradmin/hosthub/onboarding/accept-host-application-minglar
|
path: /minglaradmin/hosthub/hosts/accept-pq-by-am
|
||||||
method: patch
|
method: patch
|
||||||
|
|
||||||
rejectHostApplication:
|
rejectHostApplication:
|
||||||
@@ -361,7 +357,7 @@ rejectHostApplication:
|
|||||||
events:
|
events:
|
||||||
- httpApi:
|
- httpApi:
|
||||||
path: /minglaradmin/hosthub/onboarding/reject-host-application
|
path: /minglaradmin/hosthub/onboarding/reject-host-application
|
||||||
method: post
|
method: patch
|
||||||
|
|
||||||
rejectHostApplicationAM:
|
rejectHostApplicationAM:
|
||||||
handler: src/modules/minglaradmin/handlers/hosthub/hosts/rejectHostApplicationAM.handler
|
handler: src/modules/minglaradmin/handlers/hosthub/hosts/rejectHostApplicationAM.handler
|
||||||
@@ -377,7 +373,7 @@ rejectHostApplicationAM:
|
|||||||
events:
|
events:
|
||||||
- httpApi:
|
- httpApi:
|
||||||
path: /minglaradmin/hosthub/hosts/reject-host-application-am
|
path: /minglaradmin/hosthub/hosts/reject-host-application-am
|
||||||
method: post
|
method: patch
|
||||||
|
|
||||||
addPQQSuggestion:
|
addPQQSuggestion:
|
||||||
handler: src/modules/minglaradmin/handlers/hosthub/hosts/addPQQSuggestion.handler
|
handler: src/modules/minglaradmin/handlers/hosthub/hosts/addPQQSuggestion.handler
|
||||||
@@ -394,3 +390,36 @@ addPQQSuggestion:
|
|||||||
- httpApi:
|
- httpApi:
|
||||||
path: /minglaradmin/hosthub/hosts/add-Pqq-suggestion
|
path: /minglaradmin/hosthub/hosts/add-Pqq-suggestion
|
||||||
method: post
|
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
|
||||||
|
|
||||||
|
|
||||||
|
getSuggestionsForAM:
|
||||||
|
handler: src/modules/minglaradmin/handlers/hosthub/onboarding/showSuggestionToAM.handler
|
||||||
|
memorySize: 384
|
||||||
|
package:
|
||||||
|
patterns:
|
||||||
|
- 'src/modules/minglaradmin/handlers/hosthub/onboarding/showSuggestionToAM**'
|
||||||
|
- '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/onboarding/show-suggestion-to-am/{hostXid}
|
||||||
|
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
|
||||||
@@ -92,3 +92,18 @@ getFrequenciesOfActivity:
|
|||||||
- httpApi:
|
- httpApi:
|
||||||
path: /prepopulate/get-all-Frequencies
|
path: /prepopulate/get-all-Frequencies
|
||||||
method: get
|
method: get
|
||||||
|
|
||||||
|
getAddActivityPrePopulate:
|
||||||
|
handler: src/modules/prepopulate/handlers/getAddActivityPrePopulate.handler
|
||||||
|
memorySize: 384
|
||||||
|
package:
|
||||||
|
patterns:
|
||||||
|
- 'src/modules/prepopulate/**'
|
||||||
|
- ${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: /prepopulate/get-add-activity-prepopulate
|
||||||
|
method: get
|
||||||
|
|||||||
20
serverless/functions/swagger.yml
Normal file
20
serverless/functions/swagger.yml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Swagger Documentation Functions
|
||||||
|
|
||||||
|
swaggerUi:
|
||||||
|
handler: src/handlers/swagger.swaggerUi
|
||||||
|
memorySize: 256
|
||||||
|
events:
|
||||||
|
- httpApi:
|
||||||
|
path: /api-docs
|
||||||
|
method: get
|
||||||
|
|
||||||
|
swaggerJson:
|
||||||
|
handler: src/handlers/swagger.swaggerJson
|
||||||
|
memorySize: 256
|
||||||
|
package:
|
||||||
|
patterns:
|
||||||
|
- 'swagger.json'
|
||||||
|
events:
|
||||||
|
- httpApi:
|
||||||
|
path: /swagger.json
|
||||||
|
method: get
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
# Base packaging patterns shared across all functions
|
# Base packaging patterns shared across all functions
|
||||||
pattern1: 'src/common/**'
|
pattern1: 'src/common/**'
|
||||||
pattern2: 'common/**'
|
pattern2: 'common/**'
|
||||||
pattern3: 'node_modules/@prisma/client/**'
|
# REMOVED: Prisma is now provided by Lambda layer - DO NOT include in function packages
|
||||||
pattern4: 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
# pattern3: 'node_modules/@prisma/client/**'
|
||||||
|
# pattern4: 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node'
|
||||||
|
pattern3: '!node_modules/@prisma/**'
|
||||||
|
pattern4: '!node_modules/.prisma/**'
|
||||||
pattern5: '!node_modules/.prisma/client/libquery_engine*'
|
pattern5: '!node_modules/.prisma/client/libquery_engine*'
|
||||||
@@ -1,11 +1,29 @@
|
|||||||
import { PrismaClient } from '@prisma/client';
|
import { PrismaClient } from '@prisma/client';
|
||||||
import { PrismaPg } from '@prisma/adapter-pg';
|
import { PrismaPg } from '@prisma/adapter-pg';
|
||||||
|
|
||||||
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
|
// Singleton pattern for Prisma client - prevents "Too many database connections" error
|
||||||
|
const globalForPrisma = globalThis as unknown as {
|
||||||
|
prisma: PrismaClient | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
export const prisma = new PrismaClient({
|
function createPrismaClient() {
|
||||||
|
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
|
||||||
|
|
||||||
|
return new PrismaClient({
|
||||||
adapter,
|
adapter,
|
||||||
log: process.env.NODE_ENV === 'dev' ? ['query', 'info', 'warn', 'error'] : ['error'],
|
log: process.env.NODE_ENV === 'dev' ? ['query', 'info', 'warn', 'error'] : ['error'],
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const prisma = globalForPrisma.prisma ?? createPrismaClient();
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
globalForPrisma.prisma = prisma;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For serverless environments, always cache the client
|
||||||
|
if (process.env.IS_OFFLINE || process.env.AWS_LAMBDA_FUNCTION_NAME) {
|
||||||
|
globalForPrisma.prisma = prisma;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
5
src/common/database/prisma.lambda.service.ts
Normal file
5
src/common/database/prisma.lambda.service.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
// Re-export the singleton prisma client for Lambda handlers
|
||||||
|
// This ensures all Lambda functions use the same cached connection
|
||||||
|
import { prisma } from './prisma.client';
|
||||||
|
|
||||||
|
export const prismaClient = prisma;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Global, Module } from '@nestjs/common';
|
import { Global, Module } from '@nestjs/common';
|
||||||
import { PrismaService } from './prisma.service';
|
import { PrismaService } from './prisma.lambda.service';
|
||||||
|
|
||||||
@Global()
|
@Global()
|
||||||
@Module({
|
@Module({
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
import { Injectable, OnModuleInit, OnModuleDestroy, INestApplication } from '@nestjs/common';
|
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
||||||
import { PrismaClient } from '@prisma/client';
|
import { PrismaClient } from '@prisma/client';
|
||||||
import { PrismaPg } from '@prisma/adapter-pg';
|
import { prisma } from './prisma.client';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
|
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
|
||||||
constructor() {
|
constructor() {
|
||||||
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
|
super();
|
||||||
super({
|
// Use the singleton instance
|
||||||
adapter,
|
Object.assign(this, prisma);
|
||||||
log: process.env.NODE_ENV === 'dev' ? ['query', 'info', 'warn', 'error'] : ['error'],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async onModuleInit() {
|
async onModuleInit() {
|
||||||
@@ -19,10 +17,4 @@ export class PrismaService extends PrismaClient implements OnModuleInit, OnModul
|
|||||||
async onModuleDestroy() {
|
async onModuleDestroy() {
|
||||||
await this.$disconnect();
|
await this.$disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
async enableShutdownHooks(app: INestApplication) {
|
|
||||||
process.on('beforeExit', async () => {
|
|
||||||
await app.close();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -49,6 +49,17 @@ export async function verifyHostToken(token: string): Promise<{ id: number; role
|
|||||||
include: { role: true },
|
include: { role: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const latestToken = await prisma.token.findFirst({
|
||||||
|
where: {
|
||||||
|
userXid: userId
|
||||||
|
},
|
||||||
|
orderBy: { id: 'desc' }
|
||||||
|
})
|
||||||
|
|
||||||
|
if (latestToken.isBlackListed == true) {
|
||||||
|
throw new ApiError(401, "This session is expired. Please login.")
|
||||||
|
}
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new ApiError(httpStatus.UNAUTHORIZED, 'User not found');
|
throw new ApiError(httpStatus.UNAUTHORIZED, 'User not found');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,17 @@ export async function verifyMinglarAdminToken(token: string): Promise<{ id: numb
|
|||||||
include: { role: true },
|
include: { role: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const latestToken = await prisma.token.findFirst({
|
||||||
|
where: {
|
||||||
|
userXid: userId
|
||||||
|
},
|
||||||
|
orderBy: { id: 'desc' }
|
||||||
|
})
|
||||||
|
|
||||||
|
if (latestToken.isBlackListed == true) {
|
||||||
|
throw new ApiError(401, "This session is expired. Please login.")
|
||||||
|
}
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new ApiError(httpStatus.UNAUTHORIZED, 'User not found');
|
throw new ApiError(httpStatus.UNAUTHORIZED, 'User not found');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,17 @@ export async function verifyMinglarAdminHostToken(token: string): Promise<{ id:
|
|||||||
include: { role: true },
|
include: { role: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const latestToken = await prisma.token.findFirst({
|
||||||
|
where: {
|
||||||
|
userXid: userId
|
||||||
|
},
|
||||||
|
orderBy: { id: 'desc' }
|
||||||
|
})
|
||||||
|
|
||||||
|
if (latestToken.isBlackListed == true) {
|
||||||
|
throw new ApiError(401, "This session is expired. Please login.")
|
||||||
|
}
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new ApiError(httpStatus.UNAUTHORIZED, 'User not found');
|
throw new ApiError(httpStatus.UNAUTHORIZED, 'User not found');
|
||||||
}
|
}
|
||||||
@@ -49,6 +49,17 @@ export async function verifyOnlyMinglarAdminToken(token: string): Promise<{ id:
|
|||||||
include: { role: true },
|
include: { role: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const latestToken = await prisma.token.findFirst({
|
||||||
|
where: {
|
||||||
|
userXid: userId
|
||||||
|
},
|
||||||
|
orderBy: { id: 'desc' }
|
||||||
|
})
|
||||||
|
|
||||||
|
if (latestToken.isBlackListed == true) {
|
||||||
|
throw new ApiError(401, "This session is expired. Please login.")
|
||||||
|
}
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new ApiError(httpStatus.UNAUTHORIZED, 'User not found');
|
throw new ApiError(httpStatus.UNAUTHORIZED, 'User not found');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,17 @@ export async function verifyUserToken(token: string): Promise<{ id: number; role
|
|||||||
include: { role: true },
|
include: { role: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const latestToken = await prisma.token.findFirst({
|
||||||
|
where: {
|
||||||
|
userXid: userId
|
||||||
|
},
|
||||||
|
orderBy: { id: 'desc' }
|
||||||
|
})
|
||||||
|
|
||||||
|
if (latestToken.isBlackListed == true) {
|
||||||
|
throw new ApiError(401, "This session is expired. Please login.")
|
||||||
|
}
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new ApiError(httpStatus.UNAUTHORIZED, 'User not found');
|
throw new ApiError(httpStatus.UNAUTHORIZED, 'User not found');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
export const HOST_STATUS_INTERNAL = {
|
export const HOST_STATUS_INTERNAL = {
|
||||||
HOST_SUBMITTED: "Host Submitted",
|
HOST_SUBMITTED: 'Host Submitted',
|
||||||
HOST_TO_UPDATE: "Host To Update",
|
HOST_TO_UPDATE: 'Host To Update',
|
||||||
REJECTED: "Rejected",
|
REJECTED: 'Rejected',
|
||||||
APPROVED: "Approved",
|
APPROVED: 'Approved',
|
||||||
DRAFT: "Draft",
|
DRAFT: 'Draft',
|
||||||
}
|
};
|
||||||
|
|
||||||
export const HOST_STATUS_DISPLAY = {
|
export const HOST_STATUS_DISPLAY = {
|
||||||
DRAFT: "Draft",
|
DRAFT: 'Draft',
|
||||||
UNDER_REVIEW: "Under Review",
|
UNDER_REVIEW: 'Under Review',
|
||||||
ENHANCING: "Enhancing",
|
ENHANCING: 'Enhancing',
|
||||||
REJECTED: "Rejected",
|
REJECTED: 'Rejected',
|
||||||
APPROVED: "Approved",
|
APPROVED: 'Approved',
|
||||||
}
|
};
|
||||||
|
|
||||||
export const STEPPER = {
|
export const STEPPER = {
|
||||||
NOT_SUBMITTED: 1,
|
NOT_SUBMITTED: 1,
|
||||||
@@ -20,12 +20,8 @@ export const STEPPER = {
|
|||||||
COMPANY_DETAILS_APPROVED: 3,
|
COMPANY_DETAILS_APPROVED: 3,
|
||||||
BANK_DETAILS_UPDATED: 4,
|
BANK_DETAILS_UPDATED: 4,
|
||||||
AGREEMENT_ACCEPTED: 5,
|
AGREEMENT_ACCEPTED: 5,
|
||||||
REJECTED: 6
|
REJECTED: 6,
|
||||||
}
|
};
|
||||||
|
|
||||||
export const LAST_QUESTION_ID = {
|
|
||||||
Q_ID: 55
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ACTIVITY_INTERNAL_STATUS = {
|
export const ACTIVITY_INTERNAL_STATUS = {
|
||||||
DRAFT_PQ: 'Draft - PQ',
|
DRAFT_PQ: 'Draft - PQ',
|
||||||
@@ -33,10 +29,19 @@ export const ACTIVITY_INTERNAL_STATUS = {
|
|||||||
REJECTED: 'Rejected',
|
REJECTED: 'Rejected',
|
||||||
DRAFT: 'Draft',
|
DRAFT: 'Draft',
|
||||||
UNDER_REVIEW: 'Under-Review',
|
UNDER_REVIEW: 'Under-Review',
|
||||||
PQQ_FAILED: 'PQQ Failed',
|
PQ_FAILED: 'PQ Failed',
|
||||||
PQQ_TO_UPDATE: 'PQ To Update',
|
PQ_TO_UPDATE: 'PQ To Update',
|
||||||
PQQ_SUBMITTED: 'PQ Submitted'
|
PQ_SUBMITTED: 'PQ Submitted',
|
||||||
}
|
PQ_APPROVED: 'PQ Approved',
|
||||||
|
|
||||||
|
ACTIVITY_DRAFT: 'Draft - Activity',
|
||||||
|
ACTIVITY_SUBMITTED: 'Activity Submitted',
|
||||||
|
ACTIVITY_TO_REVIEW: 'Activity To Review',
|
||||||
|
ACTIVITY_REJECTED: 'Activity Rejected',
|
||||||
|
ACTIVITY_APPROVED: 'Activity Approved',
|
||||||
|
ACTIVITY_LISTED: 'Activity Listed',
|
||||||
|
ACTIVITY_UNLISTED: 'Activity Un Listed By Host',
|
||||||
|
};
|
||||||
|
|
||||||
export const ACTIVITY_DISPLAY_STATUS = {
|
export const ACTIVITY_DISPLAY_STATUS = {
|
||||||
DRAFT_PQ: 'Draft - PQ',
|
DRAFT_PQ: 'Draft - PQ',
|
||||||
@@ -44,10 +49,18 @@ export const ACTIVITY_DISPLAY_STATUS = {
|
|||||||
REJECTED: 'Rejected',
|
REJECTED: 'Rejected',
|
||||||
DRAFT: 'Draft',
|
DRAFT: 'Draft',
|
||||||
UNDER_REVIEW: 'Under-Review',
|
UNDER_REVIEW: 'Under-Review',
|
||||||
PQQ_FAILED: 'PQQ Failed',
|
PQ_FAILED: 'PQ Failed',
|
||||||
ENHANCING: 'Enchancing',
|
ENHANCING: 'Enchancing',
|
||||||
PQ_IN_REVIEW: 'PQ In Review'
|
PQ_IN_REVIEW: 'PQ In Review',
|
||||||
}
|
PQ_APPROVED: 'PQ Approved',
|
||||||
|
|
||||||
|
ACTIVITY_DRAFT: 'Draft - Activity',
|
||||||
|
ACTIVITY_IN_REVIEW: 'In Review',
|
||||||
|
ACTIVITY_TO_REVIEW: 'To Review',
|
||||||
|
ACTIVITY_NOT_LISTED: 'Not Listed',
|
||||||
|
ACTIVITY_LISTED: 'Listed',
|
||||||
|
ACTIVITY_UNLISTED: 'Un Listed',
|
||||||
|
};
|
||||||
|
|
||||||
export const ACTIVITY_AM_INTERNAL_STATUS = {
|
export const ACTIVITY_AM_INTERNAL_STATUS = {
|
||||||
DRAFT_PQ: 'Draft - PQ',
|
DRAFT_PQ: 'Draft - PQ',
|
||||||
@@ -55,10 +68,17 @@ export const ACTIVITY_AM_INTERNAL_STATUS = {
|
|||||||
REJECTED: 'Rejected',
|
REJECTED: 'Rejected',
|
||||||
DRAFT: 'Draft',
|
DRAFT: 'Draft',
|
||||||
UNDER_REVIEW: 'Under-Review',
|
UNDER_REVIEW: 'Under-Review',
|
||||||
PQQ_FAILED: 'PQQ Failed',
|
PQ_FAILED: 'PQ Failed',
|
||||||
PQQ_REJECTED: 'PQ Rejected',
|
PQ_REJECTED: 'PQ Rejected',
|
||||||
PQQ_TO_REVIEW: 'PQ To Review'
|
PQ_TO_REVIEW: 'PQ To Review',
|
||||||
}
|
PQ_APPROVED: 'PQ Approved',
|
||||||
|
|
||||||
|
ACTIVITY_DRAFT: 'Draft - Activity',
|
||||||
|
ACTIVITY_TO_REVIEW: 'Activity To Review',
|
||||||
|
ACTIVITY_REJECTED: 'Activity Rejected',
|
||||||
|
ACTIVITY_APPROVED: 'Activity Approved',
|
||||||
|
ACTIVITY_LISTED: 'Activity Listed',
|
||||||
|
};
|
||||||
|
|
||||||
export const ACTIVITY_AM_DISPLAY_STATUS = {
|
export const ACTIVITY_AM_DISPLAY_STATUS = {
|
||||||
DRAFT_PQ: 'Draft - PQ',
|
DRAFT_PQ: 'Draft - PQ',
|
||||||
@@ -66,7 +86,15 @@ export const ACTIVITY_AM_DISPLAY_STATUS = {
|
|||||||
REJECTED: 'Rejected',
|
REJECTED: 'Rejected',
|
||||||
DRAFT: 'Draft',
|
DRAFT: 'Draft',
|
||||||
UNDER_REVIEW: 'Under-Review',
|
UNDER_REVIEW: 'Under-Review',
|
||||||
PQQ_FAILED: 'PQQ Failed',
|
PQ_FAILED: 'PQ Failed',
|
||||||
ENHANCING: 'Enchancing',
|
ENHANCING: 'Enchancing',
|
||||||
NEW: 'New'
|
NEW: 'New',
|
||||||
}
|
PQ_APPROVED: 'PQ Approved',
|
||||||
|
REVISED: 'Revised',
|
||||||
|
|
||||||
|
ACTIVITY_DRAFT: 'Draft - Activity',
|
||||||
|
ACTIVITY_NEW: 'To Review',
|
||||||
|
ACTIVITY_ENHANCING: 'Enhancing',
|
||||||
|
ACTIVITY_NOT_LISTED: 'Not Listed',
|
||||||
|
ACTIVITY_LISTED: 'Listed',
|
||||||
|
};
|
||||||
|
|||||||
@@ -25,23 +25,38 @@ export const MINGLAR_INVITATION_STATUS = {
|
|||||||
INVITED: 'Invited',
|
INVITED: 'Invited',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const HOST_SUGGESTION_TITLES = {
|
export const ACTIVITY_TRACK_TYPE = {
|
||||||
COMPANY_DETAILS: 'Complete Details',
|
PQ: 'PQ',
|
||||||
COMPANY_DOCUMENTATION: 'Company documentataion',
|
ACTIVITY: 'Activity'
|
||||||
COMPANY_SOCIAL_PROOF: 'Social Proof',
|
}
|
||||||
ACTIVITY_INFORMATION: 'Activity Information',
|
|
||||||
ACTIVITY_LOCATION: 'Activity Location',
|
export const ACTIVITY_TRACK_STATUS = {
|
||||||
PICKUP_DROP_LOCATION: 'Pickup-Drop Location',
|
REJECTED_BY_AM: 'Rejected By AM',
|
||||||
NUMBER_OF_PEOPLE: 'Number of People',
|
ACCEPTED_BY_AM: 'Accepted By AM',
|
||||||
INCLUSION: 'Inclusion',
|
ENHANCING: 'Enhancing',
|
||||||
TAX_SETUP: 'Tax Setup',
|
PQ_SUBMITTED: 'PQ Submitted',
|
||||||
ENERGY_LEVEL: 'Energy Level',
|
UNDER_REVIEW:'Under Review',
|
||||||
ELIGIBILITY_CRITERIA: 'Eligibility Criteria',
|
SUBMITTED:'Activity Submitted',
|
||||||
AMENITIES: 'Amenities',
|
DRAFT:'Activity Draft'
|
||||||
EXLUSIVE_NOTES: 'Exclusive Notes',
|
}
|
||||||
CANCELLATION_POLICY: 'Cancellation Policy',
|
|
||||||
DOs_AND_DONTs: 'Do’s and Dont’s',
|
// export const HOST_SUGGESTION_TITLES = {
|
||||||
TIPS_FOR_USERS: 'Tips for Users',
|
// COMPANY_DETAILS: 'Complete Details',
|
||||||
SUSTAINABILITY: 'Sustainability',
|
// COMPANY_DOCUMENTATION: 'Company documentataion',
|
||||||
TERMS_AND_CONDITION_FOR_USER: 'Terms and Conditions for User'
|
// 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'
|
||||||
|
// };
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ export interface OtpResult {
|
|||||||
export async function resendOtpHelper(
|
export async function resendOtpHelper(
|
||||||
prisma: any,
|
prisma: any,
|
||||||
userId: number,
|
userId: number,
|
||||||
email: string,
|
|
||||||
emailPurpose: "Register" | "Login" | "ForgotPassword",
|
emailPurpose: "Register" | "Login" | "ForgotPassword",
|
||||||
otpLength: 4 | 6 = 4,
|
otpLength: 4 | 6 = 4,
|
||||||
expiryMinutes: number = 5
|
expiryMinutes: number = 5
|
||||||
|
|||||||
@@ -11,11 +11,6 @@ export const hostBankDetailsSchema = z.object({
|
|||||||
.nonempty("Account holder name is required")
|
.nonempty("Account holder name is required")
|
||||||
.min(2, { message: "Account holder name must be at least 2 characters" }),
|
.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
|
bankXid: z
|
||||||
.number()
|
.number()
|
||||||
.int({ message: "Bank ID must be an integer" })
|
.int({ message: "Bank ID must be an integer" })
|
||||||
|
|||||||
@@ -2,31 +2,29 @@ import { z } from "zod";
|
|||||||
|
|
||||||
export const parentCompanySchema = z.object({
|
export const parentCompanySchema = z.object({
|
||||||
companyName: z.string()
|
companyName: z.string()
|
||||||
.min(1, "Parent company name is required")
|
.max(100, "Parent company name cannot exceed 100 characters")
|
||||||
.max(100, "Parent company name cannot exceed 100 characters"),
|
.optional(),
|
||||||
|
|
||||||
address1: z.string()
|
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()
|
address2: z.string()
|
||||||
.max(150, "Address2 cannot exceed 150 characters")
|
.max(150, "Address2 cannot exceed 150 characters")
|
||||||
.optional(),
|
.optional(),
|
||||||
|
|
||||||
cityXid: z.number().min(1, "City is required"),
|
cityXid: z.number().optional(),
|
||||||
stateXid: z.number().min(1, "State is required"),
|
stateXid: z.number().optional(),
|
||||||
countryXid: z.number().min(1, "Country is required"),
|
countryXid: z.number().optional(),
|
||||||
|
|
||||||
pinCode: z.string()
|
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()
|
logoPath: z.string()
|
||||||
.max(400, "Logo path cannot exceed 400 characters")
|
.max(400, "Logo path cannot exceed 400 characters")
|
||||||
.optional(),
|
.optional(),
|
||||||
|
|
||||||
isSubsidairy: z.boolean().optional(),
|
|
||||||
|
|
||||||
registrationNumber: z.string()
|
registrationNumber: z.string()
|
||||||
.max(30, "Registration number cannot exceed 30 characters")
|
.max(30, "Registration number cannot exceed 30 characters")
|
||||||
.optional(),
|
.optional(),
|
||||||
@@ -45,15 +43,15 @@ export const parentCompanySchema = z.object({
|
|||||||
message: "Formation date must be a valid date",
|
message: "Formation date must be a valid date",
|
||||||
}),
|
}),
|
||||||
|
|
||||||
companyType: z.string()
|
companyTypeXid: z.number()
|
||||||
.min(1, "Company type is required")
|
.optional(),
|
||||||
.max(30, "Company type cannot exceed 30 characters"),
|
|
||||||
|
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 +104,20 @@ export const hostCompanyDetailsSchema = z.object({
|
|||||||
message: "Formation date must be a valid date",
|
message: "Formation date must be a valid date",
|
||||||
}),
|
}),
|
||||||
|
|
||||||
companyType: z.string()
|
companyTypeXid: z.number()
|
||||||
.min(1, "Company type is required")
|
.int("Company type must be a valid integer")
|
||||||
.max(30, "Company type cannot exceed 30 characters"),
|
.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(),
|
parentCompany: parentCompanySchema.optional(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -81,6 +81,9 @@ const envVarsSchema = yup
|
|||||||
DB_PORT: yup.number().default(3306).required('DB Port is required'),
|
DB_PORT: yup.number().default(3306).required('DB Port is required'),
|
||||||
//OTP Bypass
|
//OTP Bypass
|
||||||
BYPASS_OTP: yup.boolean().default(false).required('Bypass OTP is required'),
|
BYPASS_OTP: yup.boolean().default(false).required('Bypass OTP is required'),
|
||||||
|
// Email links
|
||||||
|
AM_INVITATION_LINK: yup.string().required('Link to send in AM invitation mail is required'),
|
||||||
|
HOST_LINK: yup.string().required('Link to host panel is required')
|
||||||
})
|
})
|
||||||
.noUnknown(true);
|
.noUnknown(true);
|
||||||
|
|
||||||
@@ -158,6 +161,8 @@ function getConfig() {
|
|||||||
//Minglar admin
|
//Minglar admin
|
||||||
MinglarAdminEmail: envVars.MINGLAR_ADMIN_EMAIL,
|
MinglarAdminEmail: envVars.MINGLAR_ADMIN_EMAIL,
|
||||||
MinglarAdminName: envVars.MINGLAR_ADMIN_NAME,
|
MinglarAdminName: envVars.MINGLAR_ADMIN_NAME,
|
||||||
|
AM_INVITATION_LINK: envVars.AM_INVITATION_LINK,
|
||||||
|
HOST_LINK: envVars.HOST_LINK,
|
||||||
// oneSignal: {
|
// oneSignal: {
|
||||||
// appID: envVars.ONESIGNAL_APPID,
|
// appID: envVars.ONESIGNAL_APPID,
|
||||||
// restApiKey: envVars.ONESIGNAL_REST_APIKEY,
|
// restApiKey: envVars.ONESIGNAL_REST_APIKEY,
|
||||||
|
|||||||
140
src/handlers/swagger.ts
Normal file
140
src/handlers/swagger.ts
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
// src/handlers/swagger.ts
|
||||||
|
// Swagger UI handler for serverless-offline
|
||||||
|
|
||||||
|
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
// Swagger UI HTML template
|
||||||
|
const getSwaggerHtml = (specUrl: string) => `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Minglar API Documentation</title>
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui.css" />
|
||||||
|
<style>
|
||||||
|
html { box-sizing: border-box; overflow-y: scroll; }
|
||||||
|
*, *:before, *:after { box-sizing: inherit; }
|
||||||
|
body { margin: 0; background: #fafafa; }
|
||||||
|
.swagger-ui .topbar { display: none; }
|
||||||
|
.swagger-ui .info { margin: 20px 0; }
|
||||||
|
.swagger-ui .info .title { font-size: 36px; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="swagger-ui"></div>
|
||||||
|
<script src="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui-bundle.js"></script>
|
||||||
|
<script src="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui-standalone-preset.js"></script>
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
const ui = SwaggerUIBundle({
|
||||||
|
url: "/swagger.json",
|
||||||
|
dom_id: '#swagger-ui',
|
||||||
|
deepLinking: true,
|
||||||
|
presets: [
|
||||||
|
SwaggerUIBundle.presets.apis,
|
||||||
|
SwaggerUIStandalonePreset
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
SwaggerUIBundle.plugins.DownloadUrl
|
||||||
|
],
|
||||||
|
layout: "StandaloneLayout",
|
||||||
|
persistAuthorization: true,
|
||||||
|
displayRequestDuration: true,
|
||||||
|
filter: true,
|
||||||
|
showExtensions: true,
|
||||||
|
tryItOutEnabled: true
|
||||||
|
});
|
||||||
|
window.ui = ui;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Handler for Swagger UI HTML page
|
||||||
|
export const swaggerUi = async (
|
||||||
|
event: APIGatewayProxyEvent
|
||||||
|
): Promise<APIGatewayProxyResult> => {
|
||||||
|
const host = event.headers?.Host || event.headers?.host || 'localhost:3000';
|
||||||
|
|
||||||
|
// For serverless-offline, use simple direct URL without stage
|
||||||
|
const specUrl = `/swagger.json`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
statusCode: 200,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/html',
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||||||
|
'Pragma': 'no-cache',
|
||||||
|
'Expires': '0',
|
||||||
|
},
|
||||||
|
body: getSwaggerHtml(specUrl),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handler for swagger.json
|
||||||
|
export const swaggerJson = async (
|
||||||
|
event: APIGatewayProxyEvent
|
||||||
|
): Promise<APIGatewayProxyResult> => {
|
||||||
|
try {
|
||||||
|
// Read swagger.json from project root
|
||||||
|
const swaggerPath = path.join(process.cwd(), 'swagger.json');
|
||||||
|
const swaggerContent = fs.readFileSync(swaggerPath, 'utf8');
|
||||||
|
const swaggerDoc = JSON.parse(swaggerContent);
|
||||||
|
|
||||||
|
// Update server URL dynamically - ALWAYS use root URL without stage
|
||||||
|
const host = event.headers?.Host || event.headers?.host || 'localhost:3000';
|
||||||
|
const protocol = event.headers?.['X-Forwarded-Proto'] || 'http';
|
||||||
|
|
||||||
|
// For local development, use root URL. For AWS, use the full URL with stage only if deployed
|
||||||
|
if (process.env.AWS_LAMBDA_FUNCTION_NAME && process.env.AWS_EXECUTION_ENV) {
|
||||||
|
// Only add stage for actual AWS deployment, not serverless-offline
|
||||||
|
const stage = event.requestContext?.stage;
|
||||||
|
const stagePrefix = stage && stage !== '$default' ? `/${stage}` : '';
|
||||||
|
swaggerDoc.servers = [
|
||||||
|
{
|
||||||
|
url: `${protocol}://${host}${stagePrefix}`,
|
||||||
|
description: 'AWS API Gateway'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
// Local development - no stage prefix
|
||||||
|
swaggerDoc.servers = [
|
||||||
|
{
|
||||||
|
url: `http://${host}`,
|
||||||
|
description: 'Local Development (serverless-offline)'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
statusCode: 200,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
'Access-Control-Allow-Headers': 'Content-Type,Authorization',
|
||||||
|
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||||||
|
'Pragma': 'no-cache',
|
||||||
|
'Expires': '0',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(swaggerDoc, null, 2),
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading swagger.json:', error);
|
||||||
|
return {
|
||||||
|
statusCode: 500,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
error: 'Failed to load swagger.json',
|
||||||
|
message: error instanceof Error ? error.message : 'Unknown error'
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
162
src/modules/host/dto/createActivity.schema.ts
Normal file
162
src/modules/host/dto/createActivity.schema.ts
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
/* ================= MEDIA ================= */
|
||||||
|
export const MediaDto = z.object({
|
||||||
|
mediaType: z.string().optional(), // "image/jpeg", "video/mp4", etc.
|
||||||
|
mediaFileName: z.string(), // S3 file URL
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ================= PRICE =================
|
||||||
|
* ❌ No tax info here; root-level only
|
||||||
|
*/
|
||||||
|
export const PriceDto = z.object({
|
||||||
|
noOfSession: z.number().int().optional().default(1),
|
||||||
|
isPackage: z.boolean().optional().default(false),
|
||||||
|
sessionValidity: z.number().int().optional().default(0),
|
||||||
|
sessionValidityFrequency: z.string().optional().default('Days'),
|
||||||
|
basePrice: z.number().int().optional().default(0),
|
||||||
|
sellPrice: z.number().int(), // required
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ================= VENUE ================= */
|
||||||
|
export const VenueDto = z.object({
|
||||||
|
venueName: z.string(),
|
||||||
|
venueCapacity: z.number().int().optional().default(0),
|
||||||
|
availableSeats: z.number().int().optional().default(0),
|
||||||
|
isMinPeopleReqMandatory: z.boolean().optional().default(false),
|
||||||
|
minPeopleRequired: z.number().int().nullable().optional(),
|
||||||
|
minReqfullfilledBeforeMins: z.number().int().nullable().optional(),
|
||||||
|
venueDescription: z.string().optional(),
|
||||||
|
|
||||||
|
// ✅ new: media per venue (for ActivityVenueArtifacts)
|
||||||
|
media: z.array(MediaDto).optional().default([]),
|
||||||
|
|
||||||
|
// price list per venue
|
||||||
|
prices: z.array(PriceDto).optional().default([]),
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ================= PICKUP / DROP ================= */
|
||||||
|
export const PickupDetailDto = z.object({
|
||||||
|
isPickUp: z.boolean().optional().default(false),
|
||||||
|
locationLat: z.number().nullable().optional(),
|
||||||
|
locationLong: z.number().nullable().optional(),
|
||||||
|
locationAddress: z.string().nullable().optional(),
|
||||||
|
transportBasePrice: z.number().int().optional().default(0),
|
||||||
|
transportTotalPrice: z.number().int().optional().default(0),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const PickupTransportDto = z.object({
|
||||||
|
transportModeXid: z.number().int(),
|
||||||
|
isTransportModeChargeable: z.boolean().optional().default(false),
|
||||||
|
pickupDetails: z.array(PickupDetailDto).optional().default([]),
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ================= EQUIPMENT ================= */
|
||||||
|
export const EquipmentDto = z.object({
|
||||||
|
equipmentName: z.string(),
|
||||||
|
isEquipmentChargeable: z.boolean().optional().default(false),
|
||||||
|
equipmentBasePrice: z.number().int().optional().default(0),
|
||||||
|
equipmentTotalPrice: z.number().int().optional().default(0),
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ================= ELIGIBILITY ================= */
|
||||||
|
export const EligibilityDto = z.object({
|
||||||
|
isAgeRestriction: z.boolean().optional().default(false),
|
||||||
|
ageRestrictionXid: z.number().int().nullable().optional(),
|
||||||
|
|
||||||
|
isWeightRestriction: z.boolean().optional().default(false),
|
||||||
|
weightRestrictionName: z.string().nullable().optional(),
|
||||||
|
weightEntered: z.number().int().nullable().optional(),
|
||||||
|
weightIn: z.string().nullable().optional(),
|
||||||
|
minWeight: z.number().int().nullable().optional(),
|
||||||
|
maxWeight: z.number().int().nullable().optional(),
|
||||||
|
|
||||||
|
isHeightRestriction: z.boolean().optional().default(false),
|
||||||
|
heightRestrictionName: z.string().nullable().optional(),
|
||||||
|
heightEntered: z.number().int().nullable().optional(),
|
||||||
|
heightIn: z.string().nullable().optional(),
|
||||||
|
minHeight: z.number().int().nullable().optional(),
|
||||||
|
maxHeight: z.number().int().nullable().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ================= OTHER DETAILS ================= */
|
||||||
|
export const OtherDetailsDto = z.object({
|
||||||
|
exclusiveNotes: z.string().optional(),
|
||||||
|
dosNotes: z.string().optional(),
|
||||||
|
dontsNotes: z.string().optional(),
|
||||||
|
tipsNotes: z.string().optional(),
|
||||||
|
termsAndCondition: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ================= CREATE ACTIVITY ================= */
|
||||||
|
export const CreateActivityDto = z.object({
|
||||||
|
/* 🔑 REQUIRED */
|
||||||
|
activityXid: z.number().int(),
|
||||||
|
|
||||||
|
/* OPTIONAL CORE */
|
||||||
|
activityTypeXid: z.number().int().optional(),
|
||||||
|
frequenciesXid: z.number().int().nullable().optional(),
|
||||||
|
activityTitle: z.string().optional(),
|
||||||
|
activityDescription: z.string().optional(),
|
||||||
|
|
||||||
|
/* LOCATION */
|
||||||
|
checkInLat: z.number().nullable().optional(),
|
||||||
|
checkInLong: z.number().nullable().optional(),
|
||||||
|
checkInAddress: z.string().nullable().optional(),
|
||||||
|
isCheckOutSame: z.boolean().optional().default(true),
|
||||||
|
checkOutLat: z.number().nullable().optional(),
|
||||||
|
checkOutLong: z.number().nullable().optional(),
|
||||||
|
checkOutAddress: z.string().nullable().optional(),
|
||||||
|
|
||||||
|
/* DURATION / ENERGY */
|
||||||
|
energyLevelXid: z.number().int().nullable().optional(),
|
||||||
|
activityDurationMins: z.number().int().nullable().optional(),
|
||||||
|
durationHours: z.number().int().optional(),
|
||||||
|
durationMins: z.number().int().optional(),
|
||||||
|
|
||||||
|
/* FLAGS */
|
||||||
|
foodAvailable: z.boolean().optional().default(false),
|
||||||
|
foodIsChargeable: z.boolean().optional().default(false),
|
||||||
|
alcoholAvailable: z.boolean().optional().default(false),
|
||||||
|
|
||||||
|
trainerAvailable: z.boolean().optional().default(false),
|
||||||
|
trainerIsChargeable: z.boolean().optional().default(false),
|
||||||
|
|
||||||
|
pickUpDropAvailable: z.boolean().optional().default(false),
|
||||||
|
pickUpDropIsChargeable: z.boolean().optional().default(false),
|
||||||
|
|
||||||
|
inActivityAvailable: z.boolean().optional().default(false),
|
||||||
|
inActivityIsChargeable: z.boolean().optional().default(false),
|
||||||
|
|
||||||
|
equipmentAvailable: z.boolean().optional().default(false),
|
||||||
|
equipmentIsChargeable: z.boolean().optional().default(false),
|
||||||
|
|
||||||
|
cancellationAvailable: z.boolean().optional().default(false),
|
||||||
|
|
||||||
|
/* MONEY / CURRENCY */
|
||||||
|
currencyXid: z.number().int().nullable().optional(),
|
||||||
|
sustainabilityScore: z.number().int().nullable().optional(),
|
||||||
|
safetyScore: z.number().int().nullable().optional(),
|
||||||
|
isInstantBooking: z.boolean().optional().default(false),
|
||||||
|
|
||||||
|
/* 🔥 ROOT-LEVEL TAX (SINGLE SOURCE OF TRUTH) */
|
||||||
|
taxXids: z.array(z.number().int()).optional().default([]),
|
||||||
|
|
||||||
|
/* 🔥 MEDIA ARRAYS */
|
||||||
|
media: z.array(MediaDto).optional().default([]), // Activity-level media
|
||||||
|
venues: z.array(VenueDto).optional().default([]), // Each venue’s media + prices
|
||||||
|
|
||||||
|
/* RELATION ARRAYS */
|
||||||
|
foodTypeIds: z.array(z.number().int()).optional().default([]),
|
||||||
|
cuisineIds: z.array(z.number().int()).optional().default([]),
|
||||||
|
pickupTransports: z.array(PickupTransportDto).optional().default([]),
|
||||||
|
navigationModes: z.array(z.number().int()).optional().default([]),
|
||||||
|
equipments: z.array(EquipmentDto).optional().default([]),
|
||||||
|
amenitiesIds: z.array(z.number().int()).optional().default([]),
|
||||||
|
|
||||||
|
/* EXTRA OBJECTS */
|
||||||
|
eligibility: EligibilityDto.optional(),
|
||||||
|
otherDetails: OtherDetailsDto.optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type CreateActivityInput = z.infer<typeof CreateActivityDto>;
|
||||||
@@ -90,5 +90,6 @@ export class AddPaymentDetailsDTO {
|
|||||||
this.accountHolderName = accountHolderName;
|
this.accountHolderName = accountHolderName;
|
||||||
this.ifscCode = ifscCode;
|
this.ifscCode = ifscCode;
|
||||||
this.hostXid = hostXid;
|
this.hostXid = hostXid;
|
||||||
|
this.currencyXid = currencyXid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,311 @@
|
|||||||
|
import config from '../../../../../config/config';
|
||||||
|
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
||||||
|
import AWS from 'aws-sdk';
|
||||||
|
import Busboy from 'busboy';
|
||||||
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
|
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||||
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
|
import {
|
||||||
|
CreateActivityDto,
|
||||||
|
CreateActivityInput,
|
||||||
|
} from '../../../dto/createActivity.schema';
|
||||||
|
import { HostService } from '../../../services/host.service';
|
||||||
|
|
||||||
|
const hostService = new HostService(prismaClient);
|
||||||
|
const s3 = new AWS.S3({ region: config.aws.region });
|
||||||
|
|
||||||
|
/* ------------------------------- Utilities ------------------------------- */
|
||||||
|
|
||||||
|
function getExtensionFromMime(mimeType: string) {
|
||||||
|
const map: Record<string, string> = {
|
||||||
|
'image/jpeg': 'jpg',
|
||||||
|
'image/png': 'png',
|
||||||
|
'image/webp': 'webp',
|
||||||
|
'video/mp4': 'mp4',
|
||||||
|
'video/quicktime': 'mov',
|
||||||
|
'video/x-msvideo': 'avi',
|
||||||
|
'video/x-matroska': 'mkv',
|
||||||
|
};
|
||||||
|
return map[mimeType] || 'bin';
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeJsonField(fields: any, key: string) {
|
||||||
|
if (!fields[key]) return undefined;
|
||||||
|
if (typeof fields[key] === 'object') return fields[key];
|
||||||
|
|
||||||
|
try {
|
||||||
|
return JSON.parse(fields[key]);
|
||||||
|
} catch {
|
||||||
|
throw new ApiError(400, `Invalid JSON in field: ${key}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------- Handler -------------------------------- */
|
||||||
|
|
||||||
|
export const handler = safeHandler(
|
||||||
|
async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
|
||||||
|
/* 1️⃣ AUTH */
|
||||||
|
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 verifyHostToken(token);
|
||||||
|
|
||||||
|
/* 2️⃣ CONTENT TYPE */
|
||||||
|
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 BUFFER */
|
||||||
|
const bodyBuffer = event.isBase64Encoded
|
||||||
|
? Buffer.from(event.body as string, 'base64')
|
||||||
|
: Buffer.from(event.body as string);
|
||||||
|
|
||||||
|
const fields: Record<string, any> = {};
|
||||||
|
const files: Array<{
|
||||||
|
buffer: Buffer;
|
||||||
|
mimeType: string;
|
||||||
|
fileName: string;
|
||||||
|
fieldName: string;
|
||||||
|
}> = [];
|
||||||
|
|
||||||
|
await new Promise<void>((resolve, reject) => {
|
||||||
|
const bb = Busboy({
|
||||||
|
headers: {
|
||||||
|
...event.headers,
|
||||||
|
'content-type': contentType,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
bb.on('field', (name, value) => {
|
||||||
|
fields[name] = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
bb.on('file', (fieldName, file, info) => {
|
||||||
|
const { filename, mimeType } = info;
|
||||||
|
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 exceeds 5MB limit'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
chunks.push(chunk);
|
||||||
|
});
|
||||||
|
|
||||||
|
file.on('end', () => {
|
||||||
|
if (chunks.length > 0) {
|
||||||
|
files.push({
|
||||||
|
buffer: Buffer.concat(chunks),
|
||||||
|
mimeType: mimeType || 'application/octet-stream',
|
||||||
|
fileName: filename || 'unknown',
|
||||||
|
fieldName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
bb.on('finish', () => resolve());
|
||||||
|
bb.on('error', (err) => reject(new ApiError(400, err.message)));
|
||||||
|
|
||||||
|
bb.end(bodyBuffer);
|
||||||
|
});
|
||||||
|
|
||||||
|
/* 4️⃣ FLAGS */
|
||||||
|
const isDraft = fields.isDraft === 'true' || fields.isDraft === true;
|
||||||
|
|
||||||
|
/* 5️⃣ ACTIVITY PAYLOAD */
|
||||||
|
const activityPayload: any = normalizeJsonField(fields, 'activity');
|
||||||
|
if (!activityPayload) {
|
||||||
|
throw new ApiError(400, 'activity payload is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 6️⃣ NORMALIZE IDS */
|
||||||
|
if (activityPayload.activityXid) {
|
||||||
|
activityPayload.activityXid = Number(activityPayload.activityXid);
|
||||||
|
}
|
||||||
|
|
||||||
|
const numberKeys = [
|
||||||
|
'currencyXid',
|
||||||
|
'energyLevelXid',
|
||||||
|
'activityDurationMins',
|
||||||
|
'activityTypeXid',
|
||||||
|
'frequenciesXid',
|
||||||
|
'trainerTotalAmount',
|
||||||
|
'pickupDropTotalPrice',
|
||||||
|
'navigationModeTotalPrice',
|
||||||
|
'sustainabilityScore',
|
||||||
|
'safetyScore',
|
||||||
|
'checkInLat',
|
||||||
|
'checkInLong',
|
||||||
|
'checkOutLat',
|
||||||
|
'checkOutLong',
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const key of numberKeys) {
|
||||||
|
if (activityPayload[key] !== undefined && activityPayload[key] !== null && activityPayload[key] !== '') {
|
||||||
|
activityPayload[key] = Number(activityPayload[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 7️⃣ NORMALIZE BOOLEANS */
|
||||||
|
const booleanKeys = [
|
||||||
|
'isInstantBooking',
|
||||||
|
'foodAvailable',
|
||||||
|
'foodIsChargeable',
|
||||||
|
'alcoholAvailable',
|
||||||
|
'trainerAvailable',
|
||||||
|
'trainerIsChargeable',
|
||||||
|
'pickUpDropAvailable',
|
||||||
|
'pickUpDropIsChargeable',
|
||||||
|
'inActivityAvailable',
|
||||||
|
'inActivityIsChargeable',
|
||||||
|
'equipmentAvailable',
|
||||||
|
'equipmentIsChargeable',
|
||||||
|
'cancellationAvailable',
|
||||||
|
'isCheckOutSame',
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const key of booleanKeys) {
|
||||||
|
if (activityPayload[key] === 'true') activityPayload[key] = true;
|
||||||
|
if (activityPayload[key] === 'false') activityPayload[key] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 8️⃣ UPLOAD ACTIVITY-LEVEL MEDIA (images/videos) */
|
||||||
|
const uploadedActivityMedia: Array<{ mediaType?: string; mediaFileName: string }> = [];
|
||||||
|
|
||||||
|
for (const file of files.filter(
|
||||||
|
(f) => f.fieldName === 'activityImages' || f.fieldName === 'activityVideos',
|
||||||
|
)) {
|
||||||
|
const s3Key = `ActivityOnboarding/Activity_${activityPayload.activityXid}/Media/${Date.now()}_${file.fileName}`;
|
||||||
|
|
||||||
|
if (s3Key.length > 900) {
|
||||||
|
throw new ApiError(400, 'Generated S3 key too long');
|
||||||
|
}
|
||||||
|
|
||||||
|
await s3
|
||||||
|
.upload({
|
||||||
|
Bucket: config.aws.bucketName,
|
||||||
|
Key: s3Key,
|
||||||
|
Body: file.buffer,
|
||||||
|
ContentType: file.mimeType,
|
||||||
|
ACL: 'private',
|
||||||
|
})
|
||||||
|
.promise();
|
||||||
|
|
||||||
|
uploadedActivityMedia.push({
|
||||||
|
mediaType: file.mimeType,
|
||||||
|
mediaFileName: `https://${config.aws.bucketName}.s3.${config.aws.region}.amazonaws.com/${s3Key}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 🔥 MERGE ACTIVITY MEDIA */
|
||||||
|
const existingMedia = Array.isArray(activityPayload.media)
|
||||||
|
? activityPayload.media
|
||||||
|
: [];
|
||||||
|
activityPayload.media = [...existingMedia, ...uploadedActivityMedia];
|
||||||
|
|
||||||
|
/* 9️⃣ PROCESS VENUE MEDIA UPLOADS */
|
||||||
|
// Group venue files by index: venueImages[0], venueImages[1], etc.
|
||||||
|
const venueFilesMap: Map<number, Array<{ buffer: Buffer; mimeType: string; fileName: string }>> = new Map();
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
// Match patterns like: venueImages[0], venueVideos[1], etc.
|
||||||
|
const match = file.fieldName.match(/^venue(Images|Videos)\[(\d+)\]$/);
|
||||||
|
if (match) {
|
||||||
|
const venueIndex = parseInt(match[2], 10);
|
||||||
|
if (!venueFilesMap.has(venueIndex)) {
|
||||||
|
venueFilesMap.set(venueIndex, []);
|
||||||
|
}
|
||||||
|
venueFilesMap.get(venueIndex)!.push(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload venue files and attach to corresponding venues
|
||||||
|
if (Array.isArray(activityPayload.venues)) {
|
||||||
|
for (let i = 0; i < activityPayload.venues.length; i++) {
|
||||||
|
const venue = activityPayload.venues[i];
|
||||||
|
const venueFiles = venueFilesMap.get(i) || [];
|
||||||
|
|
||||||
|
const uploadedVenueMedia: Array<{ mediaType?: string; mediaFileName: string }> = [];
|
||||||
|
|
||||||
|
for (const file of venueFiles) {
|
||||||
|
const s3Key = `ActivityOnboarding/Activity_${activityPayload.activityXid}/Venue_${i}/Media/${Date.now()}_${file.fileName}`;
|
||||||
|
|
||||||
|
if (s3Key.length > 900) {
|
||||||
|
throw new ApiError(400, 'Generated S3 key too long for venue media');
|
||||||
|
}
|
||||||
|
|
||||||
|
await s3
|
||||||
|
.upload({
|
||||||
|
Bucket: config.aws.bucketName,
|
||||||
|
Key: s3Key,
|
||||||
|
Body: file.buffer,
|
||||||
|
ContentType: file.mimeType,
|
||||||
|
ACL: 'private',
|
||||||
|
})
|
||||||
|
.promise();
|
||||||
|
|
||||||
|
uploadedVenueMedia.push({
|
||||||
|
mediaType: file.mimeType,
|
||||||
|
mediaFileName: `https://${config.aws.bucketName}.s3.${config.aws.region}.amazonaws.com/${s3Key}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge with existing venue media
|
||||||
|
const existingVenueMedia = Array.isArray(venue.media) ? venue.media : [];
|
||||||
|
venue.media = [...existingVenueMedia, ...uploadedVenueMedia];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 🔟 VALIDATION */
|
||||||
|
let parsedDto: CreateActivityInput;
|
||||||
|
|
||||||
|
if (!isDraft) {
|
||||||
|
const parsed = CreateActivityDto.safeParse(activityPayload);
|
||||||
|
if (!parsed.success) {
|
||||||
|
throw new ApiError(
|
||||||
|
400,
|
||||||
|
parsed.error.issues.map((i) => i.message).join(', '),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
parsedDto = parsed.data;
|
||||||
|
} else {
|
||||||
|
parsedDto = activityPayload as CreateActivityInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 1️⃣1️⃣ SAVE ACTIVITY */
|
||||||
|
const createdActivity = await hostService.createOrUpdateActivity(
|
||||||
|
userInfo.id,
|
||||||
|
parsedDto,
|
||||||
|
isDraft,
|
||||||
|
);
|
||||||
|
|
||||||
|
/* 1️⃣2️⃣ RESPONSE */
|
||||||
|
return {
|
||||||
|
statusCode: 200,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
success: true,
|
||||||
|
message: isDraft
|
||||||
|
? 'Activity saved as draft successfully'
|
||||||
|
: 'Activity created successfully',
|
||||||
|
data: createdActivity,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||||
|
import {
|
||||||
|
APIGatewayProxyEvent,
|
||||||
|
APIGatewayProxyResult,
|
||||||
|
Context,
|
||||||
|
} from 'aws-lambda';
|
||||||
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
|
import { HostService } from '../../../services/host.service';
|
||||||
|
|
||||||
|
const hostService = new HostService(prismaClient);
|
||||||
|
|
||||||
|
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,14 +1,13 @@
|
|||||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { HostService } from '../../../services/host.service';
|
import { HostService } from '../../../services/host.service';
|
||||||
import { PrePopulateService } from '../../../../prepopulate/services/prepopulate.service';
|
import { PrePopulateService } from '../../../../prepopulate/services/prepopulate.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const hostService = new HostService(prismaClient);
|
||||||
const hostService = new HostService(prismaService);
|
const prePopulateService = new PrePopulateService(prismaClient);
|
||||||
const prePopulateService = new PrePopulateService(prismaService);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add suggestion handler for host applications
|
* Add suggestion handler for host applications
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { HostService } from '../../../services/host.service';
|
import { HostService } from '../../../services/host.service';
|
||||||
import { string } from 'zod';
|
import { paginationService } from '../../../../../common/utils/pagination/pagination.service';
|
||||||
|
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const hostService = new HostService(prismaClient);
|
||||||
const hostService = new HostService(prismaService);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,11 +28,18 @@ export const handler = safeHandler(async (
|
|||||||
// Verify token and get user info
|
// Verify token and get user info
|
||||||
const userInfo = await verifyHostToken(token);
|
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=)
|
// Read optional search query (supports ?search= or ?q=)
|
||||||
const search = event.queryStringParameters?.search || event.queryStringParameters?.q || undefined;
|
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 {
|
return {
|
||||||
@@ -45,8 +51,7 @@ export const handler = safeHandler(async (
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'Data retrieved successfully',
|
message: 'Data retrieved successfully',
|
||||||
data,
|
...result,
|
||||||
|
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
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 { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { PrePopulateService } from '../../../../prepopulate/services/prepopulate.service';
|
|
||||||
import { HostService } from '../../../services/host.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(prismaClient);
|
||||||
const hostService = new HostService(prismaService);
|
|
||||||
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
@@ -23,7 +20,15 @@ export const handler = safeHandler(async (
|
|||||||
// Authenticate user using the shared authForHost function
|
// Authenticate user using the shared authForHost function
|
||||||
await verifyMinglarAdminHostToken(token);
|
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 {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
|
|||||||
@@ -1,55 +1,42 @@
|
|||||||
import config from '@/config/config';
|
import config from '../../../../../config/config';
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
||||||
import AWS from 'aws-sdk';
|
import AWS from 'aws-sdk';
|
||||||
import Busboy from 'busboy';
|
import Busboy from 'busboy';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { HostService } from '../../../services/host.service';
|
import { HostService } from '../../../services/host.service';
|
||||||
import { LAST_QUESTION_ID } from '@/common/utils/constants/host.constant';
|
|
||||||
|
|
||||||
const prisma = new PrismaService();
|
const hostService = new HostService(prismaClient);
|
||||||
const pqqService = new HostService(prisma);
|
|
||||||
|
|
||||||
const s3 = new AWS.S3({ region: config.aws.region });
|
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 {
|
function getS3KeyFromUrl(url: string): string {
|
||||||
const bucketBaseUrl = `https://${config.aws.bucketName}.s3.${config.aws.region}.amazonaws.com/`;
|
const bucketBaseUrl = `https://${config.aws.bucketName}.s3.${config.aws.region}.amazonaws.com/`;
|
||||||
return url.replace(bucketBaseUrl, '');
|
return url.replace(bucketBaseUrl, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to delete file from S3
|
// Delete file from S3
|
||||||
async function deleteFromS3(s3Key: string): Promise<void> {
|
async function deleteFromS3(s3Key: string): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await s3.deleteObject({
|
await s3.deleteObject({
|
||||||
Bucket: config.aws.bucketName,
|
Bucket: config.aws.bucketName,
|
||||||
Key: s3Key,
|
Key: s3Key,
|
||||||
}).promise();
|
}).promise();
|
||||||
console.log(`✅ File deleted from S3: ${s3Key}`);
|
console.log(`✅ Deleted from S3: ${s3Key}`);
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.error(`❌ Error deleting file from S3: ${s3Key}`, error);
|
console.error(`❌ Failed to delete from S3: ${s3Key}`, err);
|
||||||
// Don't throw error here, continue with upload
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function uploadToS3(buffer: Buffer, mimeType: string, originalName: string, prefix: string, existingUrl?: string): Promise<string> {
|
// Upload new file
|
||||||
let s3Key: string;
|
async function uploadToS3(buffer: Buffer, mimeType: string, originalName: string, prefix: string): Promise<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}`;
|
const uniqueKey = `${crypto.randomUUID()}_${originalName}`;
|
||||||
s3Key = `${prefix}/${uniqueKey}`;
|
const s3Key = `${prefix}/${uniqueKey}`;
|
||||||
}
|
|
||||||
|
|
||||||
// Upload new file (replaces existing if same key)
|
|
||||||
await s3.upload({
|
await s3.upload({
|
||||||
Bucket: config.aws.bucketName,
|
Bucket: config.aws.bucketName,
|
||||||
Key: s3Key,
|
Key: s3Key,
|
||||||
@@ -58,253 +45,160 @@ async function uploadToS3(buffer: Buffer, mimeType: string, originalName: string
|
|||||||
ACL: 'private'
|
ACL: 'private'
|
||||||
}).promise();
|
}).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}`;
|
return `https://${config.aws.bucketName}.s3.${config.aws.region}.amazonaws.com/${s3Key}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
|
export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
|
||||||
try {
|
try {
|
||||||
// 1) Auth
|
// AUTH
|
||||||
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, 'Missing token.');
|
if (!token) throw new ApiError(401, 'Missing token');
|
||||||
|
|
||||||
const user = await verifyHostToken(token);
|
const user = await verifyHostToken(token);
|
||||||
|
|
||||||
// 2) Content-Type check
|
// Content-Type
|
||||||
const contentType = event.headers["content-type"] || event.headers["Content-Type"];
|
const contentType = event.headers["content-type"] || event.headers["Content-Type"];
|
||||||
if (!contentType?.startsWith("multipart/form-data"))
|
if (!contentType?.startsWith("multipart/form-data"))
|
||||||
throw new ApiError(400, "Content-Type must be multipart/form-data");
|
throw new ApiError(400, "Content-Type must be multipart/form-data");
|
||||||
|
|
||||||
if (!event.isBase64Encoded)
|
if (!event.isBase64Encoded) throw new ApiError(400, "Body must be base64 encoded");
|
||||||
throw new ApiError(400, "Body must be base64 encoded");
|
|
||||||
|
|
||||||
const bodyBuffer = Buffer.from(event.body!, "base64");
|
const bodyBuffer = Buffer.from(event.body!, "base64");
|
||||||
|
|
||||||
const fields: any = {};
|
const fields: any = {};
|
||||||
const files: Array<{ buffer: Buffer; mimeType: string; fileName: string; fieldName: string }> = [];
|
const files: Array<{ buffer: Buffer; mimeType: string; fileName: string; fieldName: string }> = [];
|
||||||
|
|
||||||
// 3) Parse multipart data
|
// Parse multipart
|
||||||
await new Promise<void>((resolve, reject) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
const bb = Busboy({ headers: { 'content-type': contentType } });
|
const bb = Busboy({ headers: { 'content-type': contentType } });
|
||||||
|
|
||||||
bb.on('file', (fieldname, file, info) => {
|
bb.on('file', (fieldname, file, info) => {
|
||||||
const { filename, mimeType } = info;
|
const { filename, mimeType } = info;
|
||||||
|
if (!filename) return file.resume();
|
||||||
// Skip if no filename (empty file field)
|
|
||||||
if (!filename) {
|
|
||||||
file.resume();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const chunks: Buffer[] = [];
|
const chunks: Buffer[] = [];
|
||||||
let totalSize = 0;
|
let size = 0;
|
||||||
const MAX_SIZE = 5 * 1024 * 1024; // 5 MB
|
|
||||||
|
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);
|
chunks.push(chunk);
|
||||||
});
|
});
|
||||||
|
|
||||||
file.on('end', () => {
|
file.on('end', () => {
|
||||||
// Only add file if we have data
|
|
||||||
if (chunks.length > 0) {
|
if (chunks.length > 0) {
|
||||||
files.push({
|
files.push({
|
||||||
buffer: Buffer.concat(chunks),
|
buffer: Buffer.concat(chunks),
|
||||||
mimeType,
|
mimeType,
|
||||||
fileName: filename,
|
fileName: filename,
|
||||||
fieldName: fieldname,
|
fieldName: fieldname
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
file.on('error', (err) => {
|
|
||||||
reject(new ApiError(400, `File upload error: ${err.message}`));
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
bb.on('field', (fieldname, val) => {
|
bb.on('field', (fieldname, val) => {
|
||||||
// Handle empty or null values
|
try { fields[fieldname] = JSON.parse(val); }
|
||||||
if (val === '' || val === 'null' || val === 'undefined') {
|
catch { fields[fieldname] = val; }
|
||||||
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}`));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bb.on('close', resolve);
|
||||||
|
bb.on('error', err => reject(new ApiError(400, err.message)));
|
||||||
bb.end(bodyBuffer);
|
bb.end(bodyBuffer);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 4) Extract required fields - only activityXid, pqqQuestionXid, pqqAnswerXid are required
|
// Required fields
|
||||||
const activityXid = Number(fields.activityXid);
|
const activityXid = Number(fields.activityXid);
|
||||||
const pqqQuestionXid = Number(fields.pqqQuestionXid);
|
const pqqQuestionXid = Number(fields.pqqQuestionXid);
|
||||||
const pqqAnswerXid = Number(fields.pqqAnswerXid);
|
const pqqAnswerXid = Number(fields.pqqAnswerXid);
|
||||||
|
|
||||||
// Comments and files are optional
|
|
||||||
const comments = fields.comments || null;
|
const comments = fields.comments || null;
|
||||||
|
|
||||||
// Validate required fields
|
if (!activityXid || !pqqQuestionXid || !pqqAnswerXid)
|
||||||
if (!activityXid || isNaN(activityXid)) throw new ApiError(400, "Valid activityXid is required");
|
throw new ApiError(400, "Missing required fields");
|
||||||
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
|
|
||||||
);
|
|
||||||
|
|
||||||
|
// UPSERT header
|
||||||
|
const existingHeader = await hostService.findHeaderByCompositeKey(activityXid, pqqQuestionXid);
|
||||||
let header;
|
let header;
|
||||||
|
|
||||||
if (existingHeader) {
|
if (existingHeader) {
|
||||||
console.log("🔄 Updating existing PQQ header");
|
header = await hostService.updateHeader(existingHeader.id, pqqAnswerXid, comments);
|
||||||
// Update existing header (comments can be null)
|
|
||||||
header = await pqqService.updateHeader(
|
|
||||||
existingHeader.id,
|
|
||||||
comments
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
console.log("🆕 Creating new PQQ header");
|
header = await hostService.createHeader(activityXid, pqqQuestionXid, pqqAnswerXid, comments);
|
||||||
// Create new header (comments can be null)
|
|
||||||
header = await pqqService.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
|
// Existing supporting files
|
||||||
const existingSupportingFiles = await pqqService.getSupportingFilesByHeaderId(header.id);
|
const existingSupportingFiles = await hostService.getSupportingFilesByHeaderId(header.id);
|
||||||
console.log(`📁 Found ${existingSupportingFiles.length} existing supporting files`);
|
|
||||||
|
|
||||||
// 7) Handle file UPSERT - only if files are provided
|
// Read deletedFiles from frontend
|
||||||
const uploadedFiles: any[] = [];
|
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) {
|
if (files.length > 0) {
|
||||||
console.log("📤 Processing file uploads...");
|
for (const file of files) {
|
||||||
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
|
||||||
const file = files[i];
|
|
||||||
const existingFile = existingSupportingFiles[i] || null;
|
|
||||||
|
|
||||||
const url = await uploadToS3(
|
const url = await uploadToS3(
|
||||||
file.buffer,
|
file.buffer,
|
||||||
file.mimeType,
|
file.mimeType,
|
||||||
file.fileName,
|
file.fileName,
|
||||||
`ActivityOnboarding/supportings/${activityXid}`,
|
`ActivityOnboarding/supportings/${activityXid}`
|
||||||
existingFile ? existingFile.mediaFileName : undefined
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let supporting;
|
const newRec = await hostService.addSupportingFile(header.id, file.mimeType, url);
|
||||||
if (existingFile) {
|
addResults.push(newRec);
|
||||||
// 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}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 9) Prepare response
|
const getAllUpdatedQuestionResponse = await hostService.getAllPQUpdatedResponse(activityXid)
|
||||||
const responseMessage = existingHeader ? "PQQ answer updated successfully" : "PQQ answer submitted successfully";
|
|
||||||
|
// CASE 2 — NO deletion & NO new files => DO NOTHING to existing files
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
headers: {
|
headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" },
|
||||||
"Content-Type": "application/json",
|
|
||||||
"Access-Control-Allow-Origin": "*"
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
message: responseMessage,
|
message: existingHeader ? "PQQ answer updated successfully" : "PQQ answer submitted successfully",
|
||||||
data: {
|
data: {
|
||||||
headerId: header.id,
|
headerId: header.id,
|
||||||
activityXid,
|
activityXid,
|
||||||
pqqQuestionXid,
|
pqqQuestionXid,
|
||||||
pqqAnswerXid,
|
pqqAnswerXid,
|
||||||
comments: comments,
|
comments,
|
||||||
score,
|
score,
|
||||||
files: {
|
getAllUpdatedQuestionResponse
|
||||||
uploaded: uploadedFiles,
|
|
||||||
total: uploadedFiles.length
|
|
||||||
},
|
|
||||||
operation: existingHeader ? 'updated' : 'created',
|
|
||||||
fileOperation: files.length > 0 ?
|
|
||||||
(existingSupportingFiles.length > 0 ? 'replaced' : 'added') :
|
|
||||||
(existingSupportingFiles.length > 0 ? 'removed' : 'unchanged')
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (err: any) {
|
||||||
console.error("❌ Error in submitPqqAnswer:", error);
|
console.error("❌ Error:", err);
|
||||||
throw error;
|
throw err;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
|
import { verifyMinglarAdminHostToken } from '../../../../../common/middlewares/jwt/authForMinglarAdminHost';
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
|
||||||
import { HostService } from '../../../services/host.service';
|
import { HostService } from '../../../services/host.service';
|
||||||
import { verifyMinglarAdminHostToken } from '@/common/middlewares/jwt/authForMinglarAdmin&Host';
|
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const hostService = new HostService(prismaClient);
|
||||||
const hostService = new HostService(prismaService);
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
context?: Context
|
context?: Context
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
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';
|
import { HostService } from '../../../services/host.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const hostService = new HostService(prismaClient);
|
||||||
const hostService = new HostService(prismaService);
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
context?: Context
|
context?: Context
|
||||||
@@ -29,15 +28,18 @@ export const handler = safeHandler(async (
|
|||||||
if (!activity_xid || isNaN(activity_xid)) {
|
if (!activity_xid || isNaN(activity_xid)) {
|
||||||
throw new ApiError(400, "Activity id is required and must be a number.");
|
throw new ApiError(400, "Activity id is required and must be a number.");
|
||||||
}
|
}
|
||||||
|
let result = null;
|
||||||
|
|
||||||
// Fetch user with their HostHeader stepper info
|
// Fetch user with their HostHeader stepper info
|
||||||
const pqqQuestionDetails = await hostService.getLatestQuestionDetailsPQQ(activity_xid);
|
const pqqQuestionDetails = await hostService.getLatestQuestionDetailsPQQ(activity_xid);
|
||||||
|
|
||||||
const result = {
|
if (pqqQuestionDetails) {
|
||||||
|
result = {
|
||||||
pqqQuestionXid: pqqQuestionDetails.pqqQuestionXid,
|
pqqQuestionXid: pqqQuestionDetails.pqqQuestionXid,
|
||||||
pqqAnswerXid: pqqQuestionDetails.pqqAnswerXid,
|
pqqAnswerXid: pqqQuestionDetails.pqqAnswerXid || null,
|
||||||
pqqSubCategoryXid: pqqQuestionDetails.pqqQuestions.pqqSubCategoryXid,
|
pqqSubCategoryXid: pqqQuestionDetails.pqqQuestions.pqqSubCategoryXid || null,
|
||||||
categoryXid: pqqQuestionDetails.pqqQuestions.pqqSubCategories.categoryXid
|
categoryXid: pqqQuestionDetails.pqqQuestions.pqqSubCategories.categoryXid || null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { HostService } from '../../../services/host.service';
|
import { HostService } from '../../../services/host.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const hostService = new HostService(prismaClient);
|
||||||
const hostService = new HostService(prismaService);
|
|
||||||
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
|
|||||||
@@ -0,0 +1,300 @@
|
|||||||
|
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 { 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';
|
||||||
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
|
|
||||||
|
const hostService = new HostService(prismaClient);
|
||||||
|
|
||||||
|
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,40 @@
|
|||||||
|
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||||
|
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
||||||
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
|
import { HostService } from '../../../services/host.service';
|
||||||
|
|
||||||
|
const pqqService = new HostService(prismaClient);
|
||||||
|
|
||||||
|
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,16 +1,15 @@
|
|||||||
import config from '@/config/config';
|
import config from '../../../../../config/config';
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
||||||
import AWS from 'aws-sdk';
|
import AWS from 'aws-sdk';
|
||||||
import Busboy from 'busboy';
|
import Busboy from 'busboy';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { HostService } from '../../../services/host.service';
|
import { HostService } from '../../../services/host.service';
|
||||||
|
|
||||||
const prisma = new PrismaService();
|
const pqqService = new HostService(prismaClient);
|
||||||
const pqqService = new HostService(prisma);
|
|
||||||
|
|
||||||
const s3 = new AWS.S3({ region: config.aws.region });
|
const s3 = new AWS.S3({ region: config.aws.region });
|
||||||
|
|
||||||
@@ -30,34 +29,24 @@ async function deleteFromS3(s3Key: string): Promise<void> {
|
|||||||
console.log(`✅ File deleted from S3: ${s3Key}`);
|
console.log(`✅ File deleted from S3: ${s3Key}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`❌ Error deleting file from S3: ${s3Key}`, 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> {
|
async function uploadToS3(buffer: Buffer, mimeType: string, originalName: string, prefix: string, existingUrl?: string): Promise<string> {
|
||||||
let s3Key: string;
|
// We intentionally do NOT reuse old key. If existingUrl is provided we delete old file and create a new random key.
|
||||||
|
|
||||||
// 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}`;
|
|
||||||
// }
|
|
||||||
if (existingUrl) {
|
if (existingUrl) {
|
||||||
// Delete old file, but DO NOT reuse its name
|
try {
|
||||||
const oldKey = getS3KeyFromUrl(existingUrl);
|
const oldKey = getS3KeyFromUrl(existingUrl);
|
||||||
await deleteFromS3(oldKey);
|
await deleteFromS3(oldKey);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Warning deleting existingUrl before upload', err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new key always
|
|
||||||
const uniqueKey = `${crypto.randomUUID()}_${originalName}`;
|
const uniqueKey = `${crypto.randomUUID()}_${originalName}`;
|
||||||
s3Key = `${prefix}/${uniqueKey}`;
|
const s3Key = `${prefix}/${uniqueKey}`;
|
||||||
|
|
||||||
// Upload new file (replaces existing if same key)
|
|
||||||
await s3.upload({
|
await s3.upload({
|
||||||
Bucket: config.aws.bucketName,
|
Bucket: config.aws.bucketName,
|
||||||
Key: s3Key,
|
Key: s3Key,
|
||||||
@@ -82,7 +71,7 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
|||||||
if (!contentType?.includes("multipart/form-data"))
|
if (!contentType?.includes("multipart/form-data"))
|
||||||
throw new ApiError(400, "Content-Type must be 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
|
const bodyBuffer = event.isBase64Encoded
|
||||||
? Buffer.from(event.body!, "base64")
|
? Buffer.from(event.body!, "base64")
|
||||||
: Buffer.from(event.body!, "binary");
|
: Buffer.from(event.body!, "binary");
|
||||||
@@ -90,7 +79,7 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
|||||||
const fields: any = {};
|
const fields: any = {};
|
||||||
const files: Array<{ buffer: Buffer; mimeType: string; fileName: string; fieldName: string }> = [];
|
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) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
const bb = Busboy({ headers: { 'content-type': contentType } });
|
const bb = Busboy({ headers: { 'content-type': contentType } });
|
||||||
|
|
||||||
@@ -152,41 +141,32 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
|||||||
bb.end();
|
bb.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 4) Extract required fields - only activityXid, pqqQuestionXid, pqqAnswerXid are required
|
// 5) Extract required fields
|
||||||
const activityXid = Number(fields.activityXid);
|
const activityXid = Number(fields.activityXid);
|
||||||
const pqqQuestionXid = Number(fields.pqqQuestionXid);
|
const pqqQuestionXid = Number(fields.pqqQuestionXid);
|
||||||
const pqqAnswerXid = Number(fields.pqqAnswerXid);
|
const pqqAnswerXid = Number(fields.pqqAnswerXid);
|
||||||
|
|
||||||
// Comments and files are optional
|
|
||||||
const comments = fields.comments || null;
|
const comments = fields.comments || null;
|
||||||
|
|
||||||
// Validate required fields
|
|
||||||
if (!activityXid || isNaN(activityXid)) throw new ApiError(400, "Valid activityXid is required");
|
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 || isNaN(pqqQuestionXid)) throw new ApiError(400, "Valid pqqQuestionXid is required");
|
||||||
if (!pqqAnswerXid || isNaN(pqqAnswerXid)) throw new ApiError(400, "Valid pqqAnswerXid is required");
|
if (!pqqAnswerXid || isNaN(pqqAnswerXid)) throw new ApiError(400, "Valid pqqAnswerXid is required");
|
||||||
|
|
||||||
// console.log(`📝 Processing - Activity: ${activityXid}, Question: ${pqqQuestionXid}, Answer: ${pqqAnswerXid}`);
|
// 6) UPSERT header
|
||||||
// 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(
|
const existingHeader = await pqqService.findHeaderByCompositeKey(
|
||||||
activityXid,
|
activityXid,
|
||||||
pqqQuestionXid,
|
pqqQuestionXid,
|
||||||
pqqAnswerXid
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let header;
|
let header;
|
||||||
if (existingHeader) {
|
if (existingHeader) {
|
||||||
console.log("🔄 Updating existing PQQ header");
|
console.log("🔄 Updating existing PQQ header");
|
||||||
// Update existing header (comments can be null)
|
|
||||||
header = await pqqService.updateHeader(
|
header = await pqqService.updateHeader(
|
||||||
existingHeader.id,
|
existingHeader.id,
|
||||||
|
pqqAnswerXid,
|
||||||
comments
|
comments
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log("🆕 Creating new PQQ header");
|
console.log("🆕 Creating new PQQ header");
|
||||||
// Create new header (comments can be null)
|
|
||||||
header = await pqqService.createHeader(
|
header = await pqqService.createHeader(
|
||||||
activityXid,
|
activityXid,
|
||||||
pqqQuestionXid,
|
pqqQuestionXid,
|
||||||
@@ -195,79 +175,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);
|
const existingSupportingFiles = await pqqService.getSupportingFilesByHeaderId(header.id);
|
||||||
console.log(`📁 Found ${existingSupportingFiles.length} existing supporting files`);
|
console.log(`📁 Found ${existingSupportingFiles.length} existing supporting files`);
|
||||||
|
|
||||||
// 7) Handle file UPSERT - only if files are provided
|
// 8) Parse incoming control fields
|
||||||
const uploadedFiles: any[] = [];
|
// 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) {
|
if (files.length > 0) {
|
||||||
console.log("📤 Processing file uploads...");
|
console.log(`📤 Processing ${files.length} uploaded new file(s)`);
|
||||||
|
for (const file of files) {
|
||||||
for (let i = 0; i < files.length; i++) {
|
try {
|
||||||
const file = files[i];
|
|
||||||
const existingFile = existingSupportingFiles[i] || null;
|
|
||||||
|
|
||||||
const url = await uploadToS3(
|
const url = await uploadToS3(
|
||||||
file.buffer,
|
file.buffer,
|
||||||
file.mimeType,
|
file.mimeType,
|
||||||
file.fileName,
|
file.fileName,
|
||||||
`ActivityOnboarding/supportings/${activityXid}`,
|
`ActivityOnboarding/supportings/${activityXid}`
|
||||||
existingFile ? existingFile.mediaFileName : undefined
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let supporting;
|
// create DB record
|
||||||
if (existingFile) {
|
const supporting = await pqqService.addSupportingFile(
|
||||||
// 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,
|
header.id,
|
||||||
file.mimeType,
|
file.mimeType,
|
||||||
url
|
url
|
||||||
);
|
);
|
||||||
console.log(`🆕 Created new supporting file: ${supporting.id}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadedFiles.push(supporting);
|
addedResults.push(supporting);
|
||||||
}
|
console.log(`🆕 Created new supporting file record: ${supporting.id}`);
|
||||||
|
} catch (err: any) {
|
||||||
// 8) Delete any remaining existing files that weren't replaced
|
console.error('❌ Error uploading/creating supporting file', err);
|
||||||
if (existingSupportingFiles.length > files.length) {
|
// push failure result but continue processing other files
|
||||||
const filesToDelete = existingSupportingFiles.slice(files.length);
|
addedResults.push({ success: false, reason: err.message || 'upload/create failed' });
|
||||||
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 {
|
} else {
|
||||||
console.log("📭 No files provided in request");
|
console.log('📭 No new files uploaded 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}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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";
|
const responseMessage = existingHeader ? "PQQ answer updated successfully" : "PQQ answer submitted successfully";
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -284,15 +278,15 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
|||||||
activityXid,
|
activityXid,
|
||||||
pqqQuestionXid,
|
pqqQuestionXid,
|
||||||
pqqAnswerXid,
|
pqqAnswerXid,
|
||||||
comments: comments,
|
comments,
|
||||||
files: {
|
files: {
|
||||||
uploaded: uploadedFiles,
|
added: addedResults,
|
||||||
total: uploadedFiles.length
|
deleted: deletedResults,
|
||||||
|
existingKeptCount: (existingSupportingFiles.length - deletedResults.filter(d => d.success).length)
|
||||||
},
|
},
|
||||||
operation: existingHeader ? 'updated' : 'created',
|
operation: existingHeader ? 'updated' : 'created',
|
||||||
fileOperation: files.length > 0 ?
|
// summary label for UI convenience:
|
||||||
(existingSupportingFiles.length > 0 ? 'replaced' : 'added') :
|
fileOperation: (deletedResults.length > 0 || addedResults.length > 0) ? 'modified' : 'unchanged'
|
||||||
(existingSupportingFiles.length > 0 ? 'removed' : 'unchanged')
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { HostService } from '../../../services/host.service';
|
import { HostService } from '../../../services/host.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const hostService = new HostService(prismaClient);
|
||||||
const hostService = new HostService(prismaService);
|
|
||||||
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { HostService } from '../../../services/host.service';
|
import { HostService } from '../../../services/host.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const hostService = new HostService(prismaClient);
|
||||||
const hostService = new HostService(prismaService);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add suggestion handler for host applications
|
* Add suggestion handler for host applications
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { HostService } from '../../../services/host.service';
|
import { HostService } from '../../../services/host.service';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
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(prismaClient);
|
||||||
const hostService = new HostService(prismaService);
|
|
||||||
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { HostService } from '../../../services/host.service';
|
import { HostService } from '../../../services/host.service';
|
||||||
import { TokenService } from '../../../services/token.service';
|
import { TokenService } from '../../../services/token.service';
|
||||||
import { GetHostLoginResponseDTO } from '../../../dto/host.dto';
|
import { GetHostLoginResponseDTO } from '../../../dto/host.dto';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import * as bcrypt from 'bcryptjs';
|
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const hostService = new HostService(prismaClient);
|
||||||
const hostService = new HostService(prismaService);
|
const tokenService = new TokenService(prismaClient);
|
||||||
const tokenService = new TokenService(prismaService);
|
|
||||||
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
@@ -30,7 +28,9 @@ export const handler = safeHandler(async (
|
|||||||
throw new ApiError(400, 'Email and password are required');
|
throw new ApiError(400, 'Email and password are required');
|
||||||
}
|
}
|
||||||
|
|
||||||
const loginForHost = await hostService.loginForHost(emailAddress, userPassword);
|
const emailToLowerCase = emailAddress.toLowerCase()
|
||||||
|
|
||||||
|
const loginForHost = await hostService.loginForHost(emailToLowerCase, userPassword);
|
||||||
|
|
||||||
if (!loginForHost) {
|
if (!loginForHost) {
|
||||||
throw new ApiError(400, 'Failed to login');
|
throw new ApiError(400, 'Failed to login');
|
||||||
@@ -40,15 +40,6 @@ export const handler = safeHandler(async (
|
|||||||
throw new ApiError(401, 'Invalid credentials');
|
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(
|
const generateTokenForHost = await tokenService.generateAuthToken(
|
||||||
loginForHost.id
|
loginForHost.id
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { MinglarService } from '../../../../minglaradmin/services/minglar.service';
|
import { MinglarService } from '../../../../minglaradmin/services/minglar.service';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarService = new MinglarService(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get suggestions handler
|
* Get suggestions handler
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import * as bcrypt from 'bcryptjs';
|
||||||
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
|
import { ROLE } from '../../../../../common/utils/constants/common.constant';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import * as bcrypt from 'bcryptjs';
|
|
||||||
import { OtpGeneratorSixDigit } from '../../../../../common/utils/helper/OtpGenerator';
|
|
||||||
import { encryptUserId } from '../../../../../common/utils/helper/CodeGenerator';
|
import { encryptUserId } from '../../../../../common/utils/helper/CodeGenerator';
|
||||||
|
import { OtpGeneratorSixDigit } from '../../../../../common/utils/helper/OtpGenerator';
|
||||||
import { HostService } from '../../../services/host.service';
|
import { HostService } from '../../../services/host.service';
|
||||||
import { sendOtpEmailForHost } from '../../../services/sendOTPEmail.service';
|
import { sendOtpEmailForHost } from '@/modules/host/services/sendOTPEmail.service';
|
||||||
import { ROLE } from '../../../../../common/utils/constants/common.constant';
|
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const hostService = new HostService(prismaClient);
|
||||||
const hostService = new HostService(prismaService);
|
|
||||||
|
|
||||||
export async function generateHostRefNumber(tx: any) {
|
export async function generateHostRefNumber(tx: any) {
|
||||||
const lastrecord = await tx.user.findFirst({
|
const lastrecord = await tx.user.findFirst({
|
||||||
@@ -46,10 +45,12 @@ export const handler = safeHandler(async (
|
|||||||
throw new ApiError(400, 'Email is required');
|
throw new ApiError(400, 'Email is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const emailToLowerCase = email.toLowerCase()
|
||||||
|
|
||||||
// Use a single transaction for user creation/lookup and OTP storage
|
// Use a single transaction for user creation/lookup and OTP storage
|
||||||
const transactionResult = await prismaService.$transaction(async (tx) => {
|
const transactionResult = await prismaClient.$transaction(async (tx) => {
|
||||||
const user = await tx.user.findUnique({
|
const user = await tx.user.findUnique({
|
||||||
where: { emailAddress: email },
|
where: { emailAddress: emailToLowerCase },
|
||||||
select: { emailAddress: true, id: true, userPassword: true },
|
select: { emailAddress: true, id: true, userPassword: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -67,7 +68,7 @@ export const handler = safeHandler(async (
|
|||||||
} else {
|
} else {
|
||||||
// create new user record within the transaction
|
// create new user record within the transaction
|
||||||
newUserLocal = await tx.user.create({
|
newUserLocal = await tx.user.create({
|
||||||
data: { emailAddress: email, roleXid: ROLE.HOST, userRefNumber: referenceNumber },
|
data: { emailAddress: emailToLowerCase, roleXid: ROLE.HOST, userRefNumber: referenceNumber },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +103,7 @@ export const handler = safeHandler(async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send OTP email outside the DB transaction
|
// Send OTP email outside the DB transaction
|
||||||
// await sendOtpEmailForHost(transactionResult.newUser.emailAddress, transactionResult.otp);
|
await sendOtpEmailForHost(transactionResult.newUser.emailAddress, transactionResult.otp);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
// modules/host/handlers/addCompanyDetails.ts
|
// modules/host/handlers/addCompanyDetails.ts
|
||||||
import config from '@/config/config';
|
import config from '../../../../../config/config';
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
||||||
import AWS from 'aws-sdk';
|
import AWS from 'aws-sdk';
|
||||||
import Busboy from 'busboy';
|
import Busboy from 'busboy';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import {
|
import {
|
||||||
@@ -15,8 +15,17 @@ import {
|
|||||||
import { HostService } from '../../../services/host.service';
|
import { HostService } from '../../../services/host.service';
|
||||||
import { sendEmailToAM, sendEmailToMinglarAdmin } from '../../../services/sendHostResubmitEmailToAM.service';
|
import { sendEmailToAM, sendEmailToMinglarAdmin } from '../../../services/sendHostResubmitEmailToAM.service';
|
||||||
|
|
||||||
const prisma = new PrismaService();
|
const hostService = new HostService(prismaClient);
|
||||||
const hostService = new HostService(prisma);
|
|
||||||
|
function getExtensionFromMime(mimeType: string) {
|
||||||
|
const map: Record<string, string> = {
|
||||||
|
'image/jpeg': 'jpg',
|
||||||
|
'image/png': 'png',
|
||||||
|
'application/pdf': 'pdf',
|
||||||
|
'image/webp': 'webp',
|
||||||
|
};
|
||||||
|
return map[mimeType] || 'bin';
|
||||||
|
}
|
||||||
|
|
||||||
const s3 = new AWS.S3({
|
const s3 = new AWS.S3({
|
||||||
region: config.aws.region,
|
region: config.aws.region,
|
||||||
@@ -50,6 +59,25 @@ function cleanEmptyStrings(obj: any) {
|
|||||||
return cleaned;
|
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> => {
|
export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@@ -112,6 +140,9 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
|||||||
bb.end();
|
bb.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const deletedFiles = normalizeJsonField(fields, "deletedFiles") || [];
|
||||||
|
const parentDeletedFiles = normalizeJsonField(fields, "parentDeletedFiles") || [];
|
||||||
|
|
||||||
/** 4) Extract and clean isDraft flag */
|
/** 4) Extract and clean isDraft flag */
|
||||||
const isDraft = fields.isDraft === 'true' || fields.isDraft === true;
|
const isDraft = fields.isDraft === 'true' || fields.isDraft === true;
|
||||||
|
|
||||||
@@ -128,13 +159,22 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
companyDetailsRaw.parentCompany &&
|
||||||
|
Object.values(companyDetailsRaw.parentCompany).every(
|
||||||
|
(v) => v === undefined || v === null
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
companyDetailsRaw.parentCompany = null;
|
||||||
|
}
|
||||||
|
|
||||||
/** 6) Profile update if provided */
|
/** 6) Profile update if provided */
|
||||||
if (fields.userProfile) {
|
if (fields.userProfile) {
|
||||||
const userProfileRaw = normalizeJsonField(fields, 'userProfile');
|
const userProfileRaw = normalizeJsonField(fields, 'userProfile');
|
||||||
if (userProfileRaw) {
|
if (userProfileRaw) {
|
||||||
const { firstName, lastName, mobileNumber } = userProfileRaw;
|
const { firstName, lastName, mobileNumber } = userProfileRaw;
|
||||||
|
|
||||||
await prisma.user.update({
|
await prismaClient.user.update({
|
||||||
where: { id: userInfo.id },
|
where: { id: userInfo.id },
|
||||||
data: {
|
data: {
|
||||||
...(firstName && { firstName }),
|
...(firstName && { firstName }),
|
||||||
@@ -178,13 +218,8 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
|||||||
const file = files.find((f) => f.fieldName === doc.fieldName);
|
const file = files.find((f) => f.fieldName === doc.fieldName);
|
||||||
|
|
||||||
// In DRAFT mode → allow missing documents
|
// In DRAFT mode → allow missing documents
|
||||||
if (isDraft && !file) {
|
|
||||||
return { ...doc, file: null };
|
|
||||||
}
|
|
||||||
|
|
||||||
// In FINAL mode → file must exist
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
throw new ApiError(400, `File not found for field: ${doc.fieldName}`);
|
return { ...doc, file: null };
|
||||||
}
|
}
|
||||||
|
|
||||||
return { ...doc, file };
|
return { ...doc, file };
|
||||||
@@ -213,9 +248,65 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
|||||||
parsedParentCompany = parsedCompany.parentCompany || null;
|
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 prismaClient.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 prismaClient.hostParenetDocuments.delete({
|
||||||
|
where: { id }
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`🗑️ Deleted PARENT document ID ${id}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 11) UPLOAD DOCUMENTS */
|
/** 11) UPLOAD DOCUMENTS */
|
||||||
async function uploadToS3(buffer, mimeType, originalName, folderType, documentTypeXid?, fieldName?) {
|
async function uploadToS3(buffer, mimeType, originalName, folderType, documentTypeXid?, fieldName?) {
|
||||||
const ext = originalName.split('.').pop() || 'jpg';
|
// const ext = originalName.split('.').pop() || 'jpg';
|
||||||
|
const ext = getExtensionFromMime(mimeType);
|
||||||
|
|
||||||
let s3Key = '';
|
let s3Key = '';
|
||||||
|
|
||||||
@@ -249,7 +340,7 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
|||||||
/** Upload host docs */
|
/** Upload host docs */
|
||||||
const uploadedHostDocs: Array<any> = [];
|
const uploadedHostDocs: Array<any> = [];
|
||||||
for (const doc of hostDocs) {
|
for (const doc of hostDocs) {
|
||||||
if (isDraft && !doc.file) continue;
|
if (!doc.file) continue;
|
||||||
|
|
||||||
const path = await uploadToS3(
|
const path = await uploadToS3(
|
||||||
doc.file.buffer,
|
doc.file.buffer,
|
||||||
@@ -270,7 +361,7 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
|||||||
/** Upload parent docs */
|
/** Upload parent docs */
|
||||||
const uploadedParentDocs: Array<any> = [];
|
const uploadedParentDocs: Array<any> = [];
|
||||||
for (const doc of parentDocs) {
|
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(
|
const path = await uploadToS3(
|
||||||
doc.file.buffer,
|
doc.file.buffer,
|
||||||
@@ -289,31 +380,67 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise<
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** UPLOAD LOGO (if provided) */
|
/** UPLOAD LOGO (if provided) */
|
||||||
const logoFile = files.find((f) => f.fieldName === 'companyLogo' || f.fieldName === 'companyLogoFile');
|
const logoFile = files.find(
|
||||||
if (logoFile) {
|
(f) => f.fieldName === 'companyLogo' || f.fieldName === 'companyLogoFile'
|
||||||
const logoUrl = await uploadToS3(logoFile.buffer, logoFile.mimeType, logoFile.fileName, 'logo');
|
);
|
||||||
|
|
||||||
|
if (logoFile && logoFile.buffer && logoFile.fileName) {
|
||||||
|
const logoUrl = await uploadToS3(
|
||||||
|
logoFile.buffer,
|
||||||
|
logoFile.mimeType,
|
||||||
|
logoFile.fileName,
|
||||||
|
'logo'
|
||||||
|
);
|
||||||
parsedCompany.logoPath = logoUrl;
|
parsedCompany.logoPath = logoUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** UPLOAD PARENT COMPANY LOGO (if provided) */
|
/** UPLOAD PARENT COMPANY LOGO (if provided) */
|
||||||
const parentLogoFile = files.find((f) => f.fieldName === 'parentCompanyLogo');
|
const parentLogoFile = files.find(
|
||||||
if (parentLogoFile) {
|
(f) => f.fieldName === 'parentCompanyLogo'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (parentLogoFile && parentLogoFile.buffer && parentLogoFile.mimeType) {
|
||||||
|
// 🔒 Only upload when an actual file is present
|
||||||
const parentLogoUrl = await uploadToS3(
|
const parentLogoUrl = await uploadToS3(
|
||||||
parentLogoFile.buffer,
|
parentLogoFile.buffer,
|
||||||
parentLogoFile.mimeType,
|
parentLogoFile.mimeType,
|
||||||
parentLogoFile.fileName,
|
parentLogoFile.fileName, // safe here because it's a real file
|
||||||
'parent_company_logo',
|
'parent_company_logo',
|
||||||
);
|
);
|
||||||
|
|
||||||
if (parsedParentCompany) {
|
if (parsedParentCompany) {
|
||||||
parsedParentCompany.logoPath = parentLogoUrl;
|
parsedParentCompany.logoPath = parentLogoUrl;
|
||||||
} else {
|
} else {
|
||||||
// if no parent object exists yet (drafts or other flows), attach it safely
|
parsedParentCompany = {
|
||||||
parsedParentCompany = parsedParentCompany || {};
|
logoPath: parentLogoUrl,
|
||||||
parsedParentCompany.logoPath = parentLogoUrl;
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parsedCompany.cityXid) {
|
||||||
|
const city = await prismaClient.cities.findUnique({
|
||||||
|
where: { id: Number(parsedCompany.cityXid) }
|
||||||
|
});
|
||||||
|
if (!city) {
|
||||||
|
throw new ApiError(400, `City with ID ${parsedCompany.cityXid} not found`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parsedCompany.isSubsidairy) {
|
||||||
|
const parentDocuments = await hostService.getParentDocumentsByHostId(userInfo.id);
|
||||||
|
if (parentDocuments.length > 0) {
|
||||||
|
for (const doc of parentDocuments) {
|
||||||
|
try {
|
||||||
|
const s3Key = getS3KeyFromUrl(doc.filePath);
|
||||||
|
await deleteFromS3(s3Key);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("S3 delete failed:", doc.filePath, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await hostService.deleteExistingParentRecords(userInfo.id)
|
||||||
|
}
|
||||||
|
|
||||||
/** 12) SAVE / UPDATE HOST ENTRY */
|
/** 12) SAVE / UPDATE HOST ENTRY */
|
||||||
const createdOrUpdated = await hostService.addOrUpdateCompanyDetails(
|
const createdOrUpdated = await hostService.addOrUpdateCompanyDetails(
|
||||||
userInfo.id,
|
userInfo.id,
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { HostService } from '../../../services/host.service';
|
import { HostService } from '../../../services/host.service';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { verifyHostToken } from '@/common/middlewares/jwt/authForHost';
|
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||||
import { hostBankDetailsSchema } from '@/common/utils/validation/host/addPaymentDetails.validation';
|
import { hostBankDetailsSchema } from '../../../../../common/utils/validation/host/addPaymentDetails.validation';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const hostService = new HostService(prismaClient);
|
||||||
const hostService = new HostService(prismaService);
|
|
||||||
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
@@ -33,7 +32,7 @@ export const handler = safeHandler(async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse request body
|
// 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 {
|
try {
|
||||||
body = event.body ? JSON.parse(event.body) : {};
|
body = event.body ? JSON.parse(event.body) : {};
|
||||||
@@ -44,7 +43,7 @@ export const handler = safeHandler(async (
|
|||||||
// ✅ Validate payload using Zod
|
// ✅ Validate payload using Zod
|
||||||
const validationResult = hostBankDetailsSchema.safeParse({
|
const validationResult = hostBankDetailsSchema.safeParse({
|
||||||
...(body as object),
|
...(body as object),
|
||||||
hostXid: host.id, // inject hostId from token (not from user input)
|
hostXid: host.host.id, // inject hostId from token (not from user input)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!validationResult.success) {
|
if (!validationResult.success) {
|
||||||
@@ -54,7 +53,16 @@ export const handler = safeHandler(async (
|
|||||||
|
|
||||||
const validatedData = validationResult.data;
|
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 {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { HostService } from '../../../services/host.service';
|
import { HostService } from '../../../services/host.service';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { TokenService } from '../../../services/token.service';
|
import { TokenService } from '../../../services/token.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const hostService = new HostService(prismaClient);
|
||||||
const hostService = new HostService(prismaService);
|
const tokenService = new TokenService(prismaClient);
|
||||||
const tokenService = new TokenService(prismaService);
|
|
||||||
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
@@ -28,8 +27,10 @@ export const handler = safeHandler(async (
|
|||||||
throw new ApiError(400, 'Email and OTP are required');
|
throw new ApiError(400, 'Email and OTP are required');
|
||||||
}
|
}
|
||||||
|
|
||||||
await hostService.verifyHostOtp(email, otp);
|
const emailToLowerCase = email.toLowerCase();
|
||||||
const user = await hostService.getHostByEmail(email);
|
|
||||||
|
await hostService.verifyHostOtp(emailToLowerCase, otp);
|
||||||
|
const user = await hostService.getHostByEmail(emailToLowerCase);
|
||||||
const generateTokenForHost = await tokenService.generateAuthToken(
|
const generateTokenForHost = await tokenService.generateAuthToken(
|
||||||
user.id
|
user.id
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
||||||
import { PrismaService } from '../../../common/database/prisma.service';
|
import { prismaClient } from '../../../common/database/prisma.lambda.service';
|
||||||
import ApiError from '../../../common/utils/helper/ApiError';
|
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';
|
import { HostService } from '../services/host.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const hostService = new HostService(prismaClient);
|
||||||
const hostService = new HostService(prismaService);
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
context?: Context
|
context?: Context
|
||||||
@@ -26,11 +25,7 @@ export const handler = safeHandler(async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetch user with their HostHeader stepper info
|
// 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');
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
@@ -42,7 +37,8 @@ export const handler = safeHandler(async (
|
|||||||
success: true,
|
success: true,
|
||||||
message: 'Stepper information retrieved successfully',
|
message: 'Stepper information retrieved successfully',
|
||||||
data: {
|
data: {
|
||||||
stepper: host.stepper,
|
stepper: host?.host?.stepper || null,
|
||||||
|
emailAddress: host.user?.emailAddress || null,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { verifyMinglarAdminHostToken } from '@/common/middlewares/jwt/authForMinglarAdmin&Host';
|
import { verifyMinglarAdminHostToken } from '../../../common/middlewares/jwt/authForMinglarAdminHost';
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { PrismaService } from '../../../common/database/prisma.service';
|
import { prismaClient } from '../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../common/utils/helper/ApiError';
|
import ApiError from '../../../common/utils/helper/ApiError';
|
||||||
import { HostService } from '../services/host.service';
|
import { HostService } from '../services/host.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const hostService = new HostService(prismaClient);
|
||||||
const hostService = new HostService(prismaService);
|
|
||||||
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
@@ -14,7 +13,7 @@ export const handler = safeHandler(async (
|
|||||||
): Promise<APIGatewayProxyResult> => {
|
): Promise<APIGatewayProxyResult> => {
|
||||||
// Get host ID from path parameters
|
// Get host ID from path parameters
|
||||||
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) {
|
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.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { PrismaClient } from '@prisma/client';
|
|
||||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
||||||
|
import { prismaClient } from '../../../common/database/prisma.lambda.service';
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
const prisma = prismaClient;
|
||||||
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent
|
event: APIGatewayProxyEvent
|
||||||
@@ -11,7 +11,6 @@ export const handler = safeHandler(async (
|
|||||||
const result = await prisma.hostHeader.findMany({
|
const result = await prisma.hostHeader.findMany({
|
||||||
select: {
|
select: {
|
||||||
hostParent: true,
|
hostParent: true,
|
||||||
hostRefNumber: true,
|
|
||||||
hostStatusDisplay: true,
|
hostStatusDisplay: true,
|
||||||
accountManager: true,
|
accountManager: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda";
|
import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda";
|
||||||
import { PrismaService } from "../../../common/database/prisma.service";
|
import { prismaClient } from "../../../common/database/prisma.lambda.service";
|
||||||
import { safeHandler } from "../../../common/utils/handlers/safeHandler";
|
import { safeHandler } from "../../../common/utils/handlers/safeHandler";
|
||||||
import ApiError from "../../../common/utils/helper/ApiError";
|
import ApiError from "../../../common/utils/helper/ApiError";
|
||||||
import { resendOtpHelper } from "../../../common/utils/helper/resendOtpHelper";
|
import { resendOtpHelper } from "../../../common/utils/helper/resendOtpHelper";
|
||||||
import { resendOtpEmail } from "../services/resendOTPEmail.service";
|
import { resendOtpEmail } from "../services/resendOTPEmail.service";
|
||||||
|
|
||||||
const prisma = new PrismaService();
|
const prisma = prismaClient;
|
||||||
|
|
||||||
// allowed purposes
|
// allowed purposes
|
||||||
const ALLOWED_PURPOSES = ["Register", "Login", "ForgotPassword"] as const;
|
const ALLOWED_PURPOSES = ["Register", "Login", "ForgotPassword"] as const;
|
||||||
@@ -41,9 +41,11 @@ export const handler = safeHandler(
|
|||||||
const email = (body.email || "").trim();
|
const email = (body.email || "").trim();
|
||||||
if (!email) throw new ApiError(400, "Email is required");
|
if (!email) throw new ApiError(400, "Email is required");
|
||||||
|
|
||||||
|
const emailToLowerCase = email.toLowerCase();
|
||||||
|
|
||||||
// find user (you can adapt the isActive / userStatus checks per your rules)
|
// find user (you can adapt the isActive / userStatus checks per your rules)
|
||||||
const user = await prisma.user.findUnique({
|
const user = await prisma.user.findUnique({
|
||||||
where: { emailAddress: email, isActive: true },
|
where: { emailAddress: emailToLowerCase, isActive: true },
|
||||||
select: { id: true, emailAddress: true, role: true },
|
select: { id: true, emailAddress: true, role: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -56,7 +58,6 @@ export const handler = safeHandler(
|
|||||||
const otpResult = await resendOtpHelper(
|
const otpResult = await resendOtpHelper(
|
||||||
prisma,
|
prisma,
|
||||||
user.id,
|
user.id,
|
||||||
user.emailAddress,
|
|
||||||
purpose,
|
purpose,
|
||||||
6, // 6-digit OTP
|
6, // 6-digit OTP
|
||||||
5 // expires in 5 minutes
|
5 // expires in 5 minutes
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -15,8 +15,8 @@ export async function resendOtpEmail(
|
|||||||
const htmlContent = `
|
const htmlContent = `
|
||||||
<p>Dear ${role},</p>
|
<p>Dear ${role},</p>
|
||||||
<p>Your new OTP is: <strong>${otp}</strong></p>
|
<p>Your new OTP is: <strong>${otp}</strong></p>
|
||||||
<p>This code is valid for 5 minutes. Please do not share it with anyone.</p>
|
<p>This code will be valid for the next 5 minutes.</p>
|
||||||
<p>Best regards,<br/>Minglar Team</p>
|
<p>Warm regards,<br/>Minglar Team</p>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -13,9 +13,10 @@ export async function sendOtpEmailForHost(
|
|||||||
|
|
||||||
const htmlContent = `
|
const htmlContent = `
|
||||||
<p>Dear Host,</p>
|
<p>Dear Host,</p>
|
||||||
<p>Your OTP for registration is: <strong>${otp}</strong></p>
|
<p>You’re almost all set! 🎉</p>
|
||||||
<p>This code is valid for 5 minutes. Please do not share it with anyone.</p>
|
<p>Enter <strong>${otp}</strong> to wrap your registration.</p>
|
||||||
<p>Best regards,<br/>Minglar Team</p>
|
<p>This code will be valid for the next 5 minutes.</p>
|
||||||
|
<p>Warm regards,<br/>Minglar Team</p>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { PrismaService } from "../../../common/database/prisma.service";
|
import { PrismaClient } from '@prisma/client';
|
||||||
import jwt, { JwtPayload } from "jsonwebtoken";
|
import jwt, { JwtPayload } from "jsonwebtoken";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import config from "../../../config/config";
|
import config from "../../../config/config";
|
||||||
|
|
||||||
export class TokenService {
|
export class TokenService {
|
||||||
constructor(private readonly prisma: PrismaService = new PrismaService()) {}
|
constructor(private prisma: PrismaClient) { }
|
||||||
|
|
||||||
private generateToken(
|
private generateToken(
|
||||||
user_xid: number,
|
user_xid: number,
|
||||||
@@ -53,6 +53,10 @@ export class TokenService {
|
|||||||
config.jwt.secret
|
config.jwt.secret
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await this.prisma.token.deleteMany({
|
||||||
|
where: { userXid: user_xid }
|
||||||
|
})
|
||||||
|
|
||||||
await this.prisma.token.create({
|
await this.prisma.token.create({
|
||||||
data: {
|
data: {
|
||||||
token: refreshToken.token,
|
token: refreshToken.token,
|
||||||
@@ -100,6 +104,10 @@ export class TokenService {
|
|||||||
config.jwt.secret
|
config.jwt.secret
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await this.prisma.token.deleteMany({
|
||||||
|
where: { userXid: user_xid }
|
||||||
|
})
|
||||||
|
|
||||||
await this.prisma.token.create({
|
await this.prisma.token.create({
|
||||||
data: {
|
data: {
|
||||||
token: refreshToken.token,
|
token: refreshToken.token,
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
|
import { verifyMinglarAdminToken } from '../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
|
import { prismaClient } from '../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
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 ApiError from '../../../common/utils/helper/ApiError';
|
||||||
import { verifyHostToken } from '../../../common/middlewares/jwt/authForHost';
|
import { MinglarService } from '../services/minglar.service';
|
||||||
import { verifyMinglarAdminToken } from '@/common/middlewares/jwt/authForMinglarAdmin';
|
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarService = new MinglarService(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
|
|||||||
@@ -3,14 +3,13 @@ import {
|
|||||||
APIGatewayProxyResult,
|
APIGatewayProxyResult,
|
||||||
Context,
|
Context,
|
||||||
} from 'aws-lambda';
|
} from 'aws-lambda';
|
||||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
import { prismaClient } from '../../../common/database/prisma.lambda.service';
|
||||||
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 { 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(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all host applications handler
|
* Get all host applications handler
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { verifyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForMinglarAdmin';
|
import { verifyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
|
import { sendEmailToHostForApprovedApplication } from '../../../services/approvalMailtoHost.service';
|
||||||
import { MinglarService } from '../../../services/minglar.service';
|
import { MinglarService } from '../../../services/minglar.service';
|
||||||
import { sendEmailToHostForApprovedApplication } from '../../../services/approvalMailtoHost.service'
|
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarService = new MinglarService(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
interface AddSuggestionBody {
|
interface AddSuggestionBody {
|
||||||
hostXid: number;
|
hostXid: number;
|
||||||
@@ -47,8 +46,8 @@ export const handler = safeHandler(async (
|
|||||||
|
|
||||||
// Add suggestion using service
|
// Add suggestion using service
|
||||||
await minglarService.acceptHostApplication(hostXid, userInfo.id);
|
await minglarService.acceptHostApplication(hostXid, userInfo.id);
|
||||||
const hostDetails = await minglarService.getUserDetails(userInfo.id)
|
const hostDetails = await minglarService.getUserDetails(hostXid)
|
||||||
await sendEmailToHostForApprovedApplication(hostDetails.emailAddress)
|
await sendEmailToHostForApprovedApplication(hostDetails.emailAddress, hostDetails.firstName)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { verifyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||||
|
import { MinglarService } from '../../../services/minglar.service';
|
||||||
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
|
import { sendAMPQQAcceptanceMailtoHost } from '../../../../minglaradmin/services/approvalMailtoHost.service';
|
||||||
|
|
||||||
|
const minglarService = new MinglarService(prismaClient);
|
||||||
|
|
||||||
|
interface Body {
|
||||||
|
activityId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Parse request body
|
||||||
|
let body: Body;
|
||||||
|
|
||||||
|
try {
|
||||||
|
body = event.body ? JSON.parse(event.body) : {};
|
||||||
|
} catch (error) {
|
||||||
|
throw new ApiError(400, 'Invalid JSON in request body');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { activityId } = body;
|
||||||
|
|
||||||
|
if (!activityId) {
|
||||||
|
throw new ApiError(400, 'activityId is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
await minglarService.acceptPQByAM(
|
||||||
|
Number(activityId),
|
||||||
|
Number(userInfo.id)
|
||||||
|
);
|
||||||
|
const hostXid = await minglarService.getHostXidByActivityId(activityId)
|
||||||
|
const hostDetails = await minglarService.getUserDetails(hostXid)
|
||||||
|
await sendAMPQQAcceptanceMailtoHost(hostDetails.emailAddress, hostDetails.firstName)
|
||||||
|
|
||||||
|
return {
|
||||||
|
statusCode: 201,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
success: true,
|
||||||
|
message: 'Approved PQ successfully',
|
||||||
|
data: null,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
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 { 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(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
interface AddSuggestionBody {
|
interface AddSuggestionBody {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -34,7 +33,7 @@ export const handler = safeHandler(async (
|
|||||||
const userInfo = await verifyMinglarAdminToken(token);
|
const userInfo = await verifyMinglarAdminToken(token);
|
||||||
|
|
||||||
// Get user details
|
// Get user details
|
||||||
const user = await prismaService.user.findUnique({
|
const user = await prismaClient.user.findUnique({
|
||||||
where: { id: userInfo.id },
|
where: { id: userInfo.id },
|
||||||
select: { id: true, roleXid: true }
|
select: { id: true, roleXid: true }
|
||||||
});
|
});
|
||||||
@@ -67,10 +66,10 @@ export const handler = safeHandler(async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate title is one of the allowed types
|
// Validate title is one of the allowed types
|
||||||
const allowedTitles = Object.values(HOST_SUGGESTION_TITLES);
|
// const allowedTitles = Object.values(HOST_SUGGESTION_TITLES);
|
||||||
if (!allowedTitles.includes(title)) {
|
// if (!allowedTitles.includes(title)) {
|
||||||
throw new ApiError(400, `Invalid title. Allowed values: ${allowedTitles.join(', ')}`);
|
// throw new ApiError(400, `Invalid title. Allowed values: ${allowedTitles.join(', ')}`);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Add suggestion using service
|
// Add suggestion using service
|
||||||
await minglarService.addPqqSuggestion(title, comments, activity_pqq_header_xid,user.id);
|
await minglarService.addPqqSuggestion(title, comments, activity_pqq_header_xid,user.id);
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
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 { 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(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
interface AddSuggestionBody {
|
interface AddSuggestionBody {
|
||||||
hostXid: number;
|
hostXid: number;
|
||||||
title: string;
|
title: string;
|
||||||
comments: string;
|
comments: string;
|
||||||
|
isParent: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,7 +33,7 @@ export const handler = safeHandler(async (
|
|||||||
const userInfo = await verifyMinglarAdminToken(token);
|
const userInfo = await verifyMinglarAdminToken(token);
|
||||||
|
|
||||||
// Get user details
|
// Get user details
|
||||||
const user = await prismaService.user.findUnique({
|
const user = await prismaClient.user.findUnique({
|
||||||
where: { id: userInfo.id },
|
where: { id: userInfo.id },
|
||||||
select: { id: true, roleXid: true }
|
select: { id: true, roleXid: true }
|
||||||
});
|
});
|
||||||
@@ -52,7 +51,7 @@ export const handler = safeHandler(async (
|
|||||||
throw new ApiError(400, 'Invalid JSON in request body');
|
throw new ApiError(400, 'Invalid JSON in request body');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { hostXid, title, comments } = body;
|
const { hostXid, title, comments, isParent } = body;
|
||||||
|
|
||||||
// Validate required fields
|
// Validate required fields
|
||||||
if (!hostXid) {
|
if (!hostXid) {
|
||||||
@@ -68,13 +67,13 @@ export const handler = safeHandler(async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate title is one of the allowed types
|
// Validate title is one of the allowed types
|
||||||
const allowedTitles = Object.values(HOST_SUGGESTION_TITLES);
|
// const allowedTitles = Object.values(HOST_SUGGESTION_TITLES);
|
||||||
if (!allowedTitles.includes(title)) {
|
// if (!allowedTitles.includes(title)) {
|
||||||
throw new ApiError(400, `Invalid title. Allowed values: ${allowedTitles.join(', ')}`);
|
// throw new ApiError(400, `Invalid title. Allowed values: ${allowedTitles.join(', ')}`);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Add suggestion using service
|
// Add suggestion using service
|
||||||
await minglarService.addHostSuggestion(hostXid, title, comments, user.id);
|
await minglarService.addHostSuggestion(hostXid, title, comments, user.id, isParent);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
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 { 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 { paginationService } from '../../../../../common/utils/pagination/pagination.service';
|
||||||
|
import { MinglarService } from '../../../services/minglar.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarService = new MinglarService(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all host applications handler with pagination
|
* Get all host applications handler with pagination
|
||||||
@@ -26,7 +25,7 @@ export const handler = safeHandler(async (
|
|||||||
const userInfo = await verifyMinglarAdminToken(token);
|
const userInfo = await verifyMinglarAdminToken(token);
|
||||||
|
|
||||||
// Get user details including role
|
// Get user details including role
|
||||||
const user = await prismaService.user.findUnique({
|
const user = await prismaClient.user.findUnique({
|
||||||
where: { id: userInfo.id },
|
where: { id: userInfo.id },
|
||||||
select: { id: true, roleXid: true }
|
select: { id: true, roleXid: true }
|
||||||
});
|
});
|
||||||
@@ -43,6 +42,7 @@ export const handler = safeHandler(async (
|
|||||||
// Parse pagination parameters
|
// Parse pagination parameters
|
||||||
const paginationParams = paginationService.getPaginationFromEvent(event);
|
const paginationParams = paginationService.getPaginationFromEvent(event);
|
||||||
const paginationOptions = paginationService.parsePaginationParams(paginationParams);
|
const paginationOptions = paginationService.parsePaginationParams(paginationParams);
|
||||||
|
const applicationStatus = event.queryStringParameters?.applicationStatus || '';
|
||||||
|
|
||||||
// Get paginated host applications
|
// Get paginated host applications
|
||||||
const { data, totalCount } = await minglarService.getAllHostApplications(
|
const { data, totalCount } = await minglarService.getAllHostApplications(
|
||||||
@@ -51,7 +51,8 @@ export const handler = safeHandler(async (
|
|||||||
search,
|
search,
|
||||||
userStatus,
|
userStatus,
|
||||||
paginationOptions,
|
paginationOptions,
|
||||||
roleFilter
|
roleFilter,
|
||||||
|
applicationStatus
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create paginated response
|
// Create paginated response
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import { verifyMinglarAdminHostToken } from '@/common/middlewares/jwt/authForMinglarAdmin&Host';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.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 { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { MinglarService } from '../../../services/minglar.service';
|
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(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import { verifyMinglarAdminToken } from '@/common/middlewares/jwt/authForMinglarAdmin';
|
import { verifyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { MinglarService } from '../../../services/minglar.service';
|
import { MinglarService } from '../../../services/minglar.service';
|
||||||
import { sendAMRejectionMailtoHost } from '../../../services/rejectionMailtoHost.service';
|
import { sendAMRejectionMailtoHost } from '../../../services/rejectionMailtoHost.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarService = new MinglarService(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
interface AddSuggestionBody {
|
interface AddSuggestionBody {
|
||||||
hostXid: number;
|
hostXid: number;
|
||||||
@@ -47,8 +46,8 @@ export const handler = safeHandler(async (
|
|||||||
|
|
||||||
// Add suggestion using service
|
// Add suggestion using service
|
||||||
await minglarService.rejectHostApplicationAM(hostXid, userInfo.id);
|
await minglarService.rejectHostApplicationAM(hostXid, userInfo.id);
|
||||||
const hostDetails = await minglarService.getUserDetails(userInfo.id)
|
const hostDetails = await minglarService.getUserDetails(hostXid)
|
||||||
await sendAMRejectionMailtoHost(hostDetails.emailAddress)
|
await sendAMRejectionMailtoHost(hostDetails.emailAddress, hostDetails.firstName)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
import { verifyMinglarAdminToken } from '@/common/middlewares/jwt/authForMinglarAdmin';
|
|
||||||
import { MinglarService } from '@/modules/minglaradmin/services/minglar.service';
|
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
|
import { verifyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
|
import { MinglarService } from '../../../services/minglar.service';
|
||||||
|
import { sendAMPQQRejectionMailtoHost } from '../../../../minglaradmin/services/rejectionMailtoHost.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarService = new MinglarService(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
interface Body {
|
||||||
|
activityId: number;
|
||||||
|
}
|
||||||
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
@@ -17,10 +21,12 @@ export const handler = safeHandler(async (
|
|||||||
|
|
||||||
const userInfo = await verifyMinglarAdminToken(token);
|
const userInfo = await verifyMinglarAdminToken(token);
|
||||||
|
|
||||||
let body: any = {};
|
// Parse request body
|
||||||
|
let body: Body;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
body = event.body ? JSON.parse(event.body) : {};
|
body = event.body ? JSON.parse(event.body) : {};
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
throw new ApiError(400, 'Invalid JSON in request body');
|
throw new ApiError(400, 'Invalid JSON in request body');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +38,11 @@ export const handler = safeHandler(async (
|
|||||||
|
|
||||||
await minglarService.rejectPQQbyAM(
|
await minglarService.rejectPQQbyAM(
|
||||||
Number(activityId),
|
Number(activityId),
|
||||||
|
Number(userInfo.id)
|
||||||
);
|
);
|
||||||
|
const hostXid = await minglarService.getHostXidByActivityId(activityId)
|
||||||
|
const hostDetails = await minglarService.getUserDetails(hostXid)
|
||||||
|
await sendAMPQQRejectionMailtoHost(hostDetails.emailAddress, hostDetails.firstName)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 201,
|
statusCode: 201,
|
||||||
@@ -42,7 +52,7 @@ export const handler = safeHandler(async (
|
|||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'Rejected successfully',
|
message: 'Rejected PQ successfully',
|
||||||
data: null,
|
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,15 +3,13 @@ import {
|
|||||||
APIGatewayProxyResult,
|
APIGatewayProxyResult,
|
||||||
Context,
|
Context,
|
||||||
} from 'aws-lambda';
|
} from 'aws-lambda';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
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 { 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(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
interface assignAMToHostBody {
|
interface assignAMToHostBody {
|
||||||
host_xid: number;
|
host_xid: number;
|
||||||
@@ -41,7 +39,7 @@ export const handler = safeHandler(
|
|||||||
const userInfo = await verifyOnlyMinglarAdminToken(token);
|
const userInfo = await verifyOnlyMinglarAdminToken(token);
|
||||||
|
|
||||||
// Get user details including role
|
// Get user details including role
|
||||||
const user = await prismaService.user.findUnique({
|
const user = await prismaClient.user.findUnique({
|
||||||
where: { id: userInfo.id },
|
where: { id: userInfo.id },
|
||||||
select: { id: true, roleXid: true },
|
select: { id: true, roleXid: true },
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin';
|
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 { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { MinglarService } from '../../../services/minglar.service';
|
import { MinglarService } from '../../../services/minglar.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarService = new MinglarService(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
interface assignAMToHostBody {
|
interface assignAMToHostBody {
|
||||||
host_xid: number,
|
host_xid: number,
|
||||||
@@ -34,7 +33,7 @@ export const handler = safeHandler(async (
|
|||||||
const userInfo = await verifyOnlyMinglarAdminToken(token);
|
const userInfo = await verifyOnlyMinglarAdminToken(token);
|
||||||
|
|
||||||
// Get user details including role
|
// Get user details including role
|
||||||
const user = await prismaService.user.findUnique({
|
const user = await prismaClient.user.findUnique({
|
||||||
where: { id: userInfo.id },
|
where: { id: userInfo.id },
|
||||||
select: { id: true, roleXid: true }
|
select: { id: true, roleXid: true }
|
||||||
});
|
});
|
||||||
@@ -64,8 +63,9 @@ export const handler = safeHandler(async (
|
|||||||
payoutDurationFrequency
|
payoutDurationFrequency
|
||||||
} = body;
|
} = body;
|
||||||
|
|
||||||
await minglarService.editAgreementDetails(
|
await minglarService.acceptHostApplicationMinglarAdmin(
|
||||||
host_xid,
|
host_xid,
|
||||||
|
userInfo.id,
|
||||||
agreementStartDate,
|
agreementStartDate,
|
||||||
duration,
|
duration,
|
||||||
isCommisionBase,
|
isCommisionBase,
|
||||||
@@ -73,8 +73,8 @@ export const handler = safeHandler(async (
|
|||||||
amountPerBooking,
|
amountPerBooking,
|
||||||
durationFrequency,
|
durationFrequency,
|
||||||
payoutDurationNum,
|
payoutDurationNum,
|
||||||
payoutDurationFrequency
|
payoutDurationFrequency);
|
||||||
);
|
// await sendEmailToHostForMinglarApproval(hostDetails.emailAddress)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
import { verifyMinglarAdminToken } from '@/common/middlewares/jwt/authForMinglarAdmin';
|
import { verifyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { PrePopulateService } from '../../../../prepopulate/services/prepopulate.service';
|
import { PrePopulateService } from '../../../../prepopulate/services/prepopulate.service';
|
||||||
import { MinglarService } from '../../../services/minglar.service';
|
import { MinglarService } from '../../../services/minglar.service';
|
||||||
|
import { paginationService } from '../../../../../common/utils/pagination/pagination.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarService = new MinglarService(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
const prePopulateService = new PrePopulateService(prismaClient);
|
||||||
const prePopulateService = new PrePopulateService(prismaService);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add suggestion handler for host applications
|
* Add suggestion handler for host applications
|
||||||
@@ -30,11 +30,18 @@ export const handler = safeHandler(async (
|
|||||||
|
|
||||||
const hostXid = Number(event.pathParameters?.id)
|
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=)
|
// Read optional search query (supports ?search= or ?q=)
|
||||||
const search = event.queryStringParameters?.search || event.queryStringParameters?.q || undefined;
|
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 {
|
return {
|
||||||
@@ -46,7 +53,7 @@ export const handler = safeHandler(async (
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'Data retrieved successfully',
|
message: 'Data retrieved successfully',
|
||||||
data,
|
...result,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,42 +1,73 @@
|
|||||||
import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin';
|
import { verifyOnlyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import {
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
APIGatewayProxyEvent,
|
||||||
|
APIGatewayProxyResult,
|
||||||
|
Context,
|
||||||
|
} from 'aws-lambda';
|
||||||
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
|
import { paginationService } from '../../../../../common/utils/pagination/pagination.service';
|
||||||
import { MinglarService } from '../../../services/minglar.service';
|
import { MinglarService } from '../../../services/minglar.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarService = new MinglarService(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all host applications handler
|
* Get all host applications handler
|
||||||
* Returns host details with status, submission date, and account manager info
|
* Returns host details with status, submission date, and account manager info
|
||||||
*/
|
*/
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(
|
||||||
|
async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
context?: Context
|
context?: Context,
|
||||||
): Promise<APIGatewayProxyResult> => {
|
): Promise<APIGatewayProxyResult> => {
|
||||||
// Verify authentication token
|
// 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) {
|
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
|
// Verify token and get user info
|
||||||
const userInfo = await verifyOnlyMinglarAdminToken(token);
|
const userInfo = await verifyOnlyMinglarAdminToken(token);
|
||||||
|
|
||||||
// Get user details including role
|
// Get user details including role
|
||||||
const user = await prismaService.user.findUnique({
|
const user = await prismaClient.user.findUnique({
|
||||||
where: { id: userInfo.id },
|
where: { id: userInfo.id },
|
||||||
select: { id: true, roleXid: true }
|
select: { id: true, roleXid: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new ApiError(404, 'User not found');
|
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
|
// 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 {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
@@ -47,7 +78,8 @@ export const handler = safeHandler(async (
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'Host applications retrieved successfully',
|
message: 'Host applications retrieved successfully',
|
||||||
data: hostApplications,
|
...paginatedResponse,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|||||||
@@ -1,42 +1,73 @@
|
|||||||
|
import {
|
||||||
|
APIGatewayProxyEvent,
|
||||||
|
APIGatewayProxyResult,
|
||||||
|
Context,
|
||||||
|
} from 'aws-lambda';
|
||||||
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
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';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
|
import { paginationService } from '../../../../../common/utils/pagination/pagination.service';
|
||||||
import { MinglarService } from '../../../services/minglar.service';
|
import { MinglarService } from '../../../services/minglar.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarService = new MinglarService(prismaClient);
|
||||||
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
|
* Returns host details with status, submission date, and account manager info
|
||||||
*/
|
*/
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(
|
||||||
|
async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
context?: Context
|
context?: Context,
|
||||||
): Promise<APIGatewayProxyResult> => {
|
): Promise<APIGatewayProxyResult> => {
|
||||||
// Verify authentication token
|
// 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) {
|
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
|
// Verify token and get user info
|
||||||
const userInfo = await verifyOnlyMinglarAdminToken(token);
|
const userInfo = await verifyOnlyMinglarAdminToken(token);
|
||||||
|
|
||||||
// Get user details including role
|
// Get user details including role
|
||||||
const user = await prismaService.user.findUnique({
|
const user = await prismaClient.user.findUnique({
|
||||||
where: { id: userInfo.id },
|
where: { id: userInfo.id },
|
||||||
select: { id: true, roleXid: true }
|
select: { id: true, roleXid: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new ApiError(404, 'User not found');
|
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
|
// 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 {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
@@ -47,7 +78,8 @@ export const handler = safeHandler(async (
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'Host applications retrieved successfully',
|
message: 'Host applications retrieved successfully',
|
||||||
data: hostApplications,
|
...paginatedResponse,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
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 { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
|
import { verifyOnlyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { MinglarService } from '../../../services/minglar.service';
|
import { MinglarService } from '../../../services/minglar.service';
|
||||||
import { sendEmailToHostForRejectedApplication } from '../../../services/rejectionMailtoHost.service';
|
import { sendEmailToHostForRejectedApplication } from '../../../services/rejectionMailtoHost.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarService = new MinglarService(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
interface AddSuggestionBody {
|
interface AddSuggestionBody {
|
||||||
hostXid: number;
|
hostXid: number;
|
||||||
@@ -47,7 +46,7 @@ export const handler = safeHandler(async (
|
|||||||
|
|
||||||
// Add suggestion using service
|
// Add suggestion using service
|
||||||
await minglarService.rejectHostApplication(hostXid, userInfo.id);
|
await minglarService.rejectHostApplication(hostXid, userInfo.id);
|
||||||
const hostDetails = await minglarService.getUserDetails(userInfo.id)
|
const hostDetails = await minglarService.getUserDetails(hostXid)
|
||||||
if (!hostDetails?.emailAddress) {
|
if (!hostDetails?.emailAddress) {
|
||||||
throw new ApiError(404, 'Host details or email address not found');
|
throw new ApiError(404, 'Host details or email address not found');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { verifyMinglarAdminToken } from '@/common/middlewares/jwt/authForMinglarAdmin';
|
||||||
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
|
import { MinglarService } from '../../../../minglaradmin/services/minglar.service';
|
||||||
|
|
||||||
|
const minglarService = new MinglarService(prismaClient);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get suggestions handler
|
||||||
|
* Retrieves suggestions based on user's role and host assignments
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
await verifyMinglarAdminToken(token);
|
||||||
|
|
||||||
|
const hostXid = Number(event.pathParameters?.hostXid)
|
||||||
|
|
||||||
|
if (!hostXid) {
|
||||||
|
throw new ApiError(
|
||||||
|
400,
|
||||||
|
'Host ID is required in path parameters.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get suggestions using service
|
||||||
|
const suggestions = await minglarService.getSuggestionsForAM(hostXid);
|
||||||
|
|
||||||
|
return {
|
||||||
|
statusCode: 200,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
success: true,
|
||||||
|
message: 'Suggestions retrieved successfully',
|
||||||
|
data: suggestions,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.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 minglarService = new MinglarService(prismaClient);
|
||||||
|
|
||||||
|
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,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { PrismaService } from '../../../common/database/prisma.service';
|
import { prismaClient } from '../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../common/utils/helper/ApiError';
|
import ApiError from '../../../common/utils/helper/ApiError';
|
||||||
import { GetMinglarLoginResponseDTO } from '../dto/minglar.dto';
|
import { GetMinglarLoginResponseDTO } from '../dto/minglar.dto';
|
||||||
import { MinglarService } from '../services/minglar.service';
|
import { MinglarService } from '../services/minglar.service';
|
||||||
import { TokenService } from "../services/token.service";
|
import { TokenService } from "../services/token.service";
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarSerivce = new MinglarService(prismaClient);
|
||||||
const minglarSerivce = new MinglarService(prismaService);
|
const tokenService = new TokenService(prismaClient);
|
||||||
const tokenService = new TokenService(prismaService);
|
|
||||||
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
@@ -23,13 +22,15 @@ export const handler = safeHandler(async (
|
|||||||
throw new ApiError(400, 'Invalid JSON in request body');
|
throw new ApiError(400, 'Invalid JSON in request body');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { emailAddress ,userPassword} = body;
|
const { emailAddress, userPassword } = body;
|
||||||
|
|
||||||
if (!emailAddress) {
|
if (!emailAddress) {
|
||||||
throw new ApiError(400, 'Email is required');
|
throw new ApiError(400, 'Email is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
const loginForMinglar = await minglarSerivce.loginForMinglar(emailAddress ,userPassword);
|
const emailToLowerCase = emailAddress.toLowerCase()
|
||||||
|
|
||||||
|
const loginForMinglar = await minglarSerivce.loginForMinglar(emailToLowerCase, userPassword);
|
||||||
|
|
||||||
if (!loginForMinglar) {
|
if (!loginForMinglar) {
|
||||||
throw new ApiError(400, 'Failed to login');
|
throw new ApiError(400, 'Failed to login');
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import {
|
|||||||
APIGatewayProxyResult,
|
APIGatewayProxyResult,
|
||||||
Context,
|
Context,
|
||||||
} from 'aws-lambda';
|
} from 'aws-lambda';
|
||||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
import { prismaClient } from '../../../common/database/prisma.lambda.service';
|
||||||
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 { 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();
|
const prismaService = prismaClient;
|
||||||
export const handler = safeHandler(
|
export const handler = safeHandler(
|
||||||
async (
|
async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
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 { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { PrismaService } from '../../../common/database/prisma.service';
|
import { prismaClient } from '../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../common/utils/helper/ApiError';
|
import ApiError from '../../../common/utils/helper/ApiError';
|
||||||
import { generateOtpHelper } from '../../../common/utils/helper/sendOtp';
|
import { generateOtpHelper } from '../../../common/utils/helper/sendOtp';
|
||||||
import { sendOtpEmailForMinglarAdmin } from '../services/sendOTPEmail.service';
|
|
||||||
import { MinglarService } from './../services/minglar.service';
|
import { MinglarService } from './../services/minglar.service';
|
||||||
|
import { sendOtpEmailForMinglarAdmin } from '../services/sendOTPEmail.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarService = new MinglarService(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
@@ -28,11 +27,15 @@ export const handler = safeHandler(async (
|
|||||||
if (!email) {
|
if (!email) {
|
||||||
throw new ApiError(400, 'Email is required');
|
throw new ApiError(400, 'Email is required');
|
||||||
}
|
}
|
||||||
|
console.log(email, " -: Email")
|
||||||
|
|
||||||
const user = await prismaService.user.findUnique({
|
const emailToLowerCase = email.toLowerCase()
|
||||||
where: { emailAddress: email, isActive: true, userStatus: USER_STATUS.INVITED },
|
|
||||||
|
const user = await prismaClient.user.findUnique({
|
||||||
|
where: { emailAddress: emailToLowerCase, isActive: true, userStatus: USER_STATUS.INVITED },
|
||||||
select: { emailAddress: true, id: true, userPassword: true, roleXid: true },
|
select: { emailAddress: true, id: true, userPassword: true, roleXid: true },
|
||||||
});
|
});
|
||||||
|
console.log(user, "sljdfjdf")
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new ApiError(403, 'You are not allowed to register directly. Please contact minglar admin.');
|
throw new ApiError(403, 'You are not allowed to register directly. Please contact minglar admin.');
|
||||||
@@ -55,7 +58,7 @@ export const handler = safeHandler(async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const otpResult = await generateOtpHelper(
|
const otpResult = await generateOtpHelper(
|
||||||
prismaService, // ⭐ pass Prisma from here
|
prismaClient, // ⭐ pass Prisma from here
|
||||||
Number(newUser?.id),
|
Number(newUser?.id),
|
||||||
newUser?.emailAddress,
|
newUser?.emailAddress,
|
||||||
'Register',
|
'Register',
|
||||||
@@ -68,7 +71,7 @@ export const handler = safeHandler(async (
|
|||||||
throw new ApiError(500, 'Failed to send OTP');
|
throw new ApiError(500, 'Failed to send OTP');
|
||||||
}
|
}
|
||||||
|
|
||||||
// await sendOtpEmailForMinglarAdmin(newUser?.emailAddress, otpResult.otp);
|
await sendOtpEmailForMinglarAdmin(newUser?.emailAddress, otpResult.otp);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin';
|
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 { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { MinglarService } from '../../../services/minglar.service';
|
import { MinglarService } from '../../../services/minglar.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarService = new MinglarService(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
|
|||||||
@@ -1,21 +1,30 @@
|
|||||||
import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin';
|
import { verifyOnlyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import {
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
APIGatewayProxyEvent,
|
||||||
|
APIGatewayProxyResult,
|
||||||
|
Context,
|
||||||
|
} from 'aws-lambda';
|
||||||
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { MinglarService } from '../../../services/minglar.service';
|
import { MinglarService } from '../../../services/minglar.service';
|
||||||
|
import { paginationService } from '../../../../../common/utils/pagination/pagination.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarService = new MinglarService(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(
|
||||||
|
async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
context?: Context
|
context?: Context,
|
||||||
): Promise<APIGatewayProxyResult> => {
|
): Promise<APIGatewayProxyResult> => {
|
||||||
// Extract token from headers
|
// Extract token from headers
|
||||||
const token = event.headers['x-auth-token'] || event.headers['X-Auth-Token']
|
const token =
|
||||||
if(!token) {
|
event.headers['x-auth-token'] || event.headers['X-Auth-Token'];
|
||||||
throw new ApiError(400, 'This is a protected route. Please provide a valid token.');
|
if (!token) {
|
||||||
|
throw new ApiError(
|
||||||
|
400,
|
||||||
|
'This is a protected route. Please provide a valid token.',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authenticate user using the shared authForHost function
|
// Authenticate user using the shared authForHost function
|
||||||
@@ -24,7 +33,20 @@ export const handler = safeHandler(async (
|
|||||||
// Extract search parameter from query string
|
// Extract search parameter from query string
|
||||||
const search = event.queryStringParameters?.search || '';
|
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 {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
@@ -35,8 +57,8 @@ export const handler = safeHandler(async (
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'Data retrieved successfully',
|
message: 'Data retrieved successfully',
|
||||||
data: result,
|
...paginatedResponse,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|||||||
@@ -1,21 +1,30 @@
|
|||||||
import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin';
|
import { verifyOnlyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import {
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
APIGatewayProxyEvent,
|
||||||
|
APIGatewayProxyResult,
|
||||||
|
Context,
|
||||||
|
} from 'aws-lambda';
|
||||||
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { MinglarService } from '../../../services/minglar.service';
|
import { MinglarService } from '../../../services/minglar.service';
|
||||||
|
import { paginationService } from '../../../../../common/utils/pagination/pagination.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarService = new MinglarService(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
export const handler = safeHandler(async (
|
export const handler = safeHandler(
|
||||||
|
async (
|
||||||
event: APIGatewayProxyEvent,
|
event: APIGatewayProxyEvent,
|
||||||
context?: Context
|
context?: Context,
|
||||||
): Promise<APIGatewayProxyResult> => {
|
): Promise<APIGatewayProxyResult> => {
|
||||||
// Extract token from headers
|
// Extract token from headers
|
||||||
const token = event.headers['x-auth-token'] || event.headers['X-Auth-Token']
|
const token =
|
||||||
if(!token) {
|
event.headers['x-auth-token'] || event.headers['X-Auth-Token'];
|
||||||
throw new ApiError(400, 'This is a protected route. Please provide a valid token.');
|
if (!token) {
|
||||||
|
throw new ApiError(
|
||||||
|
400,
|
||||||
|
'This is a protected route. Please provide a valid token.',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authenticate user using the shared authForHost function
|
// Authenticate user using the shared authForHost function
|
||||||
@@ -24,7 +33,19 @@ export const handler = safeHandler(async (
|
|||||||
// Extract search parameter from query string
|
// Extract search parameter from query string
|
||||||
const search = event.queryStringParameters?.search || '';
|
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 {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
@@ -35,8 +56,8 @@ export const handler = safeHandler(async (
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'Data retrieved successfully',
|
message: 'Data retrieved successfully',
|
||||||
data: response,
|
...paginatedResponse,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
});
|
},
|
||||||
|
);
|
||||||
@@ -1,15 +1,14 @@
|
|||||||
import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin';
|
import { verifyOnlyMinglarAdminToken } from '../../../../../common/middlewares/jwt/authForOnlyMinglarAdmin';
|
||||||
import { MINGLAR_INVITATION_STATUS } from '@/common/utils/constants/minglar.constant';
|
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||||
import { ROLE } from '../../../../../common/utils/constants/common.constant';
|
import { ROLE } from '../../../../../common/utils/constants/common.constant';
|
||||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||||
import { sendInvitationEmailForMinglarAdmin } from '../../../services/inviteTeammatesEmail.service';
|
import { sendInvitationEmailForMinglarAdmin } from '../../../services/inviteTeammatesEmail.service';
|
||||||
import { MinglarService } from '../../../services/minglar.service';
|
import { MinglarService } from '../../../services/minglar.service';
|
||||||
|
import config from '../../../../../config/config';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarService = new MinglarService(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
interface InviteTeammateBody {
|
interface InviteTeammateBody {
|
||||||
emailAddress: string;
|
emailAddress: string;
|
||||||
@@ -62,6 +61,8 @@ export const handler = safeHandler(async (
|
|||||||
throw new ApiError(400, 'Role is required');
|
throw new ApiError(400, 'Role is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const emailToLowerCase = emailAddress.toLowerCase()
|
||||||
|
|
||||||
// Validate role is either Co_Admin or Account_Manager
|
// Validate role is either Co_Admin or Account_Manager
|
||||||
if (![ROLE.CO_ADMIN, ROLE.ACCOUNT_MANAGER].includes(roleXid)) {
|
if (![ROLE.CO_ADMIN, ROLE.ACCOUNT_MANAGER].includes(roleXid)) {
|
||||||
throw new ApiError(400, 'Invalid role. Only Co_Admin and Account_Manager roles can be assigned.');
|
throw new ApiError(400, 'Invalid role. Only Co_Admin and Account_Manager roles can be assigned.');
|
||||||
@@ -80,7 +81,7 @@ export const handler = safeHandler(async (
|
|||||||
|
|
||||||
// Use single service method that encapsulates the transaction
|
// Use single service method that encapsulates the transaction
|
||||||
await minglarService.inviteTeammate(
|
await minglarService.inviteTeammate(
|
||||||
emailAddress,
|
emailToLowerCase,
|
||||||
roleXid,
|
roleXid,
|
||||||
isFixedSalary,
|
isFixedSalary,
|
||||||
perValue || 0,
|
perValue || 0,
|
||||||
@@ -88,7 +89,7 @@ export const handler = safeHandler(async (
|
|||||||
);
|
);
|
||||||
|
|
||||||
// send email after transaction commits
|
// send email after transaction commits
|
||||||
await sendInvitationEmailForMinglarAdmin(emailAddress);
|
await sendInvitationEmailForMinglarAdmin(emailToLowerCase, config.AM_INVITATION_LINK);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
// modules/minglar/handlers/updateProfile.ts
|
// modules/minglar/handlers/updateProfile.ts
|
||||||
import config from '@/config/config';
|
import config from '../../../config/config';
|
||||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
import AWS from 'aws-sdk';
|
import AWS from 'aws-sdk';
|
||||||
import { PrismaService } from '../../../common/database/prisma.service';
|
import { prismaClient } from '../../../common/database/prisma.lambda.service';
|
||||||
import { verifyMinglarAdminToken } from '../../../common/middlewares/jwt/authForMinglarAdmin';
|
import { verifyMinglarAdminToken } from '../../../common/middlewares/jwt/authForMinglarAdmin';
|
||||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
||||||
import ApiError from '../../../common/utils/helper/ApiError';
|
import ApiError from '../../../common/utils/helper/ApiError';
|
||||||
import { parseJsonField, parseMultipartFormData } from '../../../common/utils/helper/parseMultipartFormData';
|
import { parseJsonField, parseMultipartFormData } from '../../../common/utils/helper/parseMultipartFormData';
|
||||||
import { MinglarService } from '../services/minglar.service';
|
import { MinglarService } from '../services/minglar.service';
|
||||||
|
|
||||||
const prismaService = new PrismaService();
|
const minglarService = new MinglarService(prismaClient);
|
||||||
const minglarService = new MinglarService(prismaService);
|
|
||||||
|
|
||||||
const s3 = new AWS.S3({
|
const s3 = new AWS.S3({
|
||||||
region: config.aws.region,
|
region: config.aws.region,
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { PrismaService } from '../../../common/database/prisma.service';
|
import { prismaClient } from '../../../common/database/prisma.lambda.service';
|
||||||
import { sendAMEmailForHostAssign } from './AMEmail.service';
|
import { sendAMEmailForHostAssign } from './AMEmail.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AMNotificationService {
|
export class AMNotificationService {
|
||||||
constructor(private prisma: PrismaService) {}
|
private prisma = prismaClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch account manager email by id and send assignment email.
|
* Fetch account manager email by id and send assignment email.
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { brevoService } from "@/common/email/brevoApi";
|
import { brevoService } from "../../../common/email/brevoApi";
|
||||||
import ApiError from "@/common/utils/helper/ApiError";
|
import ApiError from "../../../common/utils/helper/ApiError";
|
||||||
|
import config from "../../../config/config";
|
||||||
|
|
||||||
export async function sendEmailToHostForApprovedApplication(
|
export async function sendEmailToHostForApprovedApplication(
|
||||||
emailAddress: string,
|
emailAddress: string,
|
||||||
|
name: string
|
||||||
): Promise<{
|
): Promise<{
|
||||||
sent: boolean;
|
sent: boolean;
|
||||||
// messageId: string
|
// messageId: string
|
||||||
@@ -11,9 +13,11 @@ export async function sendEmailToHostForApprovedApplication(
|
|||||||
const subject = "Approval for your application";
|
const subject = "Approval for your application";
|
||||||
|
|
||||||
const htmlContent = `
|
const htmlContent = `
|
||||||
<p>Dear Host,</p>
|
<p>Dear ${name},</p>
|
||||||
<p>Congratulations, Your application to minglar admin has been approved.</p>
|
<p>Congratulations, Your application to minglar admin has been approved.</p>
|
||||||
<p>You can start onboarding your activities through the host panel.</p>
|
<p>You can start onboarding your activities through the host panel.</p>
|
||||||
|
<p> You can login to your account using the link below:<br/>
|
||||||
|
<strong>Link:</strong> ${config.HOST_LINK} </p>
|
||||||
<p>Best regards,<br/>Minglar Team</p>
|
<p>Best regards,<br/>Minglar Team</p>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -70,3 +74,41 @@ export async function sendEmailToHostForMinglarApproval(
|
|||||||
throw new ApiError(500, "Failed to send OTP to minglar admin via email.");
|
throw new ApiError(500, "Failed to send OTP to minglar admin via email.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function sendAMPQQAcceptanceMailtoHost(
|
||||||
|
emailAddress: string,
|
||||||
|
name: string
|
||||||
|
): Promise<{
|
||||||
|
sent: boolean;
|
||||||
|
// messageId: string
|
||||||
|
}> {
|
||||||
|
|
||||||
|
const subject = "Approval for your activity onboarding application";
|
||||||
|
|
||||||
|
const htmlContent = `
|
||||||
|
<p>Dear ${name},</p>
|
||||||
|
<p>Congratulations, Your activity onboarding application to minglar admin has been approved.</p>
|
||||||
|
<p>You can start adding other details of your activity through the host panel.</p>
|
||||||
|
<p> You can login to your account using the link below:<br/>
|
||||||
|
<strong>Link:</strong> ${config.HOST_LINK} </p>
|
||||||
|
<p>Best regards,<br/>Minglar Team</p>
|
||||||
|
`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await brevoService.sendEmail({
|
||||||
|
recipients: [{ email: emailAddress }],
|
||||||
|
subject,
|
||||||
|
htmlContent,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("📧 Email sent successfully:", result);
|
||||||
|
|
||||||
|
return {
|
||||||
|
sent: true,
|
||||||
|
// messageId: result.messageId
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Brevo email send failed:", err);
|
||||||
|
throw new ApiError(500, "Failed to send OTP to minglar admin via email.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import ApiError from "@/common/utils/helper/ApiError";
|
|||||||
|
|
||||||
export async function sendInvitationEmailForMinglarAdmin(
|
export async function sendInvitationEmailForMinglarAdmin(
|
||||||
emailAddress: string,
|
emailAddress: string,
|
||||||
|
link: string
|
||||||
): Promise<{
|
): Promise<{
|
||||||
sent: boolean;
|
sent: boolean;
|
||||||
// messageId: string
|
// messageId: string
|
||||||
@@ -11,9 +12,19 @@ export async function sendInvitationEmailForMinglarAdmin(
|
|||||||
const subject = "Minglar Admin: Your Team Invitation";
|
const subject = "Minglar Admin: Your Team Invitation";
|
||||||
|
|
||||||
const htmlContent = `
|
const htmlContent = `
|
||||||
<p>Dear,</p>
|
<p>Hi there,</p>
|
||||||
<p>You are invited to join the Minglar Admin team. Please click the link below to create your account.</p>
|
<p>We're excited to invite you to join the <strong>Minglar Admin Team</strong>!<br/>
|
||||||
<p>Best regards,<br/>Minglar Admin Team</p>
|
Please use the link below to set up your account and get started.</p>
|
||||||
|
|
||||||
|
<p><strong>Access Your Invitation:</strong><br/>
|
||||||
|
<a href="${link}">${link}</a></p>
|
||||||
|
|
||||||
|
<p>If you have any questions or need assistance, feel free to reach out — we’re here to help.<br/>
|
||||||
|
We look forward to having you on board!</p>
|
||||||
|
|
||||||
|
<p>Welcome aboard!<br/>
|
||||||
|
<strong>The Minglar Admin Team</strong></p>
|
||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
|||||||
import { brevoService } from "@/common/email/brevoApi";
|
import { brevoService } from "../../../common/email/brevoApi";
|
||||||
import ApiError from "@/common/utils/helper/ApiError";
|
import ApiError from "../../../common/utils/helper/ApiError";
|
||||||
|
import config from "../../../config/config";
|
||||||
|
|
||||||
export async function sendEmailToHostForRejectedApplication(
|
export async function sendEmailToHostForRejectedApplication(
|
||||||
emailAddress: string,
|
emailAddress: string,
|
||||||
@@ -38,6 +39,7 @@ export async function sendEmailToHostForRejectedApplication(
|
|||||||
|
|
||||||
export async function sendAMRejectionMailtoHost(
|
export async function sendAMRejectionMailtoHost(
|
||||||
emailAddress: string,
|
emailAddress: string,
|
||||||
|
name: string
|
||||||
): Promise<{
|
): Promise<{
|
||||||
sent: boolean;
|
sent: boolean;
|
||||||
// messageId: string
|
// messageId: string
|
||||||
@@ -46,11 +48,64 @@ export async function sendAMRejectionMailtoHost(
|
|||||||
const subject = "Improvement of your application";
|
const subject = "Improvement of your application";
|
||||||
|
|
||||||
const htmlContent = `
|
const htmlContent = `
|
||||||
<p>Dear Host,</p>
|
<p>Dear ${name},</p>
|
||||||
<p>Your account manager has made some suggestions on your application.<br/>
|
<p> Your account manager has reviewed your application and provided some suggestions. <br/>
|
||||||
Please improve it and re-submit the application to onboard on minglar.</p>
|
Please make the necessary improvements and re-submit your application to proceed with the onboarding process on Minglar.</p>
|
||||||
<p>If you have any questions please contact to minglar admin.</p>
|
<p> You may access your application using the link below:<br/>
|
||||||
<p>Best regards,<br/>Minglar Team</p>
|
<strong>Link:</strong>
|
||||||
|
<a href="${config.HOST_LINK}" target="_blank">
|
||||||
|
${config.HOST_LINK}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p> If you have any questions, please feel free to contact the Minglar Support Team. </p>
|
||||||
|
<p> Best regards,<br/>
|
||||||
|
<strong>Minglar Team</strong> </p>
|
||||||
|
`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await brevoService.sendEmail({
|
||||||
|
recipients: [{ email: emailAddress }],
|
||||||
|
subject,
|
||||||
|
htmlContent,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("📧 Email sent successfully:", result);
|
||||||
|
|
||||||
|
return {
|
||||||
|
sent: true,
|
||||||
|
// messageId: result.messageId
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Brevo email send failed:", err);
|
||||||
|
throw new ApiError(500, "Failed to send OTP to minglar admin via email.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function sendAMPQQRejectionMailtoHost(
|
||||||
|
emailAddress: string,
|
||||||
|
name: string
|
||||||
|
): Promise<{
|
||||||
|
sent: boolean;
|
||||||
|
// messageId: string
|
||||||
|
}> {
|
||||||
|
|
||||||
|
const subject = "Improvement of your activity onboarding application";
|
||||||
|
|
||||||
|
const htmlContent = `
|
||||||
|
<p>Dear ${name},</p>
|
||||||
|
|
||||||
|
<p>Your account manager has reviewed your activity application and provided some suggestions.<br/>
|
||||||
|
Please make the necessary improvements and re-submit your activity application along with the pre-qualification answers to proceed with the onboarding process on Minglar.</p>
|
||||||
|
|
||||||
|
<p>You may access your activity onboarding application using the link below:<br/>
|
||||||
|
<strong>Link:</strong> ${config.HOST_LINK}</p>
|
||||||
|
|
||||||
|
<p>If you have any questions, please feel free to contact the Minglar Support Team.</p>
|
||||||
|
|
||||||
|
<p>Best regards,<br/>
|
||||||
|
<strong>Minglar Team</strong></p>
|
||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { PrismaService } from "../../../common/database/prisma.service";
|
import { PrismaClient } from '@prisma/client';
|
||||||
import jwt, { JwtPayload } from "jsonwebtoken";
|
import jwt, { JwtPayload } from "jsonwebtoken";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import config from "../../../config/config";
|
import config from "../../../config/config";
|
||||||
|
|
||||||
export class TokenService {
|
export class TokenService {
|
||||||
constructor(private readonly prisma: PrismaService = new PrismaService()) {}
|
constructor(private prisma: PrismaClient) { }
|
||||||
|
|
||||||
private generateToken(
|
private generateToken(
|
||||||
user_xid: number,
|
user_xid: number,
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||||
|
import { prismaClient } from '../../../common/database/prisma.lambda.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';
|
||||||
|
|
||||||
|
const prePopulateService = new PrePopulateService(prismaClient);
|
||||||
|
|
||||||
|
export const handler = safeHandler(async (
|
||||||
|
event: APIGatewayProxyEvent,
|
||||||
|
context?: Context
|
||||||
|
): Promise<APIGatewayProxyResult> => {
|
||||||
|
// Extract token from headers
|
||||||
|
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.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authenticate user using the shared authForHost function
|
||||||
|
await verifyMinglarAdminHostToken(token);
|
||||||
|
|
||||||
|
const result = await prePopulateService.getAllPrePopulateDataForAddActivity();
|
||||||
|
|
||||||
|
return {
|
||||||
|
statusCode: 200,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
success: true,
|
||||||
|
message: 'Data retrieved successfully',
|
||||||
|
data: result,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user