|
|
|
@ -1051,81 +1051,81 @@ 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
|
|
|
|
|
// 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')." });
|
|
|
|
|
}
|
|
|
|
|
// 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." });
|
|
|
|
|
}
|
|
|
|
|
// // 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}`;
|
|
|
|
|
// 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);
|
|
|
|
|
// // 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();
|
|
|
|
|
// // 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}`;
|
|
|
|
|
// const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`;
|
|
|
|
|
|
|
|
|
|
// 1) Upsert installation profile picture collection
|
|
|
|
|
await ProfilePictureInstall.findOneAndUpdate(
|
|
|
|
|
{ installationId },
|
|
|
|
|
{ picture: publicUrl },
|
|
|
|
|
{ new: true, upsert: true }
|
|
|
|
|
);
|
|
|
|
|
// // 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 }
|
|
|
|
|
);
|
|
|
|
|
// // 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 }
|
|
|
|
|
// );
|
|
|
|
|
// // 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 {}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
// 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')
|
|
|
|
@ -1232,103 +1232,103 @@ fastify.post('/api/uploads_company_profile/:customerId', async (request, reply)
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
fastify.post("/api/uploads_installation_TeamMember_profile/:installationId/:teamMemberId", {
|
|
|
|
|
preHandler: upload.single("file"),
|
|
|
|
|
}, async (request, reply) => {
|
|
|
|
|
try {
|
|
|
|
|
const { installationId ,teamMemberId} = request.params;
|
|
|
|
|
//const teamMemberId = request.body?.teamMemberId; // OPTIONAL
|
|
|
|
|
const file = request.file;
|
|
|
|
|
|
|
|
|
|
if (!file) {
|
|
|
|
|
return reply.code(400).send({ error: "No file uploaded (field name 'file')." });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Validate image type
|
|
|
|
|
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." });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build GCS path
|
|
|
|
|
const ext = (mime.extension(file.mimetype) || path.extname(file.originalname).slice(1) || "png").toLowerCase();
|
|
|
|
|
const safeBase = path.parse(file.originalname).name.replace(/[^\w.-]/g, "_");
|
|
|
|
|
const filePath = `arminta_team_profiles/${safeBase}-${Date.now()}.${ext}`;
|
|
|
|
|
const bucketName = "arminta_profile_pictures";
|
|
|
|
|
|
|
|
|
|
// Upload
|
|
|
|
|
const buffer = await fs.promises.readFile(file.path);
|
|
|
|
|
const bucket = storage.bucket(bucketName);
|
|
|
|
|
const gcsFile = bucket.file(filePath);
|
|
|
|
|
await gcsFile.save(buffer, {
|
|
|
|
|
resumable: false,
|
|
|
|
|
public: true,
|
|
|
|
|
contentType: file.mimetype,
|
|
|
|
|
metadata: { cacheControl: "public, max-age=31536000" },
|
|
|
|
|
});
|
|
|
|
|
await gcsFile.makePublic();
|
|
|
|
|
// fastify.post("/api/uploads_installation_TeamMember_profile/:installationId/:teamMemberId", {
|
|
|
|
|
// preHandler: upload.single("file"),
|
|
|
|
|
// }, async (request, reply) => {
|
|
|
|
|
// try {
|
|
|
|
|
// const { installationId ,teamMemberId} = request.params;
|
|
|
|
|
// //const teamMemberId = request.body?.teamMemberId; // OPTIONAL
|
|
|
|
|
// const file = request.file;
|
|
|
|
|
|
|
|
|
|
const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`;
|
|
|
|
|
// if (!file) {
|
|
|
|
|
// return reply.code(400).send({ error: "No file uploaded (field name 'file')." });
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// Always upsert the installation-level picture doc
|
|
|
|
|
await ProfilePictureInstallTeamMember.findOneAndUpdate(
|
|
|
|
|
{ installationId, teamMemberId },
|
|
|
|
|
{ picture: publicUrl },
|
|
|
|
|
{ new: true, upsert: true }
|
|
|
|
|
);
|
|
|
|
|
// // Validate image type
|
|
|
|
|
// 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." });
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // Build GCS path
|
|
|
|
|
// const ext = (mime.extension(file.mimetype) || path.extname(file.originalname).slice(1) || "png").toLowerCase();
|
|
|
|
|
// const safeBase = path.parse(file.originalname).name.replace(/[^\w.-]/g, "_");
|
|
|
|
|
// const filePath = `arminta_team_profiles/${safeBase}-${Date.now()}.${ext}`;
|
|
|
|
|
// const bucketName = "arminta_profile_pictures";
|
|
|
|
|
|
|
|
|
|
// Update department picture where departmentId === installationId
|
|
|
|
|
const deptUpdate = await Deparments.findOneAndUpdate(
|
|
|
|
|
{ departmentId: installationId },
|
|
|
|
|
{ picture: publicUrl },
|
|
|
|
|
{ new: true }
|
|
|
|
|
);
|
|
|
|
|
// // Upload
|
|
|
|
|
// const buffer = await fs.promises.readFile(file.path);
|
|
|
|
|
// const bucket = storage.bucket(bucketName);
|
|
|
|
|
// const gcsFile = bucket.file(filePath);
|
|
|
|
|
// await gcsFile.save(buffer, {
|
|
|
|
|
// resumable: false,
|
|
|
|
|
// public: true,
|
|
|
|
|
// contentType: file.mimetype,
|
|
|
|
|
// metadata: { cacheControl: "public, max-age=31536000" },
|
|
|
|
|
// });
|
|
|
|
|
// await gcsFile.makePublic();
|
|
|
|
|
|
|
|
|
|
let teamMemberUpdated = false;
|
|
|
|
|
if (teamMemberId) {
|
|
|
|
|
// 1) Upsert team-member picture collection
|
|
|
|
|
await ProfilePictureInstallTeamMember.findOneAndUpdate(
|
|
|
|
|
{ teamMemberId },
|
|
|
|
|
{ picture: publicUrl },
|
|
|
|
|
{ new: true, upsert: true }
|
|
|
|
|
);
|
|
|
|
|
// const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`;
|
|
|
|
|
|
|
|
|
|
// 2) Update nested item inside Installations.team_member.team_member[]
|
|
|
|
|
// Using arrayFilters to match the correct team member element
|
|
|
|
|
const res = await Install.updateOne(
|
|
|
|
|
{ installationId },
|
|
|
|
|
{
|
|
|
|
|
$set: {
|
|
|
|
|
"team_member.team_member.$[tm].picture": publicUrl
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
arrayFilters: [{ "tm.teamMemberId": teamMemberId }]
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
teamMemberUpdated = res.modifiedCount > 0;
|
|
|
|
|
}
|
|
|
|
|
// // Always upsert the installation-level picture doc
|
|
|
|
|
// await ProfilePictureInstallTeamMember.findOneAndUpdate(
|
|
|
|
|
// { installationId, teamMemberId },
|
|
|
|
|
// { picture: publicUrl },
|
|
|
|
|
// { new: true, upsert: true }
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
return reply.send({
|
|
|
|
|
installationId,
|
|
|
|
|
teamMemberId: teamMemberId || null,
|
|
|
|
|
picture: publicUrl,
|
|
|
|
|
departmentUpdated: Boolean(deptUpdate),
|
|
|
|
|
teamMemberUpdated,
|
|
|
|
|
message: teamMemberId
|
|
|
|
|
? (teamMemberUpdated
|
|
|
|
|
? "Upload successful. Installation + team member picture updated."
|
|
|
|
|
: "Upload successful. Team member not found under this installation.")
|
|
|
|
|
: "Upload successful. Installation picture updated.",
|
|
|
|
|
});
|
|
|
|
|
} catch (err) {
|
|
|
|
|
request.log.error(err);
|
|
|
|
|
return reply.code(500).send({ error: "Upload failed", details: err.message });
|
|
|
|
|
} finally {
|
|
|
|
|
try { if (request.file?.path) await fs.promises.unlink(request.file.path); } catch {}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// // Update department picture where departmentId === installationId
|
|
|
|
|
// const deptUpdate = await Deparments.findOneAndUpdate(
|
|
|
|
|
// { departmentId: installationId },
|
|
|
|
|
// { picture: publicUrl },
|
|
|
|
|
// { new: true }
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
// let teamMemberUpdated = false;
|
|
|
|
|
// if (teamMemberId) {
|
|
|
|
|
// // 1) Upsert team-member picture collection
|
|
|
|
|
// await ProfilePictureInstallTeamMember.findOneAndUpdate(
|
|
|
|
|
// { teamMemberId },
|
|
|
|
|
// { picture: publicUrl },
|
|
|
|
|
// { new: true, upsert: true }
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
// // 2) Update nested item inside Installations.team_member.team_member[]
|
|
|
|
|
// // Using arrayFilters to match the correct team member element
|
|
|
|
|
// const res = await Install.updateOne(
|
|
|
|
|
// { installationId },
|
|
|
|
|
// {
|
|
|
|
|
// $set: {
|
|
|
|
|
// "team_member.team_member.$[tm].picture": publicUrl
|
|
|
|
|
// }
|
|
|
|
|
// },
|
|
|
|
|
// {
|
|
|
|
|
// arrayFilters: [{ "tm.teamMemberId": teamMemberId }]
|
|
|
|
|
// }
|
|
|
|
|
// );
|
|
|
|
|
// teamMemberUpdated = res.modifiedCount > 0;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// return reply.send({
|
|
|
|
|
// installationId,
|
|
|
|
|
// teamMemberId: teamMemberId || null,
|
|
|
|
|
// picture: publicUrl,
|
|
|
|
|
// departmentUpdated: Boolean(deptUpdate),
|
|
|
|
|
// teamMemberUpdated,
|
|
|
|
|
// message: teamMemberId
|
|
|
|
|
// ? (teamMemberUpdated
|
|
|
|
|
// ? "Upload successful. Installation + team member picture updated."
|
|
|
|
|
// : "Upload successful. Team member not found under this installation.")
|
|
|
|
|
// : "Upload successful. Installation picture updated.",
|
|
|
|
|
// });
|
|
|
|
|
// } catch (err) {
|
|
|
|
|
// request.log.error(err);
|
|
|
|
|
// return reply.code(500).send({ error: "Upload failed", details: err.message });
|
|
|
|
|
// } finally {
|
|
|
|
|
// try { if (request.file?.path) await fs.promises.unlink(request.file.path); } catch {}
|
|
|
|
|
// }
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
fastify.post('/api/uploads/:supplierId', async (request, reply) => {
|
|
|
|
|
try {
|
|
|
|
@ -1495,59 +1495,59 @@ fastify.post('/api/uploads-user/:customerId', async (request, reply) => {
|
|
|
|
|
// }
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
fastify.post(
|
|
|
|
|
"/api/uploads-electricty-work/:customerId/:installationId",
|
|
|
|
|
{ preHandler: upload.any() }, // allow multiple files
|
|
|
|
|
async (request, reply) => {
|
|
|
|
|
try {
|
|
|
|
|
const { customerId, installationId } = request.params;
|
|
|
|
|
const files = request.files;
|
|
|
|
|
// fastify.post(
|
|
|
|
|
// "/api/uploads-electricty-work/:customerId/:installationId",
|
|
|
|
|
// { preHandler: upload.any() }, // allow multiple files
|
|
|
|
|
// async (request, reply) => {
|
|
|
|
|
// try {
|
|
|
|
|
// const { customerId, installationId } = request.params;
|
|
|
|
|
// const files = request.files;
|
|
|
|
|
|
|
|
|
|
if (!files || files.length === 0) {
|
|
|
|
|
return reply.code(400).send({ error: "No files uploaded" });
|
|
|
|
|
}
|
|
|
|
|
// if (!files || files.length === 0) {
|
|
|
|
|
// return reply.code(400).send({ error: "No files uploaded" });
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
const bucketName = "arminta_profile_pictures";
|
|
|
|
|
const publicUrls = [];
|
|
|
|
|
// const bucketName = "arminta_profile_pictures";
|
|
|
|
|
// const publicUrls = [];
|
|
|
|
|
|
|
|
|
|
for (const file of files) {
|
|
|
|
|
const uniqueFileName = `${Date.now()}-${Math.random()
|
|
|
|
|
.toString(36)
|
|
|
|
|
.substring(7)}-${file.originalname}`;
|
|
|
|
|
const filePath = `electricty_work_picture/${uniqueFileName}`;
|
|
|
|
|
// for (const file of files) {
|
|
|
|
|
// const uniqueFileName = `${Date.now()}-${Math.random()
|
|
|
|
|
// .toString(36)
|
|
|
|
|
// .substring(7)}-${file.originalname}`;
|
|
|
|
|
// const filePath = `electricty_work_picture/${uniqueFileName}`;
|
|
|
|
|
|
|
|
|
|
// ✅ Handle buffer vs path depending on multer storage
|
|
|
|
|
const fileBuffer = file.buffer
|
|
|
|
|
? file.buffer // memoryStorage
|
|
|
|
|
: await fs.promises.readFile(file.path); // diskStorage
|
|
|
|
|
// // ✅ Handle buffer vs path depending on multer storage
|
|
|
|
|
// const fileBuffer = file.buffer
|
|
|
|
|
// ? file.buffer // memoryStorage
|
|
|
|
|
// : await fs.promises.readFile(file.path); // diskStorage
|
|
|
|
|
|
|
|
|
|
await storage.bucket(bucketName).file(filePath).save(fileBuffer);
|
|
|
|
|
// await storage.bucket(bucketName).file(filePath).save(fileBuffer);
|
|
|
|
|
|
|
|
|
|
await storage.bucket(bucketName).file(filePath).makePublic();
|
|
|
|
|
const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`;
|
|
|
|
|
publicUrls.push(publicUrl);
|
|
|
|
|
// await storage.bucket(bucketName).file(filePath).makePublic();
|
|
|
|
|
// const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`;
|
|
|
|
|
// publicUrls.push(publicUrl);
|
|
|
|
|
|
|
|
|
|
console.log(`✅ Uploaded: ${publicUrl}`);
|
|
|
|
|
}
|
|
|
|
|
// console.log(`✅ Uploaded: ${publicUrl}`);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// Update MongoDB
|
|
|
|
|
const updatedRecord = await ElectrictyWorkPictures.findOneAndUpdate(
|
|
|
|
|
{ customerId, installationId },
|
|
|
|
|
{ $push: { pictureUrl: { $each: publicUrls.map((url) => ({ url })) } } },
|
|
|
|
|
{ new: true, upsert: true }
|
|
|
|
|
);
|
|
|
|
|
// // Update MongoDB
|
|
|
|
|
// const updatedRecord = await ElectrictyWorkPictures.findOneAndUpdate(
|
|
|
|
|
// { customerId, installationId },
|
|
|
|
|
// { $push: { pictureUrl: { $each: publicUrls.map((url) => ({ url })) } } },
|
|
|
|
|
// { new: true, upsert: true }
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
return reply.send({
|
|
|
|
|
success: true,
|
|
|
|
|
pictures: publicUrls,
|
|
|
|
|
details: updatedRecord,
|
|
|
|
|
});
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error("❌ Upload Error:", err);
|
|
|
|
|
return reply.code(500).send({ error: "Upload failed", details: err.message });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
// return reply.send({
|
|
|
|
|
// success: true,
|
|
|
|
|
// pictures: publicUrls,
|
|
|
|
|
// details: updatedRecord,
|
|
|
|
|
// });
|
|
|
|
|
// } catch (err) {
|
|
|
|
|
// console.error("❌ Upload Error:", err);
|
|
|
|
|
// return reply.code(500).send({ error: "Upload failed", details: err.message });
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
// fastify.post("/api/uploads-manualTestVideo-work/:customerId/:installationId", async (request, reply) => {
|
|
|
|
|
// try {
|
|
|
|
@ -1681,142 +1681,142 @@ fastify.post(
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fastify.post(
|
|
|
|
|
"/api/uploads-manualTestVideo-work/:customerId/:installationId",
|
|
|
|
|
{ preHandler: upload.any() }, // Multer saves files to "uploads/"
|
|
|
|
|
async (request, reply) => {
|
|
|
|
|
try {
|
|
|
|
|
const { customerId, installationId } = request.params;
|
|
|
|
|
const files = request.files; // Multer saves file info here
|
|
|
|
|
// fastify.post(
|
|
|
|
|
// "/api/uploads-manualTestVideo-work/:customerId/:installationId",
|
|
|
|
|
// { preHandler: upload.any() }, // Multer saves files to "uploads/"
|
|
|
|
|
// async (request, reply) => {
|
|
|
|
|
// try {
|
|
|
|
|
// const { customerId, installationId } = request.params;
|
|
|
|
|
// const files = request.files; // Multer saves file info here
|
|
|
|
|
|
|
|
|
|
if (!files || files.length === 0) {
|
|
|
|
|
return reply.code(400).send({ error: "No files uploaded" });
|
|
|
|
|
}
|
|
|
|
|
// if (!files || files.length === 0) {
|
|
|
|
|
// return reply.code(400).send({ error: "No files uploaded" });
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
const bucketName = "arminta_profile_pictures";
|
|
|
|
|
const publicUrls = [];
|
|
|
|
|
// const bucketName = "arminta_profile_pictures";
|
|
|
|
|
// const publicUrls = [];
|
|
|
|
|
|
|
|
|
|
for (const file of files) {
|
|
|
|
|
const uniqueFileName = `${Date.now()}-${Math.random()
|
|
|
|
|
.toString(36)
|
|
|
|
|
.substring(7)}-${file.originalname}`;
|
|
|
|
|
const filePath = `manual_test_video/${uniqueFileName}`;
|
|
|
|
|
// for (const file of files) {
|
|
|
|
|
// const uniqueFileName = `${Date.now()}-${Math.random()
|
|
|
|
|
// .toString(36)
|
|
|
|
|
// .substring(7)}-${file.originalname}`;
|
|
|
|
|
// const filePath = `manual_test_video/${uniqueFileName}`;
|
|
|
|
|
|
|
|
|
|
console.log(`Uploading video: ${file.path} → ${filePath}`);
|
|
|
|
|
// console.log(`Uploading video: ${file.path} → ${filePath}`);
|
|
|
|
|
|
|
|
|
|
const gcsFile = storage.bucket(bucketName).file(filePath);
|
|
|
|
|
const stream = gcsFile.createWriteStream({
|
|
|
|
|
metadata: {
|
|
|
|
|
contentType: file.mimetype || "video/mp4",
|
|
|
|
|
contentDisposition: "inline",
|
|
|
|
|
},
|
|
|
|
|
resumable: false,
|
|
|
|
|
});
|
|
|
|
|
// const gcsFile = storage.bucket(bucketName).file(filePath);
|
|
|
|
|
// const stream = gcsFile.createWriteStream({
|
|
|
|
|
// metadata: {
|
|
|
|
|
// contentType: file.mimetype || "video/mp4",
|
|
|
|
|
// contentDisposition: "inline",
|
|
|
|
|
// },
|
|
|
|
|
// resumable: false,
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
// Pipe from disk to GCS
|
|
|
|
|
fs.createReadStream(file.path).pipe(stream);
|
|
|
|
|
// // Pipe from disk to GCS
|
|
|
|
|
// fs.createReadStream(file.path).pipe(stream);
|
|
|
|
|
|
|
|
|
|
await new Promise((resolve, reject) => {
|
|
|
|
|
stream.on("finish", async () => {
|
|
|
|
|
try {
|
|
|
|
|
await gcsFile.makePublic();
|
|
|
|
|
const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`;
|
|
|
|
|
publicUrls.push(publicUrl);
|
|
|
|
|
console.log(`✅ Uploaded: ${publicUrl}`);
|
|
|
|
|
resolve();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
reject(err);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
stream.on("error", (err) => {
|
|
|
|
|
console.error("Upload Error:", err);
|
|
|
|
|
reject(err);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
// await new Promise((resolve, reject) => {
|
|
|
|
|
// stream.on("finish", async () => {
|
|
|
|
|
// try {
|
|
|
|
|
// await gcsFile.makePublic();
|
|
|
|
|
// const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`;
|
|
|
|
|
// publicUrls.push(publicUrl);
|
|
|
|
|
// console.log(`✅ Uploaded: ${publicUrl}`);
|
|
|
|
|
// resolve();
|
|
|
|
|
// } catch (err) {
|
|
|
|
|
// reject(err);
|
|
|
|
|
// }
|
|
|
|
|
// });
|
|
|
|
|
// stream.on("error", (err) => {
|
|
|
|
|
// console.error("Upload Error:", err);
|
|
|
|
|
// reject(err);
|
|
|
|
|
// });
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
// optional: cleanup temp file
|
|
|
|
|
fs.unlink(file.path, (err) => {
|
|
|
|
|
if (err) console.error("Temp file cleanup failed:", err);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
// // optional: cleanup temp file
|
|
|
|
|
// fs.unlink(file.path, (err) => {
|
|
|
|
|
// if (err) console.error("Temp file cleanup failed:", err);
|
|
|
|
|
// });
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// Update MongoDB
|
|
|
|
|
const updatedRecord = await ManualTestVideo.findOneAndUpdate(
|
|
|
|
|
{ customerId, installationId },
|
|
|
|
|
{ $push: { pictureUrl: { $each: publicUrls.map((url) => ({ url })) } } },
|
|
|
|
|
{ new: true, upsert: true }
|
|
|
|
|
);
|
|
|
|
|
// // Update MongoDB
|
|
|
|
|
// const updatedRecord = await ManualTestVideo.findOneAndUpdate(
|
|
|
|
|
// { customerId, installationId },
|
|
|
|
|
// { $push: { pictureUrl: { $each: publicUrls.map((url) => ({ url })) } } },
|
|
|
|
|
// { new: true, upsert: true }
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
return reply.send({
|
|
|
|
|
success: true,
|
|
|
|
|
videos: publicUrls,
|
|
|
|
|
details: updatedRecord,
|
|
|
|
|
});
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error("Upload Error:", err);
|
|
|
|
|
return reply
|
|
|
|
|
.code(500)
|
|
|
|
|
.send({ error: "Upload failed", details: err.message });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
// return reply.send({
|
|
|
|
|
// success: true,
|
|
|
|
|
// videos: publicUrls,
|
|
|
|
|
// details: updatedRecord,
|
|
|
|
|
// });
|
|
|
|
|
// } catch (err) {
|
|
|
|
|
// console.error("Upload Error:", err);
|
|
|
|
|
// return reply
|
|
|
|
|
// .code(500)
|
|
|
|
|
// .send({ error: "Upload failed", details: err.message });
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
fastify.post("/api/uploads-plumbing-work/:customerId/:installationId", async (request, reply) => {
|
|
|
|
|
try {
|
|
|
|
|
const { customerId, installationId } = request.params;
|
|
|
|
|
const files = await request.files(); // Await files properly
|
|
|
|
|
// fastify.post("/api/uploads-plumbing-work/:customerId/:installationId", async (request, reply) => {
|
|
|
|
|
// try {
|
|
|
|
|
// const { customerId, installationId } = request.params;
|
|
|
|
|
// const files = await request.files(); // Await files properly
|
|
|
|
|
|
|
|
|
|
if (!files || files.length === 0) {
|
|
|
|
|
return reply.code(400).send({ error: "No files uploaded" });
|
|
|
|
|
}
|
|
|
|
|
// if (!files || files.length === 0) {
|
|
|
|
|
// return reply.code(400).send({ error: "No files uploaded" });
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
const bucketName = "arminta_profile_pictures";
|
|
|
|
|
const publicUrls = [];
|
|
|
|
|
// const bucketName = "arminta_profile_pictures";
|
|
|
|
|
// const publicUrls = [];
|
|
|
|
|
|
|
|
|
|
for await (const file of files) {
|
|
|
|
|
const uniqueFileName = `${Date.now()}-${Math.random().toString(36).substring(7)}-${file.filename}`;
|
|
|
|
|
const filePath = `plumbing_work_picture/${uniqueFileName}`;
|
|
|
|
|
// for await (const file of files) {
|
|
|
|
|
// const uniqueFileName = `${Date.now()}-${Math.random().toString(36).substring(7)}-${file.filename}`;
|
|
|
|
|
// const filePath = `plumbing_work_picture/${uniqueFileName}`;
|
|
|
|
|
|
|
|
|
|
console.log(`Uploading file: ${file.filename} → ${filePath}`);
|
|
|
|
|
// console.log(`Uploading file: ${file.filename} → ${filePath}`);
|
|
|
|
|
|
|
|
|
|
const writeStream = storage.bucket(bucketName).file(filePath).createWriteStream();
|
|
|
|
|
// const writeStream = storage.bucket(bucketName).file(filePath).createWriteStream();
|
|
|
|
|
|
|
|
|
|
file.file.pipe(writeStream);
|
|
|
|
|
// file.file.pipe(writeStream);
|
|
|
|
|
|
|
|
|
|
await new Promise((resolve, reject) => {
|
|
|
|
|
writeStream.on("finish", async () => {
|
|
|
|
|
try {
|
|
|
|
|
await storage.bucket(bucketName).file(filePath).makePublic();
|
|
|
|
|
const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`;
|
|
|
|
|
publicUrls.push(publicUrl);
|
|
|
|
|
console.log(`File uploaded: ${publicUrl}`);
|
|
|
|
|
resolve();
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Failed to make file public:", error);
|
|
|
|
|
reject(error);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
// await new Promise((resolve, reject) => {
|
|
|
|
|
// writeStream.on("finish", async () => {
|
|
|
|
|
// try {
|
|
|
|
|
// await storage.bucket(bucketName).file(filePath).makePublic();
|
|
|
|
|
// const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`;
|
|
|
|
|
// publicUrls.push(publicUrl);
|
|
|
|
|
// console.log(`File uploaded: ${publicUrl}`);
|
|
|
|
|
// resolve();
|
|
|
|
|
// } catch (error) {
|
|
|
|
|
// console.error("Failed to make file public:", error);
|
|
|
|
|
// reject(error);
|
|
|
|
|
// }
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
writeStream.on("error", (err) => {
|
|
|
|
|
console.error("Failed to upload file:", err);
|
|
|
|
|
reject(err);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
// writeStream.on("error", (err) => {
|
|
|
|
|
// console.error("Failed to upload file:", err);
|
|
|
|
|
// reject(err);
|
|
|
|
|
// });
|
|
|
|
|
// });
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// Update MongoDB: Convert URLs to { url: "..." } objects
|
|
|
|
|
const updatedRecord = await PlumbingWorkPictures.findOneAndUpdate(
|
|
|
|
|
{ customerId, installationId },
|
|
|
|
|
{ $push: { pictureUrl: { $each: publicUrls.map(url => ({ url })) } } }, // Append new images
|
|
|
|
|
{ new: true, upsert: true }
|
|
|
|
|
);
|
|
|
|
|
// // Update MongoDB: Convert URLs to { url: "..." } objects
|
|
|
|
|
// const updatedRecord = await PlumbingWorkPictures.findOneAndUpdate(
|
|
|
|
|
// { customerId, installationId },
|
|
|
|
|
// { $push: { pictureUrl: { $each: publicUrls.map(url => ({ url })) } } }, // Append new images
|
|
|
|
|
// { new: true, upsert: true }
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
reply.send({ success: true, pictures: publicUrls, details: updatedRecord });
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error("Upload Error:", err);
|
|
|
|
|
reply.code(500).send({ error: "An error occurred", details: err.message });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
// reply.send({ success: true, pictures: publicUrls, details: updatedRecord });
|
|
|
|
|
// } catch (err) {
|
|
|
|
|
// console.error("Upload Error:", err);
|
|
|
|
|
// reply.code(500).send({ error: "An error occurred", details: err.message });
|
|
|
|
|
// }
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
// fastify.post("/api/uploads-material-recieved/:customerId/:installationId", async (request, reply) => {
|
|
|
|
|
// try {
|
|
|
|
@ -1988,61 +1988,61 @@ fastify.post("/api/uploads-plumbing-work/:customerId/:installationId", async (re
|
|
|
|
|
// },
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
fastify.post(
|
|
|
|
|
"/api/uploads-material-recieved/:customerId/:installationId",
|
|
|
|
|
{ preHandler: upload.any() }, // use 'files' field for multiple uploads
|
|
|
|
|
async (request, reply) => {
|
|
|
|
|
try {
|
|
|
|
|
const { customerId, installationId } = request.params;
|
|
|
|
|
const files = request.files; // multer-style files array
|
|
|
|
|
// fastify.post(
|
|
|
|
|
// "/api/uploads-material-recieved/:customerId/:installationId",
|
|
|
|
|
// { preHandler: upload.any() }, // use 'files' field for multiple uploads
|
|
|
|
|
// async (request, reply) => {
|
|
|
|
|
// try {
|
|
|
|
|
// const { customerId, installationId } = request.params;
|
|
|
|
|
// const files = request.files; // multer-style files array
|
|
|
|
|
|
|
|
|
|
if (!files || files.length === 0) {
|
|
|
|
|
return reply.code(400).send({ error: "No files uploaded" });
|
|
|
|
|
}
|
|
|
|
|
// if (!files || files.length === 0) {
|
|
|
|
|
// return reply.code(400).send({ error: "No files uploaded" });
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
const bucketName = "arminta_profile_pictures";
|
|
|
|
|
const publicUrls = [];
|
|
|
|
|
// const bucketName = "arminta_profile_pictures";
|
|
|
|
|
// const publicUrls = [];
|
|
|
|
|
|
|
|
|
|
for (const file of files) {
|
|
|
|
|
// Generate unique file name
|
|
|
|
|
const uniqueFileName = `${Date.now()}-${Math.random()
|
|
|
|
|
.toString(36)
|
|
|
|
|
.substring(7)}-${file.originalname}`;
|
|
|
|
|
const filePath = `plumbing_work_picture/${uniqueFileName}`;
|
|
|
|
|
// for (const file of files) {
|
|
|
|
|
// // Generate unique file name
|
|
|
|
|
// const uniqueFileName = `${Date.now()}-${Math.random()
|
|
|
|
|
// .toString(36)
|
|
|
|
|
// .substring(7)}-${file.originalname}`;
|
|
|
|
|
// const filePath = `plumbing_work_picture/${uniqueFileName}`;
|
|
|
|
|
|
|
|
|
|
// Read file buffer
|
|
|
|
|
const fileBuffer = await fs.promises.readFile(file.path);
|
|
|
|
|
// // Read file buffer
|
|
|
|
|
// const fileBuffer = await fs.promises.readFile(file.path);
|
|
|
|
|
|
|
|
|
|
// Upload to GCS
|
|
|
|
|
await storage.bucket(bucketName).file(filePath).save(fileBuffer);
|
|
|
|
|
// // Upload to GCS
|
|
|
|
|
// await storage.bucket(bucketName).file(filePath).save(fileBuffer);
|
|
|
|
|
|
|
|
|
|
// Make file public
|
|
|
|
|
await storage.bucket(bucketName).file(filePath).makePublic();
|
|
|
|
|
// // Make file public
|
|
|
|
|
// await storage.bucket(bucketName).file(filePath).makePublic();
|
|
|
|
|
|
|
|
|
|
const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`;
|
|
|
|
|
publicUrls.push(publicUrl);
|
|
|
|
|
}
|
|
|
|
|
// const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`;
|
|
|
|
|
// publicUrls.push(publicUrl);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// Save/Update in DB
|
|
|
|
|
const updatedRecord = await MaterialRecievedPictures.findOneAndUpdate(
|
|
|
|
|
{ customerId, installationId },
|
|
|
|
|
{ $push: { pictureUrl: { $each: publicUrls.map((url) => ({ url })) } } }, // Append images
|
|
|
|
|
{ new: true, upsert: true }
|
|
|
|
|
);
|
|
|
|
|
// // Save/Update in DB
|
|
|
|
|
// const updatedRecord = await MaterialRecievedPictures.findOneAndUpdate(
|
|
|
|
|
// { customerId, installationId },
|
|
|
|
|
// { $push: { pictureUrl: { $each: publicUrls.map((url) => ({ url })) } } }, // Append images
|
|
|
|
|
// { new: true, upsert: true }
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
return reply.send({
|
|
|
|
|
success: true,
|
|
|
|
|
pictures: publicUrls,
|
|
|
|
|
details: updatedRecord,
|
|
|
|
|
});
|
|
|
|
|
} catch (err) {
|
|
|
|
|
request.log.error(err);
|
|
|
|
|
return reply
|
|
|
|
|
.code(500)
|
|
|
|
|
.send({ error: "Upload failed", details: err.message });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
// return reply.send({
|
|
|
|
|
// success: true,
|
|
|
|
|
// pictures: publicUrls,
|
|
|
|
|
// details: updatedRecord,
|
|
|
|
|
// });
|
|
|
|
|
// } catch (err) {
|
|
|
|
|
// request.log.error(err);
|
|
|
|
|
// return reply
|
|
|
|
|
// .code(500)
|
|
|
|
|
// .send({ error: "Upload failed", details: err.message });
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// );
|
|
|
|
|
fastify.post("/api/installLogin", {
|
|
|
|
|
schema: {
|
|
|
|
|
description: "Login as Installation Manager",
|
|
|
|
|