From 1936c42c716ead9bb33bc2702c769911b9f021bc Mon Sep 17 00:00:00 2001 From: Bhaskar Date: Wed, 10 Sep 2025 16:38:19 +0530 Subject: [PATCH] upload-installation profile --- node_modules/.package-lock.json | 104 +++++++++++++++++- package-lock.json | 188 ++++++++++++++++++++++++++++++-- package.json | 1 + src/index.js | 112 ++++++++++++++++++- 4 files changed, 392 insertions(+), 13 deletions(-) diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index 2fba4b49..d1947646 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -175,6 +175,17 @@ "node": ">=10" } }, + "node_modules/@adminjs/fastify/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/@adminjs/fastify/node_modules/pino": { "version": "8.8.0", "resolved": "https://registry.npmjs.org/pino/-/pino-8.8.0.tgz", @@ -2766,6 +2777,17 @@ "node": ">=10.0.0" } }, + "node_modules/@google-cloud/storage/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/@grpc/grpc-js": { "version": "1.12.5", "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.12.5.tgz", @@ -4141,6 +4163,17 @@ "node": ">= 6" } }, + "node_modules/adminjs/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -4451,6 +4484,17 @@ "node": ">= 6" } }, + "node_modules/axios/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/babel-plugin-macros": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", @@ -6946,6 +6990,17 @@ "node": ">= 0.12" } }, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/formidable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.1.tgz", @@ -8884,16 +8939,24 @@ } }, "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", "dependencies": { - "mime-db": "1.52.0" + "mime-db": "^1.54.0" }, "engines": { "node": ">= 0.6" } }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -10996,6 +11059,17 @@ "node": ">= 0.12" } }, + "node_modules/request/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/request/node_modules/qs": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", @@ -12279,6 +12353,17 @@ "npm": ">=1.3.7" } }, + "node_modules/twilio/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/twilio/node_modules/oauth-sign": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", @@ -12416,6 +12501,17 @@ "node": ">= 0.6" } }, + "node_modules/type-is/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", diff --git a/package-lock.json b/package-lock.json index 76d1ef9c..401b1254 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,6 +50,7 @@ "gridfile": "^1.1.3", "image-type": "^5.2.0", "libphonenumber-js": "^1.9.6", + "mime-types": "^3.0.1", "moment": "^2.29.4", "moment-timezone": "^0.5.43", "mongodb": "^5.0.1", @@ -242,6 +243,17 @@ "node": ">=10" } }, + "node_modules/@adminjs/fastify/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/@adminjs/fastify/node_modules/pino": { "version": "8.8.0", "resolved": "https://registry.npmjs.org/pino/-/pino-8.8.0.tgz", @@ -2833,6 +2845,17 @@ "node": ">=10.0.0" } }, + "node_modules/@google-cloud/storage/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/@grpc/grpc-js": { "version": "1.12.5", "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.12.5.tgz", @@ -4208,6 +4231,17 @@ "node": ">= 6" } }, + "node_modules/adminjs/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -4518,6 +4552,17 @@ "node": ">= 6" } }, + "node_modules/axios/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/babel-plugin-macros": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", @@ -7013,6 +7058,17 @@ "node": ">= 0.12" } }, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/formidable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.1.tgz", @@ -8964,16 +9020,24 @@ } }, "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", "dependencies": { - "mime-db": "1.52.0" + "mime-db": "^1.54.0" }, "engines": { "node": ">= 0.6" } }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -11076,6 +11140,17 @@ "node": ">= 0.12" } }, + "node_modules/request/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/request/node_modules/qs": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", @@ -12359,6 +12434,17 @@ "npm": ">=1.3.7" } }, + "node_modules/twilio/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/twilio/node_modules/oauth-sign": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", @@ -12496,6 +12582,17 @@ "node": ">= 0.6" } }, + "node_modules/type-is/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -13336,6 +13433,14 @@ "yallist": "^4.0.0" } }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, "pino": { "version": "8.8.0", "resolved": "https://registry.npmjs.org/pino/-/pino-8.8.0.tgz", @@ -15216,6 +15321,14 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } } } }, @@ -16253,6 +16366,14 @@ "combined-stream": "^1.0.8", "mime-types": "^2.1.12" } + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } } } }, @@ -16514,6 +16635,14 @@ "combined-stream": "^1.0.8", "mime-types": "^2.1.12" } + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } } } }, @@ -18457,6 +18586,16 @@ "asynckit": "^0.4.0", "combined-stream": "^1.0.6", "mime-types": "^2.1.12" + }, + "dependencies": { + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + } } }, "formidable": { @@ -20035,11 +20174,18 @@ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", "requires": { - "mime-db": "1.52.0" + "mime-db": "^1.54.0" + }, + "dependencies": { + "mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==" + } } }, "mimic-fn": { @@ -21612,6 +21758,14 @@ "mime-types": "^2.1.12" } }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, "qs": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", @@ -22612,6 +22766,14 @@ "sshpk": "^1.7.0" } }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, "oauth-sign": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", @@ -22721,6 +22883,16 @@ "requires": { "media-typer": "0.3.0", "mime-types": "~2.1.24" + }, + "dependencies": { + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + } } }, "typedarray": { diff --git a/package.json b/package.json index 98c7b972..1a7208b7 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "gridfile": "^1.1.3", "image-type": "^5.2.0", "libphonenumber-js": "^1.9.6", + "mime-types": "^3.0.1", "moment": "^2.29.4", "moment-timezone": "^0.5.43", "mongodb": "^5.0.1", diff --git a/src/index.js b/src/index.js index 62c7a714..1caf0421 100644 --- a/src/index.js +++ b/src/index.js @@ -968,7 +968,7 @@ const storage = new Storage({ // } // }); const fastifyMulter = require('fastify-multer'); - +const mime = require("mime-types"); const upload = fastifyMulter({ dest: 'uploads/', limits: { @@ -1051,6 +1051,116 @@ fastify.post('/api/uploads_admin_profile/:customerId', { } }); +fastify.post("/api/uploads_installation_profile/:installationId", { + preHandler: upload.single("file"), // your multer/fastify-multipart preHandler +}, async (request, reply) => { + try { + const { installationId } = request.params; + const file = request.file; // in fastify-multer this is set by preHandler + + if (!file) { + return reply.code(400).send({ error: "No file uploaded (expected field name 'file')." }); + } + + // basic file validation + const allowed = ["image/jpeg", "image/jpg", "image/png"]; + if (!allowed.includes(file.mimetype)) { + return reply.code(400).send({ error: "Only JPEG/PNG images are allowed." }); + } + + const bucketName = "arminta_profile_pictures"; + const ext = mime.extension(file.mimetype) || (file.originalname.split(".").pop() || "png"); + const safeBase = path.parse(file.originalname).name.replace(/[^\w.-]/g, "_"); + const filePath = `arminta_team_profiles/${safeBase}-${Date.now()}.${ext}`; + + // read temp file to buffer + const fileBuffer = await fs.promises.readFile(file.path); + + // upload to GCS + const bucket = storage.bucket(bucketName); + const gcsFile = bucket.file(filePath); + await gcsFile.save(fileBuffer, { + resumable: false, + contentType: file.mimetype, + public: true, + metadata: { cacheControl: "public, max-age=31536000" }, + }); + await gcsFile.makePublic(); + + const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; + + // 1) Upsert installation profile picture collection + await ProfilePictureInstall.findOneAndUpdate( + { installationId }, + { picture: publicUrl }, + { new: true, upsert: true } + ); + + // 2) Update department doc where departmentId === installationId + const deptUpdate = await Deparments.findOneAndUpdate( + { departmentId: installationId }, + { picture: publicUrl }, + { new: true } + ); + + // 3) (Optional) also save on the installation doc itself if you keep picture there + // await Installations.findOneAndUpdate( + // { installationId }, + // { picture: publicUrl }, + // { new: true } + // ); + + return reply.send({ + installationId, + picture: publicUrl, + departmentUpdated: Boolean(deptUpdate), + message: deptUpdate + ? "Upload successful. Department picture updated." + : "Upload successful. No department matched this installationId.", + }); + } catch (err) { + request.log.error(err); + return reply.code(500).send({ error: "Upload failed", details: err.message }); + } finally { + // best effort: clean up temp file if your preHandler writes to disk + try { if (request.file?.path) await fs.promises.unlink(request.file.path); } catch {} + } +}); + +// fastify.post('/api/uploads_installation_profile/:installationId', { +// preHandler: upload.single('file') +// }, async (request, reply) => { +// try { +// const { installationId } = request.params; +// const file = await request.file; // Uncomment this line +// const formData = new FormData(); +// formData.append('file', file); +// const bucketName = 'arminta_profile_pictures'; +// const filePath = `arminta_team_profiles/${file.originalname}`; + +// const fileBuffer = await fs.promises.readFile(file.path); + +// await storage.bucket(bucketName).file(filePath).save(fileBuffer); + +// // make file public +// await storage.bucket(bucketName).file(filePath).makePublic(); +// const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; + +// // save in DB +// const picture = await ProfilePictureInstall.findOneAndUpdate( +// { installationId }, +// { picture: publicUrl }, +// { new: true, upsert: true } +// ); + +// return reply.send({ picture: publicUrl }); + +// } catch (err) { +// request.log.error(err); +// return reply.code(500).send({ error: 'Upload failed', details: err.message }); +// } +// }); + // fastify.post('/api/uploads_team_profile/:customerId', async (request, reply) => { // try { // const { customerId } = request.params;