From 097bd9eb4612c94d5e12973246df1ce716bf293c Mon Sep 17 00:00:00 2001 From: Bhaskar Date: Thu, 10 Jul 2025 13:02:01 +0530 Subject: [PATCH] pictures are saved work status and reaming video --- src/controllers/installationController.js | 45 ++++++++++++++++ src/index.js | 58 +++++++++++++++++++- src/models/store.js | 45 +++++++++++++++- src/routes/installationRoute.js | 64 +++++++++++++++++++++++ 4 files changed, 209 insertions(+), 3 deletions(-) diff --git a/src/controllers/installationController.js b/src/controllers/installationController.js index e7bea7b2..33f8e266 100644 --- a/src/controllers/installationController.js +++ b/src/controllers/installationController.js @@ -1688,6 +1688,51 @@ return { }; +exports.addMediaToInsensor = async (req, reply) => { + try { + const { hardwareId, customerId, type } = req.params; + const { urls, mediaType } = req.body; + + if (!hardwareId || !customerId || !type || !urls || !mediaType) { + return reply.status(400).send({ success: false, message: "Missing required fields" }); + } + + const insensor = await Insensors.findOne({ hardwareId, customerId, type }); + if (!insensor) { + return reply.status(404).send({ success: false, message: "Insensor not found" }); + } + + const mediaItems = urls.map(url => ({ url, createdAt: new Date() })); + + if (mediaType === 'video') { + insensor.manualTestVideos.push(...mediaItems); + } else if (mediaType === 'material') { + insensor.materialReceivedPictures.push(...mediaItems); + } else if (mediaType === 'workStatus') { + insensor.workStatusPictures.push(...mediaItems); + } else { + return reply.status(400).send({ success: false, message: "Invalid mediaType" }); + } + + await insensor.save(); + + // ✅ fetch the updated document as plain object + const updatedInsensor = await Insensors.findOne({ hardwareId, customerId, type }).lean(); + console.log("updatedInsensor",updatedInsensor) + return reply.send({ + success: true, + message: "Media saved successfully", + data: updatedInsensor + }); + } catch (error) { + console.error("Error adding media to insensor:", error); + return reply.status(500).send({ success: false, message: "Internal server error" }); + } +}; + + + + exports.mastrerList = async (req, reply) => { try { diff --git a/src/index.js b/src/index.js index c4d591a4..326376a5 100644 --- a/src/index.js +++ b/src/index.js @@ -7,7 +7,7 @@ const createConnectionController = require("./controllers/createConnectionContro const storeController = require("./controllers/storeController.js") const boom = require("boom"); const bcrypt = require('bcrypt'); -const { ProfilePictureStore,generateinstallationId,Store, Survey, PlumbingWorkPictures, ElectrictyWorkPictures, MaterialRecievedPictures, Support} = require("./models/store"); +const { ProfilePictureStore,generateinstallationId,Store, Survey, PlumbingWorkPictures, ElectrictyWorkPictures, MaterialRecievedPictures, Support, ManualTestVideo} = require("./models/store"); const cors = require('fastify-cors'); @@ -966,6 +966,62 @@ fastify.post("/api/uploads-electricty-work/:customerId/:installationId", async ( } }); +fastify.post("/api/uploads-manualTestVideo-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" }); + } + + 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 = `electricty_work_picture/${uniqueFileName}`; + + console.log(`Uploading file: ${file.filename} → ${filePath}`); + + const writeStream = storage.bucket(bucketName).file(filePath).createWriteStream(); + + 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); + } + }); + + writeStream.on("error", (err) => { + console.error("Failed to upload file:", err); + reject(err); + }); + }); + } + + // Update MongoDB: Convert URLs to { url: "..." } objects + const updatedRecord = await ManualTestVideo.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 }); + } +}); fastify.post("/api/uploads-plumbing-work/:customerId/:installationId", async (request, reply) => { try { diff --git a/src/models/store.js b/src/models/store.js index 9f9c1288..5c11fc8a 100644 --- a/src/models/store.js +++ b/src/models/store.js @@ -676,7 +676,25 @@ distance_check: { { step: Number, result: String } ] } - }] + }], + manualTestVideos: [ + { + url: String, + createdAt: { type: Date, default: Date.now } + } +], +materialReceivedPictures: [ + { + url: String, + createdAt: { type: Date, default: Date.now } + } +], +workStatusPictures: [ + { + url: String, + createdAt: { type: Date, default: Date.now } + } +] }); @@ -1067,6 +1085,27 @@ const plumbingWorkPicturesSchema = new Schema({ } }); +const manualTestVideoSchema = new Schema({ + installationId: { + type: String, + //required: true, + //unique: true + }, + customerId: { + type: String, + //required: true + }, + pictureUrl: [{ + url: { + type: String, + }, + }], + createdAt: { + type: Date, + default: Date.now + } +}); + const materialRecievedPicturesSchema = new Schema({ installationId: { type: String, @@ -1120,6 +1159,8 @@ const Iotprice = mongoose.model('Iotprice', iotpriceSchema); const Insensors = mongoose.model('Insensors', insensorsSchema); const MasterSlaveData = mongoose.model('MasterSlaveData', masterSlaveDataSchema); const ElectrictyWorkPictures = mongoose.model('ElectrictyWorkPictures', electrictyWorkPicturesSchema); + const ManualTestVideo = mongoose.model('ManualTestVideo', manualTestVideoSchema); + const PlumbingWorkPictures = mongoose.model('PlumbingWorkPictures', plumbingWorkPicturesSchema); const MaterialRecievedPictures = mongoose.model('MaterialRecievedPictures', materialRecievedPicturesSchema); @@ -1145,4 +1186,4 @@ const Iotprice = mongoose.model('Iotprice', iotpriceSchema); - module.exports = {Repairorder,Support,MaterialRecievedPictures,PlumbingWorkPictures,ElectrictyWorkPictures,MasterSlaveData,SensorStock,Order,EstimationOrder,Iotprice,Sales, Install,Survey, ProfilePictureInstall, SensorQuotation,generateinstallationId,Store,ProfilePictureStore,WaterLeverSensor,MotorSwitchSensor,Insensors,generatequatationId, HardwareCart, ServiceCart}; + module.exports = {ManualTestVideo,Repairorder,Support,MaterialRecievedPictures,PlumbingWorkPictures,ElectrictyWorkPictures,MasterSlaveData,SensorStock,Order,EstimationOrder,Iotprice,Sales, Install,Survey, ProfilePictureInstall, SensorQuotation,generateinstallationId,Store,ProfilePictureStore,WaterLeverSensor,MotorSwitchSensor,Insensors,generatequatationId, HardwareCart, ServiceCart}; diff --git a/src/routes/installationRoute.js b/src/routes/installationRoute.js index 23da29f6..4ba97fc3 100644 --- a/src/routes/installationRoute.js +++ b/src/routes/installationRoute.js @@ -421,6 +421,70 @@ module.exports = function (fastify, opts, next) { }, handler: installationController.masterConnectedSlaveList, }); +fastify.post( + '/api/insensors/:hardwareId/:customerId/:type/media', + { + schema: { + summary: 'Add media (manual videos, material pictures, or work status pictures) to master or slave device', + description: 'Attach media files (video or images) to a specific Insensor (master or slave) for a given customer', + tags: ['Installation'], + params: { + type: 'object', + required: ['hardwareId', 'customerId', 'type'], + properties: { + hardwareId: { type: 'string', description: 'Hardware ID of the device' }, + customerId: { type: 'string', description: 'Customer ID' }, + type: { type: 'string', enum: ['master', 'slave'], description: 'Device type' } + } + }, + body: { + type: 'object', + required: ['urls', 'mediaType'], + properties: { + urls: { + type: 'array', + items: { type: 'string', format: 'uri', description: 'URL of media file' }, + minItems: 1, + description: 'Array of media URLs to save' + }, + mediaType: { + type: 'string', + enum: ['video', 'material', 'workStatus'], + description: 'Target field to store media in: "video" → manualTestVideos, "material" → materialReceivedPictures, "workStatus" → workStatusPictures' + } + } + }, + // response: { + // 200: { + // type: 'object', + // properties: { + // success: { type: 'boolean' }, + // message: { type: 'string' }, + // data: { + // type: 'object', + // description: 'Updated Insensor document' + // } + // } + // }, + // 400: { + // type: 'object', + // properties: { success: { type: 'boolean' }, message: { type: 'string' } } + // }, + // 404: { + // type: 'object', + // properties: { success: { type: 'boolean' }, message: { type: 'string' } } + // }, + // 500: { + // type: 'object', + // properties: { success: { type: 'boolean' }, message: { type: 'string' } } + // } + // } + }, + handler: installationController.addMediaToInsensor + + } +); + fastify.get("/api/getmasterList/:customerId/:installationId", { schema: {