Compare commits
39 Commits
0c97412057
...
Split-lamb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a61e2c412 | ||
|
|
7167eae07e | ||
|
|
4f3d7fd737 | ||
|
|
199013b0f5 | ||
| 0b81dbf7b1 | |||
|
|
9722e1988c | ||
| cf2bbbf138 | |||
|
|
2ca785248f | ||
| 0aa2b9b53e | |||
| b5cdb20c4f | |||
| 00e07113e5 | |||
| c8f0f93792 | |||
| 87779664d1 | |||
| 5b31e5f2a9 | |||
| 2a073c44a2 | |||
|
|
220d309087 | ||
| f45c33ba83 | |||
| 22b3593150 | |||
| d186681ee4 | |||
| 8f428fc1cb | |||
| 0b503cf8bb | |||
| 7110d0462c | |||
| 96648fe37e | |||
|
|
2095f8e124 | ||
| 21c8799502 | |||
|
|
ad9e8e1a3f | ||
| b200e2cb94 | |||
| cae66237d2 | |||
| 25be8a5647 | |||
| 7a4aecdd45 | |||
| 5cced2981a | |||
|
|
b9fbab3717 | ||
|
|
90c897ad48 | ||
| 4a069cc67a | |||
|
|
5d046c4bcf | ||
| accfc4b769 | |||
| e149884f72 | |||
| a31ec97640 | |||
|
|
b4ff39c0d7 |
533
package-lock.json
generated
533
package-lock.json
generated
@@ -13,7 +13,7 @@
|
||||
"@aws-crypto/sha256-browser": "^5.2.0",
|
||||
"@aws-crypto/sha256-js": "^5.2.0",
|
||||
"@aws-sdk/client-s3": "^3.928.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.310.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.928.0",
|
||||
"@aws/lambda-invoke-store": "^0.2.1",
|
||||
"@nestjs/common": "^10.3.0",
|
||||
"@nestjs/config": "^3.1.1",
|
||||
@@ -31,18 +31,27 @@
|
||||
"@types/http-status": "^1.1.2",
|
||||
"ajv": "8.12.0",
|
||||
"aws-lambda": "^1.0.7",
|
||||
"aws-sdk": "^2.1692.0",
|
||||
"bcrypt": "^6.0.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.0",
|
||||
"date-fns": "^4.1.0",
|
||||
"dayjs": "^1.11.19",
|
||||
"docx": "^9.6.0",
|
||||
"docxtemplater": "^3.68.3",
|
||||
"fast-xml-parser": "^5.3.1",
|
||||
"fs": "^0.0.1-security",
|
||||
"helmet": "^7.1.0",
|
||||
"http-status": "^2.1.0",
|
||||
"moment": "^2.30.1",
|
||||
"number-to-words": "^1.2.4",
|
||||
"passport": "^0.7.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
"passport-local": "^1.0.0",
|
||||
"path": "^0.12.7",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"pizzip": "^3.2.0",
|
||||
"prisma": "^7.0.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.8.1",
|
||||
@@ -73,6 +82,7 @@
|
||||
"prettier": "^3.2.5",
|
||||
"serverless-esbuild": "^1.55.1",
|
||||
"serverless-offline": "^14.4.0",
|
||||
"serverless-plugin-split-stacks": "^1.14.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^6.3.4",
|
||||
"ts-jest": "^29.1.2",
|
||||
@@ -4650,6 +4660,24 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@pdf-lib/standard-fonts": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz",
|
||||
"integrity": "sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pako": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@pdf-lib/upng": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@pdf-lib/upng/-/upng-1.0.1.tgz",
|
||||
"integrity": "sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pako": "^1.0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@pkgjs/parseargs": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
@@ -5751,6 +5779,13 @@
|
||||
"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tootallnate/quickjs-emscripten": {
|
||||
"version": "0.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
|
||||
"integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tsconfig/node10": {
|
||||
"version": "1.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz",
|
||||
@@ -6546,6 +6581,15 @@
|
||||
"@xtuc/long": "4.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@xmldom/xmldom": {
|
||||
"version": "0.9.8",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.8.tgz",
|
||||
"integrity": "sha512-p96FSY54r+WJ50FIOsCOjyj/wavs8921hG5+kVMmZgKcvIKxMXHTrjNJvRgWa/zuX3B6t2lijLNFaOyuxUH+2A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@xtuc/ieee754": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
|
||||
@@ -6624,6 +6668,16 @@
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
|
||||
"integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/aggregate-error": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
|
||||
@@ -6964,6 +7018,19 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ast-types": {
|
||||
"version": "0.13.4",
|
||||
"resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
|
||||
"integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/async": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
|
||||
@@ -6992,6 +7059,13 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/aws-info": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-info/-/aws-info-1.3.0.tgz",
|
||||
"integrity": "sha512-dYE3J2GQOMXjirx54IonDisZ6Ok4vBSYjNklNAGGDj2FzGHkWpGOlGAn5/BC8TRh8ttmYRy+Fsmxc8EJMnzSCg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/aws-lambda": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/aws-lambda/-/aws-lambda-1.0.7.tgz",
|
||||
@@ -7257,6 +7331,16 @@
|
||||
"baseline-browser-mapping": "dist/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/basic-ftp": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz",
|
||||
"integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bcrypt": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz",
|
||||
@@ -8386,7 +8470,6 @@
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cors": {
|
||||
@@ -8539,6 +8622,12 @@
|
||||
"url": "https://github.com/sponsors/kossnocorp"
|
||||
}
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.19",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
|
||||
"integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
@@ -8633,6 +8722,21 @@
|
||||
"integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/degenerator": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz",
|
||||
"integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ast-types": "^0.13.4",
|
||||
"escodegen": "^2.1.0",
|
||||
"esprima": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
@@ -8763,6 +8867,50 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/docx": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/docx/-/docx-9.6.0.tgz",
|
||||
"integrity": "sha512-y6EaJJMDvt4P7wgGQB9KsZf4wsRkQMJfkc9LlNufRshggI5BT35hGNkXBCAeEoI3MLMwApKguxzjdqqVcBCqNA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "^25.2.3",
|
||||
"hash.js": "^1.1.7",
|
||||
"jszip": "^3.10.1",
|
||||
"nanoid": "^5.1.3",
|
||||
"xml": "^1.0.1",
|
||||
"xml-js": "^1.6.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/docx/node_modules/@types/node": {
|
||||
"version": "25.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz",
|
||||
"integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/docx/node_modules/undici-types": {
|
||||
"version": "7.18.2",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
|
||||
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/docxtemplater": {
|
||||
"version": "3.68.3",
|
||||
"resolved": "https://registry.npmjs.org/docxtemplater/-/docxtemplater-3.68.3.tgz",
|
||||
"integrity": "sha512-hTZfGcHgN60A09w68Qj0EQRCnF5kf2/ohFlZlUVqAOozCFwx9QMm8naCTvmTsXafuO3nG9qpS4pQWSjFdaCWfQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@xmldom/xmldom": "^0.9.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.4.5",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
|
||||
@@ -9031,6 +9179,39 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/escodegen": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
|
||||
"integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"esprima": "^4.0.1",
|
||||
"estraverse": "^5.2.0",
|
||||
"esutils": "^2.0.2"
|
||||
},
|
||||
"bin": {
|
||||
"escodegen": "bin/escodegen.js",
|
||||
"esgenerate": "bin/esgenerate.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"source-map": "~0.6.1"
|
||||
}
|
||||
},
|
||||
"node_modules/escodegen/node_modules/source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "8.57.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
|
||||
@@ -10022,6 +10203,12 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/fs": {
|
||||
"version": "0.0.1-security",
|
||||
"resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz",
|
||||
"integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
@@ -10199,6 +10386,31 @@
|
||||
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/get-uri": {
|
||||
"version": "6.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz",
|
||||
"integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"basic-ftp": "^5.0.2",
|
||||
"data-uri-to-buffer": "^6.0.2",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/get-uri/node_modules/data-uri-to-buffer": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
|
||||
"integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/giget": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz",
|
||||
@@ -10437,6 +10649,16 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hash.js": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
|
||||
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"minimalistic-assert": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
@@ -10499,6 +10721,20 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/http-proxy-agent": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
|
||||
"integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.1.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/http-status": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/http-status/-/http-status-2.1.0.tgz",
|
||||
@@ -10514,6 +10750,20 @@
|
||||
"integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
|
||||
"integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.1.2",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/human-signals": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
||||
@@ -10556,7 +10806,6 @@
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
@@ -10661,6 +10910,16 @@
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ip-address": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz",
|
||||
"integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||
@@ -11986,7 +12245,6 @@
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
|
||||
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
|
||||
"dev": true,
|
||||
"license": "(MIT OR GPL-3.0-or-later)",
|
||||
"dependencies": {
|
||||
"lie": "~3.3.0",
|
||||
@@ -11999,7 +12257,6 @@
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"core-util-is": "~1.0.0",
|
||||
@@ -12015,14 +12272,12 @@
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/jszip/node_modules/string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
@@ -12149,7 +12404,6 @@
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
||||
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"immediate": "~3.0.5"
|
||||
@@ -12548,6 +12802,12 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/minimalistic-assert": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
|
||||
@@ -12698,6 +12958,24 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz",
|
||||
"integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18 || >=20"
|
||||
}
|
||||
},
|
||||
"node_modules/natural-compare": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||
@@ -12722,6 +13000,16 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/netmask": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
|
||||
"integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nock": {
|
||||
"version": "13.5.6",
|
||||
"resolved": "https://registry.npmjs.org/nock/-/nock-13.5.6.tgz",
|
||||
@@ -12873,6 +13161,12 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/number-to-words": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/number-to-words/-/number-to-words-1.2.4.tgz",
|
||||
"integrity": "sha512-/fYevVkXRcyBiZDg6yzZbm0RuaD6i0qRfn8yr+6D0KgBMOndFPxuW10qCHpzs50nN8qKuv78k8MuotZhcVX6Pw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nypm": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz",
|
||||
@@ -13118,6 +13412,40 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/pac-proxy-agent": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz",
|
||||
"integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tootallnate/quickjs-emscripten": "^0.23.0",
|
||||
"agent-base": "^7.1.2",
|
||||
"debug": "^4.3.4",
|
||||
"get-uri": "^6.0.1",
|
||||
"http-proxy-agent": "^7.0.0",
|
||||
"https-proxy-agent": "^7.0.6",
|
||||
"pac-resolver": "^7.0.1",
|
||||
"socks-proxy-agent": "^8.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/pac-resolver": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz",
|
||||
"integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"degenerator": "^5.0.0",
|
||||
"netmask": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/package-json-from-dist": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
||||
@@ -13128,7 +13456,6 @@
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
|
||||
"dev": true,
|
||||
"license": "(MIT AND Zlib)"
|
||||
},
|
||||
"node_modules/parent-module": {
|
||||
@@ -13219,6 +13546,16 @@
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/path": {
|
||||
"version": "0.12.7",
|
||||
"resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz",
|
||||
"integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"process": "^0.11.1",
|
||||
"util": "^0.10.3"
|
||||
}
|
||||
},
|
||||
"node_modules/path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
@@ -13293,6 +13630,21 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/path/node_modules/inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/path/node_modules/util": {
|
||||
"version": "0.10.4",
|
||||
"resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
|
||||
"integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/pathe": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
|
||||
@@ -13304,6 +13656,24 @@
|
||||
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
|
||||
"integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
|
||||
},
|
||||
"node_modules/pdf-lib": {
|
||||
"version": "1.17.1",
|
||||
"resolved": "https://registry.npmjs.org/pdf-lib/-/pdf-lib-1.17.1.tgz",
|
||||
"integrity": "sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@pdf-lib/standard-fonts": "^1.0.0",
|
||||
"@pdf-lib/upng": "^1.0.1",
|
||||
"pako": "^1.0.11",
|
||||
"tslib": "^1.11.1"
|
||||
}
|
||||
},
|
||||
"node_modules/pdf-lib/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/perfect-debounce": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
|
||||
@@ -13438,6 +13808,21 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/pizzip": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pizzip/-/pizzip-3.2.0.tgz",
|
||||
"integrity": "sha512-X4NPNICxCfIK8VYhF6wbksn81vTiziyLbvKuORVAmolvnUzl1A1xmz9DAWKxPRq9lZg84pJOOAMq3OE61bD8IQ==",
|
||||
"license": "(MIT OR GPL-3.0)",
|
||||
"dependencies": {
|
||||
"pako": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pizzip/node_modules/pako": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
|
||||
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
|
||||
"license": "(MIT AND Zlib)"
|
||||
},
|
||||
"node_modules/pkg-dir": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
|
||||
@@ -13689,11 +14074,19 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/process": {
|
||||
"version": "0.11.10",
|
||||
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/prompts": {
|
||||
@@ -13756,6 +14149,36 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-agent": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz",
|
||||
"integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.1.2",
|
||||
"debug": "^4.3.4",
|
||||
"http-proxy-agent": "^7.0.1",
|
||||
"https-proxy-agent": "^7.0.6",
|
||||
"lru-cache": "^7.14.1",
|
||||
"pac-proxy-agent": "^7.1.0",
|
||||
"proxy-from-env": "^1.1.0",
|
||||
"socks-proxy-agent": "^8.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-agent/node_modules/lru-cache": {
|
||||
"version": "7.18.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
|
||||
"integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
@@ -14756,6 +15179,23 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/serverless-plugin-split-stacks": {
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/serverless-plugin-split-stacks/-/serverless-plugin-split-stacks-1.14.0.tgz",
|
||||
"integrity": "sha512-VksNqvJUPnGHqef0jHNiN0BzTVr0Hy0cWaLxCG75HiQ3vnIog8qeyiu7uWH6LKNhJnGP1jiTNh0YcheCN8kaKA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"aws-info": "^1.2.0",
|
||||
"lodash": "^4.17.21",
|
||||
"proxy-agent": "^6.3.1",
|
||||
"semver": "^7.3.5",
|
||||
"throat": "^6.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"serverless": "1 || 2 || 3 || 4"
|
||||
}
|
||||
},
|
||||
"node_modules/serverless/node_modules/rimraf": {
|
||||
"version": "5.0.10",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
|
||||
@@ -14792,7 +15232,6 @@
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/setprototypeof": {
|
||||
@@ -14923,6 +15362,47 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/smart-buffer": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socks": {
|
||||
"version": "2.8.7",
|
||||
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz",
|
||||
"integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ip-address": "^10.0.1",
|
||||
"smart-buffer": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socks-proxy-agent": {
|
||||
"version": "8.0.5",
|
||||
"resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
|
||||
"integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.1.2",
|
||||
"debug": "^4.3.4",
|
||||
"socks": "^2.8.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/sorted-array-functions": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz",
|
||||
@@ -15504,6 +15984,13 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/throat": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz",
|
||||
"integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/through": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||
@@ -17076,6 +17563,30 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xml": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
|
||||
"integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/xml-js": {
|
||||
"version": "1.6.11",
|
||||
"resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
|
||||
"integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"sax": "^1.2.4"
|
||||
},
|
||||
"bin": {
|
||||
"xml-js": "bin/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/xml-js/node_modules/sax": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.3.tgz",
|
||||
"integrity": "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==",
|
||||
"license": "BlueOak-1.0.0"
|
||||
},
|
||||
"node_modules/xml2js": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
"prettier": "^3.2.5",
|
||||
"serverless-esbuild": "^1.55.1",
|
||||
"serverless-offline": "^14.4.0",
|
||||
"serverless-plugin-split-stacks": "^1.14.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^6.3.4",
|
||||
"ts-jest": "^29.1.2",
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
binaryTargets = ["native", "rhel-openssl-3.0.x"] // Add Linux target
|
||||
binaryTargets = ["native", "rhel-openssl-3.0.x"] // Lambda Node 18/20 (Amazon Linux) target
|
||||
previewFeatures = ["multiSchema"]
|
||||
engineType = "library"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
@@ -1038,13 +1039,13 @@ model ActivityOtherDetails {
|
||||
id Int @id @default(autoincrement())
|
||||
activityXid Int @map("activity_xid")
|
||||
activity Activities @relation(fields: [activityXid], references: [id], onDelete: Cascade)
|
||||
exclusiveNotes String? @map("exclusive_notes") @db.VarChar(500)
|
||||
SafetyInstruction String? @map("safety_instruction") @db.VarChar(400)
|
||||
Cancellations String? @map("cancellations") @db.VarChar(400)
|
||||
dosNotes String? @map("dos_notes") @db.VarChar(400)
|
||||
dontsNotes String? @map("donts_notes") @db.VarChar(400)
|
||||
tipsNotes String? @map("tips_notes") @db.VarChar(400)
|
||||
termsAndCondition String? @map("terms_and_condition") @db.VarChar(500)
|
||||
exclusiveNotes String? @map("exclusive_notes") @db.Text
|
||||
SafetyInstruction String? @map("safety_instruction") @db.Text
|
||||
Cancellations String? @map("cancellations") @db.Text
|
||||
dosNotes String? @map("dos_notes") @db.Text
|
||||
dontsNotes String? @map("donts_notes") @db.Text
|
||||
tipsNotes String? @map("tips_notes") @db.Text
|
||||
termsAndCondition String? @map("terms_and_condition") @db.Text
|
||||
isActive Boolean @default(true) @map("is_active")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
13
serverless.host.yml
Normal file
13
serverless.host.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
service: minglar-host
|
||||
|
||||
useDotenv: ${file(./serverless/common.yml):useDotenv}
|
||||
params: ${file(./serverless/common.yml):params}
|
||||
provider: ${file(./serverless/common.yml):provider}
|
||||
build: ${file(./serverless/common.yml):build}
|
||||
package: ${file(./serverless/common.yml):package}
|
||||
plugins: ${file(./serverless/common.yml):plugins}
|
||||
custom: ${file(./serverless/common.yml):custom}
|
||||
|
||||
functions:
|
||||
- ${file(./serverless/functions/host.yml)}
|
||||
|
||||
13
serverless.minglaradmin.yml
Normal file
13
serverless.minglaradmin.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
service: minglar-admin
|
||||
|
||||
useDotenv: ${file(./serverless/common.yml):useDotenv}
|
||||
params: ${file(./serverless/common.yml):params}
|
||||
provider: ${file(./serverless/common.yml):provider}
|
||||
build: ${file(./serverless/common.yml):build}
|
||||
package: ${file(./serverless/common.yml):package}
|
||||
plugins: ${file(./serverless/common.yml):plugins}
|
||||
custom: ${file(./serverless/common.yml):custom}
|
||||
|
||||
functions:
|
||||
- ${file(./serverless/functions/minglaradmin.yml)}
|
||||
|
||||
13
serverless.prepopulate.yml
Normal file
13
serverless.prepopulate.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
service: minglar-prepopulate
|
||||
|
||||
useDotenv: ${file(./serverless/common.yml):useDotenv}
|
||||
params: ${file(./serverless/common.yml):params}
|
||||
provider: ${file(./serverless/common.yml):provider}
|
||||
build: ${file(./serverless/common.yml):build}
|
||||
package: ${file(./serverless/common.yml):package}
|
||||
plugins: ${file(./serverless/common.yml):plugins}
|
||||
custom: ${file(./serverless/common.yml):custom}
|
||||
|
||||
functions:
|
||||
- ${file(./serverless/functions/prepopulate.yml)}
|
||||
|
||||
32
serverless.prisma-layer.yml
Normal file
32
serverless.prisma-layer.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
service: minglar-prisma-layer
|
||||
|
||||
useDotenv: true
|
||||
|
||||
params:
|
||||
dev:
|
||||
stage: dev
|
||||
test:
|
||||
stage: test
|
||||
uat:
|
||||
stage: uat
|
||||
|
||||
provider:
|
||||
name: aws
|
||||
runtime: nodejs22.x
|
||||
region: ap-south-1
|
||||
stage: ${opt:stage, 'dev'}
|
||||
deploymentBucket:
|
||||
# use a fixed bucket name to prevent Serverless from creating/quashing a resource
|
||||
name: serverless-framework-deployments-ap-south-1-50264b8e-d2b9
|
||||
# optionally uncomment below to enable serverless to create if missing
|
||||
# serverSideEncryption: AES256
|
||||
versionFunctions: false
|
||||
|
||||
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
|
||||
13
serverless.user.yml
Normal file
13
serverless.user.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
service: minglar-user
|
||||
|
||||
useDotenv: ${file(./serverless/common.yml):useDotenv}
|
||||
params: ${file(./serverless/common.yml):params}
|
||||
provider: ${file(./serverless/common.yml):provider}
|
||||
build: ${file(./serverless/common.yml):build}
|
||||
package: ${file(./serverless/common.yml):package}
|
||||
plugins: ${file(./serverless/common.yml):plugins}
|
||||
custom: ${file(./serverless/common.yml):custom}
|
||||
|
||||
functions:
|
||||
- ${file(./serverless/functions/user.yml)}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# Legacy monolith config. For new deployments use serverless.*.yml files.
|
||||
service: minglarDev
|
||||
|
||||
|
||||
@@ -16,6 +17,11 @@ provider:
|
||||
runtime: nodejs22.x
|
||||
region: ap-south-1
|
||||
stage: ${opt:stage, 'dev'}
|
||||
deploymentBucket:
|
||||
# use a fixed bucket name to prevent Serverless from creating/quashing a resource
|
||||
name: serverless-framework-deployments-ap-south-1-50264b8e-d2b9
|
||||
# optionally uncomment below to enable serverless to create if missing
|
||||
# serverSideEncryption: AES256
|
||||
versionFunctions: false
|
||||
memorySize: 512
|
||||
# Apply Prisma layer to all functions
|
||||
@@ -73,10 +79,6 @@ provider:
|
||||
- 'arn:aws:s3:::${env:S3_BUCKET_NAME}'
|
||||
- 'arn:aws:s3:::${env:S3_BUCKET_NAME}/*'
|
||||
|
||||
custom:
|
||||
serverless-offline:
|
||||
reloadHandler: true
|
||||
|
||||
build:
|
||||
esbuild:
|
||||
bundle: true
|
||||
@@ -145,8 +147,18 @@ functions:
|
||||
- ${file(./serverless/functions/host.yml)}
|
||||
- ${file(./serverless/functions/minglaradmin.yml)}
|
||||
- ${file(./serverless/functions/prepopulate.yml)}
|
||||
- ${file(./serverless/functions/pqq.yml)}
|
||||
- ${file(./serverless/functions/user.yml)}
|
||||
|
||||
plugins:
|
||||
- serverless-offline
|
||||
- serverless-offline
|
||||
- serverless-plugin-split-stacks
|
||||
|
||||
custom:
|
||||
serverless-offline:
|
||||
reloadHandler: true
|
||||
|
||||
# split-stacks configuration to avoid CloudFormation resource limit
|
||||
splitStacks:
|
||||
perFunction: true
|
||||
perType: true
|
||||
perGroupFunction: false
|
||||
|
||||
134
serverless/common.yml
Normal file
134
serverless/common.yml
Normal file
@@ -0,0 +1,134 @@
|
||||
useDotenv: true
|
||||
|
||||
params:
|
||||
dev:
|
||||
stage: dev
|
||||
test:
|
||||
stage: test
|
||||
uat:
|
||||
stage: uat
|
||||
|
||||
provider:
|
||||
name: aws
|
||||
runtime: nodejs22.x
|
||||
region: ap-south-1
|
||||
stage: ${opt:stage, 'dev'}
|
||||
deploymentBucket:
|
||||
# use a fixed bucket name to prevent Serverless from creating/quashing a resource
|
||||
name: serverless-framework-deployments-ap-south-1-50264b8e-d2b9
|
||||
# optionally uncomment below to enable serverless to create if missing
|
||||
# serverSideEncryption: AES256
|
||||
versionFunctions: false
|
||||
memorySize: 512
|
||||
# Apply Prisma layer to all functions
|
||||
# Reference the layer defined in the dedicated layer stack
|
||||
layers:
|
||||
- ${cf:minglar-prisma-layer-${sls:stage}.PrismaLambdaLayerQualifiedArn}
|
||||
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}
|
||||
JWT_ACCESS_EXPIRATION_MINUTES: ${env:JWT_ACCESS_EXPIRATION_MINUTES}
|
||||
JWT_REFRESH_EXPIRATION_DAYS: ${env:JWT_REFRESH_EXPIRATION_DAYS}
|
||||
JWT_RESET_PASSWORD_EXPIRATION_MINUTES: ${env:JWT_RESET_PASSWORD_EXPIRATION_MINUTES}
|
||||
JWT_VERIFY_EMAIL_EXPIRATION_MINUTES: ${env:JWT_VERIFY_EMAIL_EXPIRATION_MINUTES}
|
||||
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}
|
||||
AM_INVITATION_LINK: ${env:AM_INVITATION_LINK}
|
||||
HOST_LINK: ${env:HOST_LINK}
|
||||
HOST_LINK_PQ: ${env:HOST_LINK_PQ}
|
||||
|
||||
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}/*'
|
||||
|
||||
build:
|
||||
esbuild:
|
||||
bundle: true
|
||||
minify: true
|
||||
sourcemap: false
|
||||
target: node20
|
||||
platform: node
|
||||
# Mark as external so they're not bundled into the JS
|
||||
external:
|
||||
- '@prisma/client'
|
||||
- '.prisma/client'
|
||||
- '.prisma'
|
||||
- '@prisma/adapter-pg'
|
||||
- 'pg'
|
||||
- 'zod'
|
||||
- '@aws-sdk/*'
|
||||
- '@smithy/*'
|
||||
- '@aws-crypto/*'
|
||||
# Exclude prevents npm install of these packages in the zip
|
||||
exclude:
|
||||
- 'aws-sdk'
|
||||
- '@aws-sdk/*'
|
||||
- '@smithy/*'
|
||||
- '@aws-crypto/*'
|
||||
- '@prisma/adapter-pg'
|
||||
- '@prisma/client'
|
||||
- '.prisma'
|
||||
- '.prisma/client'
|
||||
- 'pg'
|
||||
- 'zod'
|
||||
- 'pg-*'
|
||||
- 'postgres-*'
|
||||
- 'pgpass'
|
||||
- 'split2'
|
||||
- 'xtend'
|
||||
|
||||
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'
|
||||
- '!*.config.js'
|
||||
- '!.git/**'
|
||||
- '!.github/**'
|
||||
|
||||
plugins:
|
||||
- serverless-offline
|
||||
|
||||
custom:
|
||||
serverless-offline:
|
||||
reloadHandler: true
|
||||
@@ -14,7 +14,7 @@ getHosts:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host
|
||||
path: /
|
||||
method: get
|
||||
|
||||
verifyOTP:
|
||||
@@ -30,7 +30,7 @@ verifyOTP:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Host_Admin/onboarding/verify-otp
|
||||
path: /Host_Admin/onboarding/verify-otp
|
||||
method: post
|
||||
|
||||
login:
|
||||
@@ -46,7 +46,7 @@ login:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Host_Admin/onboarding/login
|
||||
path: /Host_Admin/onboarding/login
|
||||
method: post
|
||||
|
||||
signUp:
|
||||
@@ -62,7 +62,7 @@ signUp:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Host_Admin/onboarding/registration
|
||||
path: /Host_Admin/onboarding/registration
|
||||
method: post
|
||||
|
||||
createPassword:
|
||||
@@ -78,7 +78,7 @@ createPassword:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Host_Admin/onboarding/create-password
|
||||
path: /Host_Admin/onboarding/create-password
|
||||
method: post
|
||||
|
||||
updateBankDetails:
|
||||
@@ -94,7 +94,7 @@ updateBankDetails:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Host_Admin/onboarding/add-payment-details
|
||||
path: /Host_Admin/onboarding/add-payment-details
|
||||
method: post
|
||||
|
||||
saveActivity_ForPQQ:
|
||||
@@ -110,7 +110,7 @@ saveActivity_ForPQQ:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Activity_Hub/OnBoarding/add-activity
|
||||
path: /Activity_Hub/OnBoarding/add-activity
|
||||
method: post
|
||||
|
||||
getHostById:
|
||||
@@ -126,7 +126,7 @@ getHostById:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/getById
|
||||
path: /getById
|
||||
method: get
|
||||
|
||||
getPQQ_ByQuestionId:
|
||||
@@ -142,7 +142,7 @@ getPQQ_ByQuestionId:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Activity_Hub/OnBoarding/get-pqq-question-details
|
||||
path: /Activity_Hub/OnBoarding/get-pqq-question-details
|
||||
method: get
|
||||
|
||||
getPQQ_LastUpdatedQuestion:
|
||||
@@ -158,7 +158,7 @@ getPQQ_LastUpdatedQuestion:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Activity_Hub/OnBoarding/get-latest-pqq-question-details
|
||||
path: /Activity_Hub/OnBoarding/get-latest-pqq-question-details
|
||||
method: get
|
||||
|
||||
prePopulateNewActivity:
|
||||
@@ -174,7 +174,7 @@ prePopulateNewActivity:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Activity_Hub/OnBoarding/prepopulate-new-activity
|
||||
path: /Activity_Hub/OnBoarding/prepopulate-new-activity
|
||||
method: get
|
||||
|
||||
createNewActivity:
|
||||
@@ -191,7 +191,7 @@ createNewActivity:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Activity_Hub/OnBoarding/create-new-activity
|
||||
path: /Activity_Hub/OnBoarding/create-new-activity
|
||||
method: patch
|
||||
|
||||
showSuggestion:
|
||||
@@ -207,7 +207,7 @@ showSuggestion:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/get-suggestion
|
||||
path: /get-suggestion
|
||||
method: get
|
||||
|
||||
getAllActivitySuggestion:
|
||||
@@ -223,7 +223,7 @@ getAllActivitySuggestion:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/get-Activity-suggestion
|
||||
path: /get-Activity-suggestion
|
||||
method: get
|
||||
|
||||
getAllHostActivity:
|
||||
@@ -239,7 +239,7 @@ getAllHostActivity:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Activity_Hub/OnBoarding/get-all-host-activity
|
||||
path: /Activity_Hub/OnBoarding/get-all-host-activity
|
||||
method: get
|
||||
|
||||
acceptAggrement:
|
||||
@@ -255,7 +255,7 @@ acceptAggrement:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Host_Admin/onboarding/accept-agreement
|
||||
path: /Host_Admin/onboarding/accept-agreement
|
||||
method: patch
|
||||
|
||||
getLatestAgreement:
|
||||
@@ -271,7 +271,7 @@ getLatestAgreement:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Host_Admin/onboarding/get-latest-agreement
|
||||
path: /Host_Admin/onboarding/get-latest-agreement
|
||||
method: get
|
||||
|
||||
getStepperInfo:
|
||||
@@ -305,7 +305,7 @@ updateHostProfile:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/profile
|
||||
path: /profile
|
||||
method: patch
|
||||
|
||||
# Functions with S3/AWS SDK dependencies
|
||||
@@ -320,7 +320,7 @@ submitCompanyDetails:
|
||||
- 'src/common/**'
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Host_Admin/onboarding/add-company-details
|
||||
path: /Host_Admin/onboarding/add-company-details
|
||||
method: patch
|
||||
|
||||
submitPQQ_Answer:
|
||||
@@ -336,7 +336,7 @@ submitPQQ_Answer:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Activity_Hub/OnBoarding/submit-pqq-answer
|
||||
path: /Activity_Hub/OnBoarding/submit-pqq-answer
|
||||
method: patch
|
||||
|
||||
updatePQQ_LastAnswer:
|
||||
@@ -352,7 +352,7 @@ updatePQQ_LastAnswer:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Activity_Hub/OnBoarding/submit-final-pqq-answer
|
||||
path: /Activity_Hub/OnBoarding/submit-final-pqq-answer
|
||||
method: post
|
||||
|
||||
submitPQQForReview:
|
||||
@@ -368,7 +368,7 @@ submitPQQForReview:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Activity_Hub/OnBoarding/submit-pqq-for-review
|
||||
path: /Activity_Hub/OnBoarding/submit-pqq-for-review
|
||||
method: patch
|
||||
|
||||
getAllPQQwithSubmittedAns:
|
||||
@@ -383,7 +383,7 @@ getAllPQQwithSubmittedAns:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Activity_Hub/OnBoarding/get-all-pqq-ques-submited-ans
|
||||
path: /Activity_Hub/OnBoarding/get-all-pqq-ques-submited-ans
|
||||
method: get
|
||||
|
||||
getAllDetailsOfActivityAndVenue:
|
||||
@@ -398,7 +398,7 @@ getAllDetailsOfActivityAndVenue:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Activity_Hub/OnBoarding/get-all-details-activity-venue/{activityXid}
|
||||
path: /Activity_Hub/OnBoarding/get-all-details-activity-venue/{activityXid}
|
||||
method: get
|
||||
|
||||
updateSuggestionAsReviewed:
|
||||
@@ -413,7 +413,7 @@ updateSuggestionAsReviewed:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /host/Activity_Hub/OnBoarding/update-suggestion-reviewed
|
||||
path: /Activity_Hub/OnBoarding/update-suggestion-reviewed
|
||||
method: patch
|
||||
|
||||
resendOTPmail:
|
||||
@@ -554,4 +554,34 @@ openCanceledSlotForActivity:
|
||||
events:
|
||||
- httpApi:
|
||||
path: /scheduling/open-canceled-slot
|
||||
method: patch
|
||||
method: patch
|
||||
|
||||
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: /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: /Activity_Hub/OnBoarding/submit-pq-answer
|
||||
method: patch
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
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
|
||||
@@ -13,7 +13,7 @@ getAllBankAndCurrencyDetails:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /prepopulate/get-all-bank-currency-details
|
||||
path: /get-all-bank-currency-details
|
||||
method: get
|
||||
|
||||
getCityByState:
|
||||
@@ -29,7 +29,7 @@ getCityByState:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /prepopulate/get-city-by-state
|
||||
path: /get-city-by-state
|
||||
method: get
|
||||
|
||||
getBranchByBankXid:
|
||||
@@ -45,7 +45,7 @@ getBranchByBankXid:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /prepopulate/get-branch-by-bank
|
||||
path: /get-branch-by-bank
|
||||
method: get
|
||||
|
||||
getAllDocumentCountryStateCityDetails:
|
||||
@@ -60,7 +60,7 @@ getAllDocumentCountryStateCityDetails:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /prepopulate/get-all-doc-country
|
||||
path: /get-all-doc-country
|
||||
method: get
|
||||
|
||||
getAllPqqQuesAns:
|
||||
@@ -75,7 +75,7 @@ getAllPqqQuesAns:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /prepopulate/get-all-pqq-ques-ans
|
||||
path: /get-all-pqq-ques-ans
|
||||
method: get
|
||||
|
||||
getFrequenciesOfActivity:
|
||||
@@ -90,7 +90,7 @@ getFrequenciesOfActivity:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /prepopulate/get-all-Frequencies
|
||||
path: /get-all-Frequencies
|
||||
method: get
|
||||
|
||||
getAddActivityPrePopulate:
|
||||
@@ -105,5 +105,5 @@ getAddActivityPrePopulate:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /prepopulate/get-add-activity-prepopulate
|
||||
path: /get-add-activity-prepopulate
|
||||
method: get
|
||||
|
||||
@@ -13,7 +13,7 @@ registerUser:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/register
|
||||
path: /register
|
||||
method: post
|
||||
|
||||
submitPersonalInfo:
|
||||
@@ -28,7 +28,7 @@ submitPersonalInfo:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/submit-personal-info
|
||||
path: /submit-personal-info
|
||||
method: post
|
||||
|
||||
verifyOtpForUser:
|
||||
@@ -43,7 +43,7 @@ verifyOtpForUser:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/verify-otp
|
||||
path: /verify-otp
|
||||
method: post
|
||||
|
||||
generateAccessFromRefreshToken:
|
||||
@@ -58,7 +58,7 @@ generateAccessFromRefreshToken:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/generate-access-from-refresh
|
||||
path: /generate-access-from-refresh
|
||||
method: post
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ setPasscodeForMobile:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/set-passcode
|
||||
path: /set-passcode
|
||||
method: post
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ verifyPasscode:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/verify-passcode
|
||||
path: /verify-passcode
|
||||
method: post
|
||||
|
||||
setUserInterest:
|
||||
@@ -105,7 +105,7 @@ setUserInterest:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/set-interests
|
||||
path: /set-interests
|
||||
method: post
|
||||
|
||||
setUserLocationss:
|
||||
@@ -120,7 +120,7 @@ setUserLocationss:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/set-location-user
|
||||
path: /set-location-user
|
||||
method: post
|
||||
|
||||
getLandingPageDetails:
|
||||
@@ -135,7 +135,7 @@ getLandingPageDetails:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/activities/get-landing-page-details
|
||||
path: /activities/get-landing-page-details
|
||||
method: get
|
||||
|
||||
getSurpriseMePageDetails:
|
||||
@@ -150,7 +150,7 @@ getSurpriseMePageDetails:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/activities/get-surprise-me-page-details
|
||||
path: /activities/get-surprise-me-page-details
|
||||
method: get
|
||||
|
||||
getActivityDetailsById:
|
||||
@@ -165,7 +165,7 @@ getActivityDetailsById:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/activities/get-activity-details-by-id/{activity_xid}
|
||||
path: /activities/get-activity-details-by-id/{activity_xid}
|
||||
method: get
|
||||
|
||||
checkAvailabilityDetails:
|
||||
@@ -180,7 +180,7 @@ checkAvailabilityDetails:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/activities/check-availability/{activity_xid}
|
||||
path: /activities/check-availability/{activity_xid}
|
||||
method: get
|
||||
|
||||
searchActivities:
|
||||
@@ -195,7 +195,7 @@ searchActivities:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/activities/specific-search
|
||||
path: /activities/specific-search
|
||||
method: get
|
||||
|
||||
searchSchoolsAndCompanies:
|
||||
@@ -210,7 +210,7 @@ searchSchoolsAndCompanies:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/connections/search-schools-companies
|
||||
path: /connections/search-schools-companies
|
||||
method: get
|
||||
|
||||
searchCities:
|
||||
@@ -225,7 +225,7 @@ searchCities:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/connections/search-cities
|
||||
path: /connections/search-cities
|
||||
method: get
|
||||
|
||||
addSchoolCompanyDetail:
|
||||
@@ -240,7 +240,7 @@ addSchoolCompanyDetail:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/connections/add-school-company
|
||||
path: /connections/add-school-company
|
||||
method: post
|
||||
|
||||
removeConnectionDetails:
|
||||
@@ -255,7 +255,7 @@ removeConnectionDetails:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/connections/remove-connection-details
|
||||
path: /connections/remove-connection-details
|
||||
method: delete
|
||||
|
||||
getAllConnectionOfUser:
|
||||
@@ -270,7 +270,7 @@ getAllConnectionOfUser:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/connections/get-all-connections-details
|
||||
path: /connections/get-all-connections-details
|
||||
method: get
|
||||
|
||||
getActivityFromConnectionsInterest:
|
||||
@@ -285,7 +285,7 @@ getActivityFromConnectionsInterest:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/connections/get-activity-from-connections-interest
|
||||
path: /connections/get-activity-from-connections-interest
|
||||
method: get
|
||||
|
||||
viewMoreActivitiesByInterest:
|
||||
@@ -300,7 +300,7 @@ viewMoreActivitiesByInterest:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/activities/view-more-activities
|
||||
path: /activities/view-more-activities
|
||||
method: get
|
||||
|
||||
viewMoreActivitiesUpperSection:
|
||||
@@ -315,7 +315,7 @@ viewMoreActivitiesUpperSection:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/activities/view-more-activities-upper-section
|
||||
path: /activities/view-more-activities-upper-section
|
||||
method: get
|
||||
|
||||
getRandomActiveActivity:
|
||||
@@ -330,7 +330,7 @@ getRandomActiveActivity:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/activities/get-random-active-activity
|
||||
path: /activities/get-random-active-activity
|
||||
method: get
|
||||
|
||||
getNearbyActivities:
|
||||
@@ -345,7 +345,7 @@ getNearbyActivities:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/activities/get-nearby-activities
|
||||
path: /activities/get-nearby-activities
|
||||
method: get
|
||||
|
||||
addActivityToBucketInterested:
|
||||
@@ -360,5 +360,50 @@ addActivityToBucketInterested:
|
||||
- ${file(./serverless/patterns/base.yml):pattern4}
|
||||
events:
|
||||
- httpApi:
|
||||
path: /user/activities/add-to-bucket-interested
|
||||
method: post
|
||||
path: /activities/add-to-bucket-interested
|
||||
method: post
|
||||
|
||||
removeActivityFromBucketInterested:
|
||||
handler: src/modules/user/handlers/activities/removeFromBucketInterested.handler
|
||||
memorySize: 384
|
||||
package:
|
||||
patterns:
|
||||
- 'src/modules/user/handlers/activities/**'
|
||||
- ${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: /activities/remove-from-bucket-interested
|
||||
method: post
|
||||
|
||||
getFilteredLandingPageAllDetails:
|
||||
handler: src/modules/user/handlers/activities/filteredLandingPageAllDetails.handler
|
||||
memorySize: 512
|
||||
package:
|
||||
patterns:
|
||||
- 'src/modules/user/**'
|
||||
- ${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: /activities/get-filtered-landing-page-details
|
||||
method: get
|
||||
|
||||
getAllBucketActivities:
|
||||
handler: src/modules/user/handlers/activities/getAllBucketActivities.handler
|
||||
memorySize: 512
|
||||
package:
|
||||
patterns:
|
||||
- 'src/modules/user/**'
|
||||
- ${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: /activities/get-all-bucket-activities
|
||||
method: get
|
||||
@@ -1,11 +1,18 @@
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import AWS from 'aws-sdk';
|
||||
import dayjs from 'dayjs';
|
||||
import { z } from 'zod';
|
||||
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 { ROLE } from '../../../common/utils/constants/common.constant';
|
||||
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from "../../../common/utils/helper/ApiError";
|
||||
import { parseMultipartFormData } from '../../../common/utils/helper/parseMultipartFormData';
|
||||
import config from '../../../config/config';
|
||||
|
||||
const s3 = new AWS.S3({
|
||||
region: config.aws.region,
|
||||
});
|
||||
|
||||
const updateHostProfileSchema = z
|
||||
.strictObject({
|
||||
@@ -17,6 +24,8 @@ const updateHostProfileSchema = z
|
||||
mobileNumber: z.string().min(5).max(15).optional(),
|
||||
dateOfBirth: z.string().min(1).optional(),
|
||||
|
||||
profileImage: z.string().url().optional(),
|
||||
|
||||
// Address
|
||||
address1: z.string().min(1).optional(),
|
||||
address2: z.string().min(1).optional(),
|
||||
@@ -30,6 +39,33 @@ const updateHostProfileSchema = z
|
||||
})
|
||||
.strip();
|
||||
|
||||
async function uploadProfileImageToS3(buffer: Buffer, mimeType: string, originalName: string, userId: number) {
|
||||
const sanitizeFileName = (name: string) => {
|
||||
return name
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9.]/g, '_')
|
||||
.replace(/_+/g, '_')
|
||||
.replace(/^_+|_+$/g, '');
|
||||
};
|
||||
|
||||
const fileExtension = originalName.split('.').pop() || 'jpg';
|
||||
const fileName = `profile_image.${fileExtension}`;
|
||||
const sanitizedFileName = sanitizeFileName(fileName);
|
||||
const s3Key = `Host/ProfileImages/${userId}/${sanitizedFileName}`;
|
||||
|
||||
await s3
|
||||
.upload({
|
||||
Bucket: config.aws.bucketName,
|
||||
Key: s3Key,
|
||||
Body: buffer,
|
||||
ContentType: mimeType,
|
||||
ACL: 'private',
|
||||
})
|
||||
.promise();
|
||||
|
||||
return `https://${config.aws.bucketName}.s3.${config.aws.region}.amazonaws.com/${s3Key}`;
|
||||
}
|
||||
|
||||
function parseDob(dateOfBirth: string): Date {
|
||||
const parsed = dayjs(dateOfBirth, ['YYYY-MM-DD', 'MM/DD/YYYY', 'DD/MM/YYYY'], true);
|
||||
if (!parsed.isValid()) {
|
||||
@@ -105,7 +141,18 @@ async function ensureHostUser(tx: any, userId: number) {
|
||||
if (user.roleXid !== ROLE.HOST) throw new ApiError(403, 'Access denied.');
|
||||
}
|
||||
|
||||
async function updateUserIfNeeded(tx: any, userId: number, input: { firstName?: string; lastName?: string | null; isdCode?: string; mobileNumber?: string; dateOfBirth?: string }) {
|
||||
async function updateUserIfNeeded(
|
||||
tx: any,
|
||||
userId: number,
|
||||
input: {
|
||||
firstName?: string;
|
||||
lastName?: string | null;
|
||||
isdCode?: string;
|
||||
mobileNumber?: string;
|
||||
dateOfBirth?: string;
|
||||
profileImage?: string;
|
||||
},
|
||||
) {
|
||||
const userUpdateData: any = {};
|
||||
if (input.firstName !== undefined) userUpdateData.firstName = input.firstName || null;
|
||||
if (input.lastName !== undefined) userUpdateData.lastName = input.lastName;
|
||||
@@ -114,6 +161,9 @@ async function updateUserIfNeeded(tx: any, userId: number, input: { firstName?:
|
||||
if (input.dateOfBirth !== undefined) {
|
||||
userUpdateData.dateOfBirth = input.dateOfBirth ? parseDob(input.dateOfBirth) : null;
|
||||
}
|
||||
if (input.profileImage !== undefined) {
|
||||
userUpdateData.profileImage = input.profileImage || null;
|
||||
}
|
||||
|
||||
if (!hasAnyDefined(userUpdateData)) return;
|
||||
|
||||
@@ -210,7 +260,56 @@ export const handler = safeHandler(async (
|
||||
throw new ApiError(400, 'Invalid user id');
|
||||
}
|
||||
|
||||
const body = parseJsonBody(event);
|
||||
const contentType = event.headers['Content-Type'] || event.headers['content-type'] || '';
|
||||
const isMultipart = contentType.includes('multipart/form-data');
|
||||
|
||||
let body: any;
|
||||
|
||||
if (isMultipart) {
|
||||
const isBase64Encoded = event.isBase64Encoded || false;
|
||||
const { fields, files } = parseMultipartFormData(event.body || null, contentType, isBase64Encoded);
|
||||
|
||||
const multipartBody: any = {};
|
||||
|
||||
const copyIfPresent = (key: string) => {
|
||||
if (fields[key] !== undefined) {
|
||||
multipartBody[key] = fields[key];
|
||||
}
|
||||
};
|
||||
|
||||
['fullName', 'firstName', 'lastName', 'isdCode', 'mobileNumber', 'dateOfBirth', 'address1', 'address2', 'pinCode'].forEach(
|
||||
copyIfPresent,
|
||||
);
|
||||
|
||||
const parseNumberField = (key: string) => {
|
||||
if (fields[key] !== undefined) {
|
||||
const value = Number(fields[key]);
|
||||
if (!Number.isNaN(value)) {
|
||||
multipartBody[key] = value;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
['countryXid', 'stateXid', 'cityXid'].forEach(parseNumberField);
|
||||
|
||||
const profileImageFile = files.find((f) => f.fieldName === 'profileImage');
|
||||
if (profileImageFile) {
|
||||
const uploadedUrl = await uploadProfileImageToS3(
|
||||
profileImageFile.data,
|
||||
profileImageFile.contentType,
|
||||
profileImageFile.fileName,
|
||||
userId,
|
||||
);
|
||||
multipartBody.profileImage = uploadedUrl;
|
||||
} else if (fields.profileImage) {
|
||||
multipartBody.profileImage = fields.profileImage;
|
||||
}
|
||||
|
||||
body = multipartBody;
|
||||
} else {
|
||||
body = parseJsonBody(event);
|
||||
}
|
||||
|
||||
const data = validateBody(body);
|
||||
const name = normalizeNameFields(data);
|
||||
const address = buildAddressInput(data);
|
||||
@@ -223,6 +322,7 @@ export const handler = safeHandler(async (
|
||||
isdCode: data.isdCode,
|
||||
mobileNumber: data.mobileNumber,
|
||||
dateOfBirth: data.dateOfBirth,
|
||||
profileImage: data.profileImage,
|
||||
});
|
||||
await upsertAddressIfNeeded(tx, userId, address);
|
||||
return getProfileSnapshot(tx, userId);
|
||||
@@ -237,7 +337,7 @@ export const handler = safeHandler(async (
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: 'Profile updated successfully',
|
||||
data: result,
|
||||
data : null// no data payload per request
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -362,6 +362,9 @@ export class SchedulingService {
|
||||
isActive: true,
|
||||
startDate: { lte: date },
|
||||
OR: [{ endDate: null }, { endDate: { gte: date } }],
|
||||
ScheduleDetails: {
|
||||
some: {}
|
||||
}
|
||||
},
|
||||
include: {
|
||||
activityVenue: {
|
||||
|
||||
@@ -177,8 +177,8 @@ function computeBasePriceAndTaxes(
|
||||
return { basePrice, taxDetails };
|
||||
}
|
||||
|
||||
const normalize = (v?: string | null) =>
|
||||
v ? v.trim().toLowerCase() : null;
|
||||
const normalize = (v?: string | null, maxLength: number = 50) =>
|
||||
v ? v.trim().toLowerCase().substring(0, maxLength) : null;
|
||||
|
||||
async function renderAgreementPdf(vars: {
|
||||
effectiveDate: string;
|
||||
@@ -338,9 +338,11 @@ const findOrCreateState = async (
|
||||
) => {
|
||||
if (!stateName || !countryXid) return null;
|
||||
|
||||
const trimmedStateName = stateName.trim().substring(0, 50);
|
||||
|
||||
const state = await tx.states.findFirst({
|
||||
where: {
|
||||
stateName: { equals: stateName.trim(), mode: 'insensitive' },
|
||||
stateName: { equals: trimmedStateName, mode: 'insensitive' },
|
||||
countryXid,
|
||||
isActive: true,
|
||||
},
|
||||
@@ -350,7 +352,7 @@ const findOrCreateState = async (
|
||||
|
||||
const created = await tx.states.create({
|
||||
data: {
|
||||
stateName: stateName.trim(),
|
||||
stateName: trimmedStateName,
|
||||
countryXid,
|
||||
},
|
||||
});
|
||||
@@ -365,9 +367,11 @@ const findOrCreateCity = async (
|
||||
) => {
|
||||
if (!cityName || !stateXid) return null;
|
||||
|
||||
const trimmedCityName = cityName.trim().substring(0, 50);
|
||||
|
||||
const city = await tx.cities.findFirst({
|
||||
where: {
|
||||
cityName: { equals: cityName.trim(), mode: 'insensitive' },
|
||||
cityName: { equals: trimmedCityName, mode: 'insensitive' },
|
||||
stateXid,
|
||||
isActive: true,
|
||||
},
|
||||
@@ -377,7 +381,7 @@ const findOrCreateCity = async (
|
||||
|
||||
const created = await tx.cities.create({
|
||||
data: {
|
||||
cityName: cityName.trim(),
|
||||
cityName: trimmedCityName,
|
||||
stateXid,
|
||||
},
|
||||
});
|
||||
@@ -506,7 +510,7 @@ export class HostService {
|
||||
}
|
||||
},
|
||||
countryXid: true,
|
||||
country:{
|
||||
country: {
|
||||
select: {
|
||||
id: true,
|
||||
countryName: true
|
||||
@@ -1159,6 +1163,29 @@ export class HostService {
|
||||
throw new ApiError(400, 'Valid hostXid is required');
|
||||
}
|
||||
|
||||
const hostHeader = await this.prisma.hostHeader.findFirst({
|
||||
where: { id: hostXid, isActive: true },
|
||||
select: {
|
||||
id: true,
|
||||
isCommisionBase: true,
|
||||
commisionPer: true,
|
||||
durationNumber: true,
|
||||
durationFrequency: true,
|
||||
amountPerBooking: true,
|
||||
agreementStartDate: true,
|
||||
payoutDurationNum: true,
|
||||
payoutDurationFrequency: true,
|
||||
registrationNumber: true,
|
||||
companyName: true,
|
||||
companyTypes: {
|
||||
select: {
|
||||
id: true,
|
||||
companyTypeName: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const agreement = await this.prisma.hostAgreement.findFirst({
|
||||
where: { hostXid, isActive: true },
|
||||
orderBy: { createdAt: 'desc' },
|
||||
@@ -1172,23 +1199,30 @@ export class HostService {
|
||||
},
|
||||
});
|
||||
|
||||
if (!agreement) {
|
||||
// ❌ If both missing
|
||||
if (!agreement && !hostHeader) {
|
||||
throw new ApiError(404, 'No active agreement found for this host');
|
||||
}
|
||||
|
||||
const filePath = agreement.filePath;
|
||||
let presignedUrl = "";
|
||||
|
||||
// If full URL is saved, extract only S3 key part
|
||||
const key = filePath.startsWith('http')
|
||||
? filePath.split('.com/')[1]
|
||||
: filePath;
|
||||
if (agreement?.filePath) {
|
||||
const key = agreement.filePath.startsWith('http')
|
||||
? agreement.filePath.split('.com/')[1]
|
||||
: agreement.filePath;
|
||||
|
||||
const bucket = config.aws.bucketName;
|
||||
const presignedUrl = await getPresignedUrl(bucket, key);
|
||||
const bucket = config.aws.bucketName;
|
||||
presignedUrl = await getPresignedUrl(bucket, key);
|
||||
}
|
||||
|
||||
return {
|
||||
...agreement,
|
||||
presignedUrl,
|
||||
hostHeader: hostHeader || null,
|
||||
agreement: agreement
|
||||
? {
|
||||
...agreement,
|
||||
presignedUrl
|
||||
}
|
||||
: null
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -53,10 +53,10 @@ export class TokenService {
|
||||
config.jwt.secret
|
||||
);
|
||||
|
||||
await this.prisma.token.deleteMany({
|
||||
where: { userXid: user_xid }
|
||||
})
|
||||
|
||||
// Optionally keep existing refresh tokens alive instead of deleting
|
||||
// Removed deleteMany call so the same refresh token can be used multiple
|
||||
// times. If you want to limit refresh tokens later you can implement
|
||||
// rotation or blacklist logic elsewhere.
|
||||
await this.prisma.token.create({
|
||||
data: {
|
||||
token: refreshToken.token,
|
||||
|
||||
@@ -66,6 +66,8 @@ export const handler = safeHandler(async (
|
||||
data: {
|
||||
bucketCount: counts.bucketCount,
|
||||
interestedCount: counts.interestedCount,
|
||||
coverImage: counts.coverImage,
|
||||
coverImagePresignedUrl: counts.coverImagePresignedUrl,
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -50,64 +50,73 @@ export const handler = safeHandler(async (
|
||||
const activity = activityDetails.activity;
|
||||
|
||||
// Rooms: combine ActivityVenues with their respective slots for the selected date
|
||||
const Venues = (activity.ActivityVenues || []).map((v: any) => {
|
||||
const header = scheduleDetails.find((h: any) => h.activityVenue?.venueXid === v.id);
|
||||
const Venues = (activity.ActivityVenues || [])
|
||||
.map((v: any) => {
|
||||
const header = scheduleDetails.find(
|
||||
(h: any) => h.activityVenue?.venueXid === v.id
|
||||
);
|
||||
|
||||
const roomSlots = (header?.slots || []).map((s: any) => {
|
||||
let status = 'Available';
|
||||
if (s.maxCapacity === 0) status = 'Housefull';
|
||||
else if (s.maxCapacity <= 2) status = '2 Slots Left';
|
||||
else if (s.maxCapacity <= 5) status = 'Fast Filling';
|
||||
if (!header || !header.slots?.length) {
|
||||
return null; // ❌ venue has no slots for selected date
|
||||
}
|
||||
|
||||
const roomSlots = header.slots.map((s: any) => {
|
||||
let status = "Available";
|
||||
|
||||
if (s.maxCapacity === 0) status = "Housefull";
|
||||
else if (s.maxCapacity <= 2) status = "2 Slots Left";
|
||||
else if (s.maxCapacity <= 5) status = "Fast Filling";
|
||||
|
||||
return {
|
||||
slotId: s.slotId,
|
||||
startTime: s.startTime,
|
||||
endTime: s.endTime,
|
||||
status,
|
||||
maxCapacity: s.maxCapacity,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
slotId: s.slotId,
|
||||
startTime: s.startTime,
|
||||
endTime: s.endTime,
|
||||
status,
|
||||
maxCapacity: s.maxCapacity,
|
||||
venueXid: v.id,
|
||||
venueName: v.venueName,
|
||||
venueLabel: v.venueLabel,
|
||||
venueCapacity: v.venueCapacity,
|
||||
availableSeats: v.availableSeats ?? null,
|
||||
price: v.ActivityPrices?.[0]?.sellPrice ?? null,
|
||||
endDate: header?.endDate ?? null,
|
||||
slots: roomSlots,
|
||||
slotsCount: roomSlots.length,
|
||||
venueMedia: (v.ActivityVenueArtifacts || []).map((media: any) => ({
|
||||
id: media.id,
|
||||
mediaType: media.mediaType,
|
||||
mediaFileName: media.mediaFileName,
|
||||
presignedUrl: media.presignedUrl,
|
||||
})),
|
||||
};
|
||||
});
|
||||
})
|
||||
.filter(Boolean); // ✅ removes null venues
|
||||
|
||||
return {
|
||||
venueXid: v.id,
|
||||
venueName: v.venueName,
|
||||
venueLabel: v.venueLabel,
|
||||
venueCapacity: v.venueCapacity,
|
||||
availableSeats: v.availableSeats ?? null,
|
||||
price: v.ActivityPrices?.[0]?.sellPrice ?? null,
|
||||
endDate: header?.endDate ?? null,
|
||||
slots: roomSlots,
|
||||
slotsCount: roomSlots.length,
|
||||
venueMedia: (v.ActivityVenueArtifacts || []).map((media: any) => ({
|
||||
id: media.id,
|
||||
mediaType: media.mediaType,
|
||||
mediaFileName: media.mediaFileName, // original S3 key / URL
|
||||
presignedUrl: media.presignedUrl, // presigned URL
|
||||
})),
|
||||
// derive check-in/out from all room slots (earliest start, latest end)
|
||||
const allSlots = Venues.flatMap(r => r.slots || []);
|
||||
const startTimes = allSlots.map(s => s.startTime).filter(Boolean);
|
||||
const endTimes = allSlots.map(s => s.endTime).filter(Boolean);
|
||||
const checkInTime = startTimes.length ? startTimes.sort()[0] : null;
|
||||
const checkOutTime = endTimes.length ? endTimes.sort().reverse()[0] : null;
|
||||
|
||||
const responsePayload = {
|
||||
selectedDate,
|
||||
Venues,
|
||||
checkInTime,
|
||||
checkOutTime,
|
||||
};
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
},
|
||||
body: JSON.stringify({ success: true, data: responsePayload }),
|
||||
};
|
||||
});
|
||||
|
||||
// derive check-in/out from all room slots (earliest start, latest end)
|
||||
const allSlots = Venues.flatMap(r => r.slots || []);
|
||||
const startTimes = allSlots.map(s => s.startTime).filter(Boolean);
|
||||
const endTimes = allSlots.map(s => s.endTime).filter(Boolean);
|
||||
const checkInTime = startTimes.length ? startTimes.sort()[0] : null;
|
||||
const checkOutTime = endTimes.length ? endTimes.sort().reverse()[0] : null;
|
||||
|
||||
const responsePayload = {
|
||||
selectedDate,
|
||||
Venues,
|
||||
checkInTime,
|
||||
checkOutTime,
|
||||
};
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
},
|
||||
body: JSON.stringify({ success: true, data: responsePayload }),
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { prismaClient } from '../../../../common/database/prisma.lambda.service';
|
||||
import { verifyUserToken } from '../../../../common/middlewares/jwt/authForUser';
|
||||
import { safeHandler } from '../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../common/utils/helper/ApiError';
|
||||
import { FilteredLandingPageService } from '../../services/filteredLandingPage.service';
|
||||
|
||||
const filteredLandingPageService = new FilteredLandingPageService(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.');
|
||||
}
|
||||
|
||||
// Verify token and get user info
|
||||
const userInfo = await verifyUserToken(token);
|
||||
const userId = Number(userInfo.id);
|
||||
|
||||
if (!userId || isNaN(userId)) {
|
||||
throw new ApiError(400, 'Invalid user ID');
|
||||
}
|
||||
|
||||
const page = Number(event.queryStringParameters?.page ?? 1);
|
||||
const limit = Number(event.queryStringParameters?.limit ?? 20);
|
||||
const countryName = event.queryStringParameters?.countryName ?? '';
|
||||
const stateName = event.queryStringParameters?.stateName ?? '';
|
||||
const cityName = event.queryStringParameters?.cityName ?? '';
|
||||
const userLat = event.queryStringParameters?.userLat ?? '';
|
||||
const userLong = event.queryStringParameters?.userLong ?? '';
|
||||
|
||||
let activityTypeXids: number[] | undefined;
|
||||
if (event.queryStringParameters?.activityTypeXids) {
|
||||
try {
|
||||
activityTypeXids = JSON.parse(event.queryStringParameters.activityTypeXids);
|
||||
} catch (error) {
|
||||
// Handle invalid JSON if needed
|
||||
}
|
||||
}
|
||||
|
||||
if (page < 1 || limit < 1) {
|
||||
throw new ApiError(400, 'Invalid pagination values');
|
||||
}
|
||||
|
||||
// Fetch filtered landing page details
|
||||
const result = await filteredLandingPageService.getFilteredLandingPageAllDetails(
|
||||
userId,
|
||||
page,
|
||||
limit,
|
||||
countryName,
|
||||
stateName,
|
||||
cityName,
|
||||
userLat,
|
||||
userLong,
|
||||
activityTypeXids
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: 'Filtered landing page data retrieved successfully',
|
||||
data: result,
|
||||
}),
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { safeHandler } from '../../../../common/utils/handlers/safeHandler';
|
||||
import { prismaClient } from '../../../../common/database/prisma.lambda.service';
|
||||
import ApiError from '../../../../common/utils/helper/ApiError';
|
||||
import { UserService } from '../../services/user.service';
|
||||
import { verifyUserToken } from '../../../../common/middlewares/jwt/authForUser';
|
||||
|
||||
const userService = new UserService(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.');
|
||||
}
|
||||
|
||||
// Verify token and get user info
|
||||
const userInfo = await verifyUserToken(token);
|
||||
const userId = Number(userInfo.id);
|
||||
|
||||
if (!userId || isNaN(userId)) {
|
||||
throw new ApiError(400, 'Invalid user ID');
|
||||
}
|
||||
|
||||
// Fetch user with their HostHeader stepper info
|
||||
const result = await userService.getAllBucketActivities(
|
||||
userId
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: 'Data retrieved successfully',
|
||||
data: result,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -27,16 +27,16 @@ export const handler = safeHandler(async (
|
||||
const longParam = event.queryStringParameters?.long ?? event.queryStringParameters?.lng ?? event.queryStringParameters?.longitude;
|
||||
const radiusParam = event.queryStringParameters?.radiusKm ?? event.queryStringParameters?.radius;
|
||||
|
||||
if (!latParam || !longParam || !radiusParam) {
|
||||
throw new ApiError(400, 'lat, long and radiusKm (in km) are required as query parameters');
|
||||
}
|
||||
const userLat = latParam ? Number(latParam) : undefined;
|
||||
const userLong = longParam ? Number(longParam) : undefined;
|
||||
const radiusKm = radiusParam ? Number(radiusParam) : 15; // default 15km
|
||||
|
||||
const userLat = Number(latParam);
|
||||
const userLong = Number(longParam);
|
||||
const radiusKm = Number(radiusParam);
|
||||
|
||||
if (Number.isNaN(userLat) || Number.isNaN(userLong) || Number.isNaN(radiusKm)) {
|
||||
throw new ApiError(400, 'lat, long and radiusKm must be valid numbers');
|
||||
if (
|
||||
(userLat !== undefined && Number.isNaN(userLat)) ||
|
||||
(userLong !== undefined && Number.isNaN(userLong)) ||
|
||||
Number.isNaN(radiusKm)
|
||||
) {
|
||||
throw new ApiError(400, 'Invalid lat/long values');
|
||||
}
|
||||
|
||||
const page = Number(event.queryStringParameters?.page ?? 1);
|
||||
|
||||
@@ -26,19 +26,11 @@ export const handler = safeHandler(async (
|
||||
}
|
||||
|
||||
// Extract query parameters for search
|
||||
const activityTitle = event.queryStringParameters?.activityTitle?.trim();
|
||||
const activityType = event.queryStringParameters?.activityType?.trim();
|
||||
const checkInCity = event.queryStringParameters?.checkInCity?.trim();
|
||||
|
||||
// At least one search parameter should be provided
|
||||
if (!activityTitle && !activityType && !checkInCity) {
|
||||
throw new ApiError(400, 'At least one search parameter (activityTitle, activityType, or checkInCity) must be provided');
|
||||
}
|
||||
|
||||
// Fetch activities based on search criteria
|
||||
const result = await userService.searchActivities(
|
||||
userId,
|
||||
{ activityTitle, activityType, checkInCity }
|
||||
activityType
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { prismaClient } from '../../../../common/database/prisma.lambda.service';
|
||||
import { verifyUserToken } from '../../../../common/middlewares/jwt/authForUser';
|
||||
import { safeHandler } from '../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../common/utils/helper/ApiError';
|
||||
import { UserService } from '../../services/user.service';
|
||||
|
||||
const userService = new UserService(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 verifyUserToken
|
||||
const userInfo = await verifyUserToken(token);
|
||||
const userId = userInfo.id;
|
||||
|
||||
if (Number.isNaN(userId)) {
|
||||
throw new ApiError(400, 'User id must be a number');
|
||||
}
|
||||
|
||||
const user = await userService.getUserById(userId);
|
||||
if (!user) {
|
||||
throw new ApiError(404, 'User not found');
|
||||
}
|
||||
|
||||
// Parse request body
|
||||
let body: { activityXid: number; isBucket: boolean; bucketTypeName: string; };
|
||||
|
||||
try {
|
||||
body = event.body ? JSON.parse(event.body) : {};
|
||||
} catch (error) {
|
||||
throw new ApiError(400, 'Invalid JSON in request body');
|
||||
}
|
||||
|
||||
const { activityXid, isBucket, bucketTypeName } = body;
|
||||
|
||||
// Validate required fields
|
||||
if (
|
||||
typeof activityXid !== 'number' ||
|
||||
typeof isBucket !== 'boolean' ||
|
||||
!bucketTypeName
|
||||
) {
|
||||
throw new ApiError(400, 'Required fields missing or invalid');
|
||||
}
|
||||
|
||||
// Remove from bucket/interested
|
||||
const counts = await userService.removeFromBucketInterested(userId, isBucket, bucketTypeName, activityXid);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
success: true,
|
||||
message: `Activity removed from ${isBucket ? 'bucket' : 'interested'} successfully`,
|
||||
data: {
|
||||
bucketCount: counts.bucketCount,
|
||||
interestedCount: counts.interestedCount,
|
||||
}
|
||||
}),
|
||||
};
|
||||
});
|
||||
@@ -45,8 +45,6 @@ export const handler = safeHandler(async (
|
||||
throw new ApiError(400, 'Invalid schoolCompanyXids');
|
||||
}
|
||||
|
||||
console.log('schoolCompanyXids', schoolCompanyXids);
|
||||
|
||||
const result = await userService.getAllActivitiesFromConnectionsUserInterests(
|
||||
userId,
|
||||
schoolCompanyXids,
|
||||
|
||||
938
src/modules/user/services/filteredLandingPage.service.ts
Normal file
938
src/modules/user/services/filteredLandingPage.service.ts
Normal file
@@ -0,0 +1,938 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { getPresignedUrl } from '../../../common/middlewares/aws/getPreSignedUrl';
|
||||
import {
|
||||
ACTIVITY_AM_INTERNAL_STATUS,
|
||||
ACTIVITY_INTERNAL_STATUS,
|
||||
} from '../../../common/utils/constants/host.constant';
|
||||
import config from '../../../config/config';
|
||||
|
||||
const bucket = config.aws.bucketName;
|
||||
|
||||
const attachPresignedUrl = async (file: string | null | undefined) => {
|
||||
if (!file) return null;
|
||||
|
||||
const key = file.startsWith('http')
|
||||
? new URL(file).pathname.replace(/^\/+/, '')
|
||||
: file;
|
||||
|
||||
return getPresignedUrl(bucket, key);
|
||||
};
|
||||
|
||||
const attachMediaWithPresignedUrl = async (mediaArr: any[] = []) => {
|
||||
return Promise.all(
|
||||
mediaArr.map(async (m) => ({
|
||||
...m,
|
||||
presignedUrl: await attachPresignedUrl(m.mediaFileName),
|
||||
})),
|
||||
);
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class FilteredLandingPageService {
|
||||
constructor(private readonly prisma: PrismaClient) { }
|
||||
|
||||
normalizeName = (name: string): string => {
|
||||
return name
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9\s]/g, '')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim();
|
||||
};
|
||||
|
||||
findOrCreateLocation = async (
|
||||
countryName: string,
|
||||
stateName: string,
|
||||
cityName: string,
|
||||
tx: any,
|
||||
) => {
|
||||
const normalizedCountry = this.normalizeName(countryName);
|
||||
const normalizedState = this.normalizeName(stateName);
|
||||
const normalizedCity = this.normalizeName(cityName);
|
||||
|
||||
let country = await tx.countries.findFirst({
|
||||
where: {
|
||||
countryName: { contains: normalizedCountry, mode: 'insensitive' },
|
||||
},
|
||||
});
|
||||
|
||||
if (!country) {
|
||||
country = await tx.countries.create({
|
||||
data: {
|
||||
countryName: countryName.trim(),
|
||||
isActive: true,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let state = await tx.states.findFirst({
|
||||
where: {
|
||||
countryXid: country.id,
|
||||
stateName: { contains: normalizedState, mode: 'insensitive' },
|
||||
},
|
||||
});
|
||||
|
||||
if (!state) {
|
||||
state = await tx.states.create({
|
||||
data: {
|
||||
countryXid: country.id,
|
||||
stateName: stateName.trim(),
|
||||
isActive: true,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let city = await tx.cities.findFirst({
|
||||
where: {
|
||||
stateXid: state.id,
|
||||
cityName: { contains: normalizedCity, mode: 'insensitive' },
|
||||
},
|
||||
});
|
||||
|
||||
if (!city) {
|
||||
city = await tx.cities.create({
|
||||
data: {
|
||||
stateXid: state.id,
|
||||
cityName: cityName.trim(),
|
||||
isActive: true,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
countryXid: country.id,
|
||||
stateXid: state.id,
|
||||
cityXid: city.id,
|
||||
};
|
||||
};
|
||||
|
||||
// attachMediaWithPresignedUrl = async (mediaArr = []) => {
|
||||
// return (
|
||||
// await Promise.all(
|
||||
// mediaArr.map(async (m) => {
|
||||
// return {
|
||||
// ...m,
|
||||
// presignedUrl: await this.attachPresignedUrl(m.mediaFileName),
|
||||
// };
|
||||
// }),
|
||||
// )
|
||||
// );
|
||||
// };
|
||||
|
||||
calculateDistance = (
|
||||
lat1: number | null,
|
||||
lon1: number | null,
|
||||
lat2: number | null,
|
||||
lon2: number | null,
|
||||
) => {
|
||||
if (!lat1 || !lon1 || !lat2 || !lon2) return null;
|
||||
|
||||
const R = 6371; // km
|
||||
const dLat = ((lat2 - lat1) * Math.PI) / 180;
|
||||
const dLon = ((lon2 - lon1) * Math.PI) / 180;
|
||||
|
||||
const a =
|
||||
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
||||
Math.cos((lat1 * Math.PI) / 180) *
|
||||
Math.cos((lat2 * Math.PI) / 180) *
|
||||
Math.sin(dLon / 2) *
|
||||
Math.sin(dLon / 2);
|
||||
|
||||
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||
const distance = R * c;
|
||||
|
||||
// return distance rounded to 2 decimals
|
||||
return Number(distance.toFixed(2));
|
||||
};
|
||||
|
||||
async rankAndPaginateActivities(
|
||||
tx: any,
|
||||
whereClause: any,
|
||||
page: number,
|
||||
limit: number,
|
||||
connectionInterestMap: Map<number, number>,
|
||||
) {
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
// Get total count
|
||||
const totalCount = await tx.activities.count({ where: whereClause });
|
||||
|
||||
// Fetch activities with ranking metadata
|
||||
const activities = await tx.activities.findMany({
|
||||
where: whereClause,
|
||||
skip,
|
||||
take: limit,
|
||||
select: {
|
||||
id: true,
|
||||
activityTitle: true,
|
||||
sustainabilityScore: true,
|
||||
totalScore: true,
|
||||
activityType: {
|
||||
select: {
|
||||
interestXid: true,
|
||||
energyLevel: {
|
||||
select: {
|
||||
id: true,
|
||||
energyLevelName: true,
|
||||
energyColor: true,
|
||||
energyIcon: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ActivitiesMedia: {
|
||||
where: { isActive: true },
|
||||
select: {
|
||||
id: true,
|
||||
mediaFileName: true,
|
||||
mediaType: true,
|
||||
},
|
||||
},
|
||||
// Fetch ranking metadata
|
||||
ItineraryActivities: {
|
||||
select: {
|
||||
ActivityFeedbacks: {
|
||||
select: { activityStars: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
ActivityVenues: {
|
||||
select: {
|
||||
ActivityPrices: {
|
||||
select: { sellPrice: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Sort and format
|
||||
const sortedActivities = activities
|
||||
.map((act) => {
|
||||
const feedbacks = act.ItineraryActivities.flatMap(
|
||||
(ia) => ia.ActivityFeedbacks,
|
||||
);
|
||||
const totalStars = feedbacks.reduce(
|
||||
(sum, f) => sum + f.activityStars,
|
||||
0,
|
||||
);
|
||||
const avgRating =
|
||||
feedbacks.length > 0 ? totalStars / feedbacks.length : 0;
|
||||
const prices = act.ActivityVenues.flatMap((v) =>
|
||||
v.ActivityPrices.map((p) => p.sellPrice),
|
||||
).filter((p) => p !== null) as number[];
|
||||
const minPrice = prices.length > 0 ? Math.min(...prices) : Infinity;
|
||||
|
||||
return {
|
||||
...act,
|
||||
avgRating,
|
||||
minPrice,
|
||||
sustainabilityScore: act.sustainabilityScore ?? 0,
|
||||
totalScore: act.totalScore ?? 0,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
if (b.avgRating !== a.avgRating) return b.avgRating - a.avgRating;
|
||||
if (a.minPrice !== b.minPrice) return a.minPrice - b.minPrice;
|
||||
if (b.sustainabilityScore !== a.sustainabilityScore)
|
||||
return b.sustainabilityScore - a.sustainabilityScore;
|
||||
return b.totalScore - a.totalScore;
|
||||
});
|
||||
|
||||
const formattedActivities = await Promise.all(
|
||||
sortedActivities.map(async (activity) => ({
|
||||
interestXid: activity.activityType.interestXid,
|
||||
activityId: activity.id,
|
||||
connectionInterestedCount:
|
||||
connectionInterestMap.get(activity.id) ?? 0,
|
||||
activityTitle: activity.activityTitle,
|
||||
sustainabilityScore: activity.sustainabilityScore,
|
||||
cheapestPrice: activity.minPrice === Infinity ? null : activity.minPrice,
|
||||
distance: 0,
|
||||
rating: activity.avgRating,
|
||||
energyLevel: activity.activityType.energyLevel
|
||||
? {
|
||||
...activity.activityType.energyLevel,
|
||||
presignedUrl: await attachPresignedUrl(
|
||||
activity.activityType.energyLevel.energyIcon
|
||||
),
|
||||
}
|
||||
: null,
|
||||
media: await attachMediaWithPresignedUrl(activity.ActivitiesMedia),
|
||||
})),
|
||||
);
|
||||
|
||||
return {
|
||||
page,
|
||||
limit,
|
||||
totalCount,
|
||||
hasMore: skip + limit < totalCount,
|
||||
activities: formattedActivities,
|
||||
};
|
||||
}
|
||||
|
||||
async getFilteredLandingPageAllDetails(
|
||||
userId: number,
|
||||
page: number,
|
||||
limit: number,
|
||||
countryName: string,
|
||||
stateName: string,
|
||||
cityName: string,
|
||||
userLat: string,
|
||||
userLong: string,
|
||||
activityTypeXids?: number[],
|
||||
) {
|
||||
const data = await this.prisma.$transaction(async (tx) => {
|
||||
const userAddressDetails = await tx.userAddressDetails.findFirst({
|
||||
where: { userXid: userId, isActive: true },
|
||||
select: {
|
||||
id: true,
|
||||
address1: true,
|
||||
address2: true,
|
||||
pinCode: true,
|
||||
locationName: true,
|
||||
stateXid: true,
|
||||
cityXid: true,
|
||||
countryXid: true,
|
||||
locationLat: true,
|
||||
locationLong: true,
|
||||
},
|
||||
});
|
||||
|
||||
const userLatitude = userAddressDetails?.locationLat ?? null;
|
||||
const userLongitude = userAddressDetails?.locationLong ?? null;
|
||||
|
||||
let effectiveLocation: {
|
||||
countryXid?: number | null;
|
||||
stateXid?: number | null;
|
||||
cityXid?: number | null;
|
||||
} | null = null;
|
||||
|
||||
const hasRequestLocation = countryName && stateName && cityName;
|
||||
|
||||
if (hasRequestLocation) {
|
||||
effectiveLocation = await this.findOrCreateLocation(
|
||||
countryName!,
|
||||
stateName!,
|
||||
cityName!,
|
||||
tx,
|
||||
);
|
||||
} else if (userAddressDetails) {
|
||||
effectiveLocation = {
|
||||
countryXid: userAddressDetails.countryXid,
|
||||
stateXid: userAddressDetails.stateXid,
|
||||
cityXid: userAddressDetails.cityXid,
|
||||
};
|
||||
}
|
||||
|
||||
const effectiveCountryXid = effectiveLocation?.countryXid ?? null;
|
||||
const effectiveStateXid = effectiveLocation?.stateXid ?? null;
|
||||
|
||||
// Get all activity types for user interests, filtered by selected activity types if provided
|
||||
const activityTypeWhere: any = {
|
||||
isActive: true,
|
||||
};
|
||||
|
||||
if (activityTypeXids && activityTypeXids.length > 0) {
|
||||
activityTypeWhere.id = { in: activityTypeXids };
|
||||
}
|
||||
|
||||
const activityTypesWithInterests = await tx.activityTypes.findMany({
|
||||
where: activityTypeWhere,
|
||||
select: {
|
||||
id: true,
|
||||
activityTypeName: true,
|
||||
interestXid: true,
|
||||
interests: {
|
||||
select: {
|
||||
id: true,
|
||||
interestName: true,
|
||||
interestColor: true,
|
||||
interestImage: true,
|
||||
displayOrder: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!activityTypesWithInterests.length) {
|
||||
return {
|
||||
userAddressDetails,
|
||||
interests: [],
|
||||
activityTypes: [],
|
||||
otherStatesActivities: null,
|
||||
overSeasActivities: null,
|
||||
};
|
||||
}
|
||||
|
||||
const userBucketInterested = await tx.userBucketInterested.findMany({
|
||||
where: {
|
||||
userXid: userId,
|
||||
isActive: true,
|
||||
},
|
||||
select: {
|
||||
activityXid: true,
|
||||
isBucket: true,
|
||||
},
|
||||
});
|
||||
|
||||
const userBucketActivityIds = userBucketInterested
|
||||
.filter(u => u.isBucket)
|
||||
.map(u => u.activityXid);
|
||||
|
||||
const userInterestedActivityIds = userBucketInterested
|
||||
.filter(u => !u.isBucket)
|
||||
.map(u => u.activityXid);
|
||||
|
||||
const allUserExcludedActivityIds = userBucketInterested.map(
|
||||
u => u.activityXid,
|
||||
);
|
||||
|
||||
const userConnectionDetails = await tx.connectDetails.findMany({
|
||||
where: { userXid: userId, isActive: true },
|
||||
select: {
|
||||
id: true,
|
||||
schoolCompanyXid: true,
|
||||
}
|
||||
});
|
||||
|
||||
const otherConnectionUsers = await tx.connectDetails.findMany({
|
||||
where: { userXid: { notIn: [userId] }, isActive: true, schoolCompanyXid: { in: userConnectionDetails.map((u) => u.schoolCompanyXid) } },
|
||||
select: {
|
||||
id: true,
|
||||
userXid: true,
|
||||
}
|
||||
});
|
||||
|
||||
const connectionUserIds =
|
||||
otherConnectionUsers.length > 0
|
||||
? otherConnectionUsers.map(u => u.userXid)
|
||||
: [-1];
|
||||
|
||||
const connectionInterestByActivity = await tx.userBucketInterested.groupBy({
|
||||
by: ['activityXid'],
|
||||
where: {
|
||||
userXid: { in: connectionUserIds },
|
||||
isActive: true,
|
||||
},
|
||||
_count: {
|
||||
activityXid: true,
|
||||
},
|
||||
});
|
||||
|
||||
const connectionInterestMap = new Map(
|
||||
connectionInterestByActivity.map(item => [
|
||||
item.activityXid,
|
||||
item._count.activityXid,
|
||||
])
|
||||
);
|
||||
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
// Group activity types by interest
|
||||
const activityTypesByInterest = activityTypesWithInterests.reduce((acc, at) => {
|
||||
if (!acc[at.interestXid]) {
|
||||
acc[at.interestXid] = {
|
||||
interest: at.interests,
|
||||
activityTypes: [],
|
||||
};
|
||||
}
|
||||
acc[at.interestXid].activityTypes.push({
|
||||
activityTypeId: at.id,
|
||||
activityTypeName: at.activityTypeName,
|
||||
});
|
||||
return acc;
|
||||
}, {} as any);
|
||||
|
||||
// Fetch activities for each activity type with excluded activities filter
|
||||
const activitiesByActivityType = await Promise.all(
|
||||
activityTypesWithInterests.map(async (activityType) => {
|
||||
const activities = await tx.activities.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
amInternalStatus: ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
activityTypeXid: activityType.id,
|
||||
id: {
|
||||
notIn: allUserExcludedActivityIds.length
|
||||
? allUserExcludedActivityIds
|
||||
: [-1],
|
||||
},
|
||||
},
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy: { id: 'desc' },
|
||||
select: {
|
||||
id: true,
|
||||
activityTitle: true,
|
||||
activityDurationMins: true,
|
||||
sustainabilityScore: true,
|
||||
checkInLat: true,
|
||||
checkInLong: true,
|
||||
activityType: {
|
||||
select: {
|
||||
id: true,
|
||||
activityTypeName: true,
|
||||
interestXid: true,
|
||||
energyLevel: {
|
||||
select: {
|
||||
id: true,
|
||||
energyLevelName: true,
|
||||
energyColor: true,
|
||||
energyIcon: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ActivityVenues: {
|
||||
select: {
|
||||
ActivityPrices: {
|
||||
select: {
|
||||
sellPrice: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ActivitiesMedia: {
|
||||
where: { isActive: true },
|
||||
select: {
|
||||
id: true,
|
||||
mediaFileName: true,
|
||||
mediaType: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const formattedActivities = await Promise.all(
|
||||
activities.map(async (activity) => {
|
||||
const cheapestPrice =
|
||||
activity.ActivityVenues.flatMap((v) => v.ActivityPrices)
|
||||
.map((p) => p.sellPrice)
|
||||
.filter(Boolean)
|
||||
.sort((a, b) => a - b)[0] ?? null;
|
||||
|
||||
const distance = this.calculateDistance(
|
||||
userLatitude,
|
||||
userLongitude,
|
||||
activity.checkInLat,
|
||||
activity.checkInLong,
|
||||
);
|
||||
|
||||
return {
|
||||
activityId: activity.id,
|
||||
connectionInterestedCount:
|
||||
connectionInterestMap.get(activity.id) ?? 0,
|
||||
activityTitle: activity.activityTitle,
|
||||
activityDurationMins: activity.activityDurationMins,
|
||||
sustainabilityScore: activity.sustainabilityScore,
|
||||
cheapestPrice,
|
||||
distance,
|
||||
rating: 0,
|
||||
energyLevel: activity.activityType.energyLevel
|
||||
? {
|
||||
...activity.activityType.energyLevel,
|
||||
presignedUrl: await attachPresignedUrl(
|
||||
activity.activityType.energyLevel.energyIcon
|
||||
),
|
||||
}
|
||||
: null,
|
||||
media: await attachMediaWithPresignedUrl(activity.ActivitiesMedia),
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
return {
|
||||
activityTypeId: activityType.id,
|
||||
activityTypeName: activityType.activityTypeName,
|
||||
interestXid: activityType.interestXid,
|
||||
activities: formattedActivities,
|
||||
pagination: {
|
||||
page,
|
||||
limit,
|
||||
hasMore: formattedActivities.length === limit,
|
||||
},
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
// Group by interests for the final structure
|
||||
const interestsWithActivities = await Promise.all(
|
||||
Object.values(activityTypesByInterest).map(async (interestGroup: any) => {
|
||||
// collect all activities belonging to this interest
|
||||
const activitiesForInterest = activitiesByActivityType
|
||||
.filter(a => a.interestXid === interestGroup.interest.id)
|
||||
.flatMap(a => a.activities);
|
||||
|
||||
return {
|
||||
interestId: interestGroup.interest.id,
|
||||
interestName: interestGroup.interest.interestName,
|
||||
interestColor: interestGroup.interest.interestColor,
|
||||
interestImage: interestGroup.interest.interestImage,
|
||||
interestImagePresignedUrl: await attachPresignedUrl(
|
||||
interestGroup.interest.interestImage
|
||||
),
|
||||
displayOrder: interestGroup.interest.displayOrder,
|
||||
page,
|
||||
limit,
|
||||
hasMore: activitiesForInterest.length === limit,
|
||||
activities: activitiesForInterest
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
// Most Hyped Activities with filtering
|
||||
const mostHypedGrouped = await tx.userBucketInterested.groupBy({
|
||||
by: ['activityXid'],
|
||||
where: {
|
||||
isActive: true,
|
||||
isBucket: false,
|
||||
activityXid: {
|
||||
notIn: allUserExcludedActivityIds.length ? allUserExcludedActivityIds : [-1],
|
||||
},
|
||||
},
|
||||
_count: {
|
||||
activityXid: true,
|
||||
},
|
||||
orderBy: {
|
||||
_count: {
|
||||
activityXid: 'desc',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Filter most hyped activities by activity type if provided
|
||||
let filteredMostHypedActivityIds = mostHypedGrouped.map((a) => a.activityXid);
|
||||
|
||||
if (activityTypeXids && activityTypeXids.length > 0) {
|
||||
const activitiesWithTypes = await tx.activities.findMany({
|
||||
where: {
|
||||
id: { in: filteredMostHypedActivityIds },
|
||||
activityTypeXid: { in: activityTypeXids },
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
filteredMostHypedActivityIds = activitiesWithTypes.map(a => a.id);
|
||||
}
|
||||
|
||||
const finalMostHypedGrouped = mostHypedGrouped
|
||||
.filter(group => filteredMostHypedActivityIds.includes(group.activityXid))
|
||||
.slice(skip, skip + limit);
|
||||
|
||||
const totalHypedActivities = filteredMostHypedActivityIds.length;
|
||||
const mostHypedActivityIds = finalMostHypedGrouped.map((a) => a.activityXid);
|
||||
|
||||
const mostHypedActivitiesRaw = await tx.activities.findMany({
|
||||
where: {
|
||||
id: {
|
||||
in: mostHypedActivityIds,
|
||||
notIn: allUserExcludedActivityIds.length
|
||||
? allUserExcludedActivityIds
|
||||
: [-1],
|
||||
},
|
||||
isActive: true,
|
||||
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
amInternalStatus: ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
activityTitle: true,
|
||||
sustainabilityScore: true,
|
||||
totalScore: true,
|
||||
activityType: {
|
||||
select: {
|
||||
energyLevel: {
|
||||
select: {
|
||||
id: true,
|
||||
energyLevelName: true,
|
||||
energyColor: true,
|
||||
energyIcon: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ActivitiesMedia: {
|
||||
where: { isActive: true },
|
||||
select: {
|
||||
id: true,
|
||||
mediaFileName: true,
|
||||
mediaType: true,
|
||||
},
|
||||
},
|
||||
ItineraryActivities: {
|
||||
select: {
|
||||
ActivityFeedbacks: {
|
||||
select: { activityStars: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
ActivityVenues: {
|
||||
select: {
|
||||
ActivityPrices: {
|
||||
select: { sellPrice: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Sort Most Hyped by the 4 criteria
|
||||
const mostHypedSorted = mostHypedActivitiesRaw
|
||||
.map((act) => {
|
||||
const feedbacks = act.ItineraryActivities.flatMap(
|
||||
(ia) => ia.ActivityFeedbacks,
|
||||
);
|
||||
const totalStars = feedbacks.reduce(
|
||||
(sum, f) => sum + f.activityStars,
|
||||
0,
|
||||
);
|
||||
const avgRating =
|
||||
feedbacks.length > 0 ? totalStars / feedbacks.length : 0;
|
||||
const prices = act.ActivityVenues.flatMap((v) =>
|
||||
v.ActivityPrices.map((p) => p.sellPrice),
|
||||
).filter((p) => p !== null) as number[];
|
||||
const minPrice = prices.length > 0 ? Math.min(...prices) : Infinity;
|
||||
|
||||
return {
|
||||
...act,
|
||||
avgRating,
|
||||
minPrice,
|
||||
sustainabilityScore: act.sustainabilityScore ?? 0,
|
||||
totalScore: act.totalScore ?? 0,
|
||||
hypeCount:
|
||||
finalMostHypedGrouped.find((g) => g.activityXid === act.id)?._count
|
||||
.activityXid ?? 0,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
if (b.avgRating !== a.avgRating) return b.avgRating - a.avgRating;
|
||||
if (a.minPrice !== b.minPrice) return a.minPrice - b.minPrice;
|
||||
if (b.sustainabilityScore !== a.sustainabilityScore)
|
||||
return b.sustainabilityScore - a.sustainabilityScore;
|
||||
return b.totalScore - a.totalScore;
|
||||
});
|
||||
|
||||
const mostHypedActivities = await Promise.all(
|
||||
mostHypedSorted.map(async (activity) => ({
|
||||
activityId: activity.id,
|
||||
activityTitle: activity.activityTitle,
|
||||
connectionInterestedCount:
|
||||
connectionInterestMap.get(activity.id) ?? 0,
|
||||
hypeCount: activity.hypeCount,
|
||||
distance: 0,
|
||||
rating: 0,
|
||||
energyLevel: activity.activityType.energyLevel
|
||||
? {
|
||||
...activity.activityType.energyLevel,
|
||||
presignedUrl: await attachPresignedUrl(
|
||||
activity.activityType.energyLevel.energyIcon
|
||||
),
|
||||
}
|
||||
: null,
|
||||
media: await attachMediaWithPresignedUrl(activity.ActivitiesMedia),
|
||||
})),
|
||||
);
|
||||
|
||||
const formattedMostHypedActivities = {
|
||||
page,
|
||||
limit,
|
||||
totalCount: totalHypedActivities,
|
||||
hasMore: skip + limit < totalHypedActivities,
|
||||
activities: mostHypedActivities,
|
||||
};
|
||||
|
||||
// New Arrivals with filtering
|
||||
const newArrivalsWhere: any = {
|
||||
isActive: true,
|
||||
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
amInternalStatus: ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
id: {
|
||||
notIn: allUserExcludedActivityIds.length
|
||||
? allUserExcludedActivityIds
|
||||
: [-1],
|
||||
},
|
||||
createdAt: { gte: new Date(Date.now() - 31 * 24 * 60 * 60 * 1000) },
|
||||
};
|
||||
|
||||
if (activityTypeXids && activityTypeXids.length > 0) {
|
||||
newArrivalsWhere.activityTypeXid = { in: activityTypeXids };
|
||||
}
|
||||
|
||||
const formattedNewArrivalsActivities = await this.rankAndPaginateActivities(
|
||||
tx,
|
||||
newArrivalsWhere,
|
||||
page,
|
||||
limit,
|
||||
connectionInterestMap
|
||||
);
|
||||
|
||||
// Other States Activities with filtering
|
||||
const otherStatesWhere: any = {
|
||||
isActive: true,
|
||||
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
amInternalStatus: ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
id: {
|
||||
notIn: allUserExcludedActivityIds.length
|
||||
? allUserExcludedActivityIds
|
||||
: [-1],
|
||||
},
|
||||
};
|
||||
|
||||
if (effectiveCountryXid) {
|
||||
otherStatesWhere.checkInCountryXid = effectiveCountryXid;
|
||||
}
|
||||
if (effectiveStateXid) {
|
||||
otherStatesWhere.checkInStateXid = { not: effectiveStateXid };
|
||||
}
|
||||
if (activityTypeXids && activityTypeXids.length > 0) {
|
||||
otherStatesWhere.activityTypeXid = { in: activityTypeXids };
|
||||
}
|
||||
|
||||
const formattedOtherStatesActivities = await this.rankAndPaginateActivities(
|
||||
tx,
|
||||
otherStatesWhere,
|
||||
page,
|
||||
limit,
|
||||
connectionInterestMap
|
||||
);
|
||||
|
||||
// Random Activities with filtering
|
||||
const totalActiveCount = await tx.activities.count({
|
||||
where: {
|
||||
isActive: true,
|
||||
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
amInternalStatus: ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
deletedAt: null,
|
||||
id: {
|
||||
notIn: allUserExcludedActivityIds.length
|
||||
? allUserExcludedActivityIds
|
||||
: [-1],
|
||||
},
|
||||
...(activityTypeXids && activityTypeXids.length > 0 && {
|
||||
activityTypeXid: { in: activityTypeXids },
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
let randomActivities: any[] = [];
|
||||
|
||||
if (totalActiveCount > 0) {
|
||||
const takeCount = Math.min(5, totalActiveCount);
|
||||
|
||||
const randomOffsets = new Set<number>();
|
||||
while (randomOffsets.size < takeCount) {
|
||||
randomOffsets.add(Math.floor(Math.random() * totalActiveCount));
|
||||
}
|
||||
|
||||
const randomFetched = await Promise.all(
|
||||
Array.from(randomOffsets).map((offset) =>
|
||||
tx.activities.findFirst({
|
||||
skip: offset,
|
||||
where: {
|
||||
isActive: true,
|
||||
activityInternalStatus:
|
||||
ACTIVITY_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
amInternalStatus:
|
||||
ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
deletedAt: null,
|
||||
id: {
|
||||
notIn: allUserExcludedActivityIds.length
|
||||
? allUserExcludedActivityIds
|
||||
: [-1],
|
||||
},
|
||||
...(activityTypeXids && activityTypeXids.length > 0 && {
|
||||
activityTypeXid: { in: activityTypeXids },
|
||||
}),
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
activityTitle: true,
|
||||
ActivitiesMedia: {
|
||||
where: { isActive: true, isCoverImage: true },
|
||||
orderBy: { displayOrder: 'asc' },
|
||||
take: 1,
|
||||
select: {
|
||||
mediaFileName: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
randomActivities = await Promise.all(
|
||||
randomFetched
|
||||
.filter(Boolean)
|
||||
.map(async (activity) => {
|
||||
const cover = activity!.ActivitiesMedia?.[0];
|
||||
|
||||
return {
|
||||
activityId: activity!.id,
|
||||
activityTitle: activity!.activityTitle,
|
||||
coverImage: cover?.mediaFileName ?? null,
|
||||
coverImagePresignedUrl: await attachPresignedUrl(
|
||||
cover?.mediaFileName
|
||||
),
|
||||
};
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// Overseas Activities with filtering
|
||||
const overseasWhere: any = {
|
||||
isActive: true,
|
||||
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
amInternalStatus: ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
id: {
|
||||
notIn: allUserExcludedActivityIds.length
|
||||
? allUserExcludedActivityIds
|
||||
: [-1],
|
||||
},
|
||||
};
|
||||
|
||||
if (effectiveCountryXid) {
|
||||
overseasWhere.checkInCountryXid = { not: effectiveCountryXid };
|
||||
}
|
||||
if (activityTypeXids && activityTypeXids.length > 0) {
|
||||
overseasWhere.activityTypeXid = { in: activityTypeXids };
|
||||
}
|
||||
|
||||
const formattedOverSeasActivities = await this.rankAndPaginateActivities(
|
||||
tx,
|
||||
overseasWhere,
|
||||
page,
|
||||
limit,
|
||||
connectionInterestMap
|
||||
);
|
||||
|
||||
return {
|
||||
userAddressDetails,
|
||||
experiencesLogged: 0,
|
||||
citiesDiscovered: 0,
|
||||
loggedInNetworkCount: 0,
|
||||
citiesInNetworkCount: 0,
|
||||
rating: 0,
|
||||
interestedCount: userInterestedActivityIds.length,
|
||||
bucketCount: userBucketActivityIds.length,
|
||||
pagination: {
|
||||
page,
|
||||
limit,
|
||||
},
|
||||
randomActivities,
|
||||
interests: interestsWithActivities,
|
||||
otherStatesActivities: formattedOtherStatesActivities,
|
||||
overSeasActivities: formattedOverSeasActivities,
|
||||
newArrivalsActivities: formattedNewArrivalsActivities,
|
||||
mostHypedActivities: formattedMostHypedActivities,
|
||||
};
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user