Aditya-feat: Add Network Failure Handling & Upload Status Feedback on Update Tool/Equipment Status Page#2103
Open
Aditya-gam wants to merge 5 commits intodevelopmentfrom
Hidden character warning
The head ref may contain hidden characters: "Aditya-feat/Add-Network\u2013Failure-Handling-Upload-Status-Feedback-on-Update-Tool-Equipment-Status-Page"
Conversation
Optional image can be sent with status updates via multipart/form-data. Multer middleware validates type (PNG/JPEG) and size (5MB). Image is uploaded to Azure Blob Storage; URL stored on equipment and in update record. Schema adds imageUrl to equipment and updateRecord. Controller uses logException for errors. Made-with: Cursor
Made-with: Cursor
Return 503 when Azure Blob env vars are missing so clients can distinguish config vs runtime failure. Extract buildUpdateRecord helper and add JSDoc for PUT /equipment/:equipmentId/status. Made-with: Cursor
Add tests for updateEquipmentById, updateLogRecords, and updateEquipmentStatus (validation, image upload, 503/500/404). Add tests for bmEquipmentStatusUpload middleware (fileFilter, limits, multipart passthrough). Made-with: Cursor
Add NOSONAR comments so SonarCloud accepts the 5 MB multer limit as reviewed. Limit is intentional and within guidance for file uploads. Made-with: Cursor
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Description
Adds backend support for image upload and storage on the BM Dashboard Update Tool/Equipment Status page (

tools/:equipmentId/update). The existing status-update API now accepts an optional image (multipart/form-data), validates format and size, uploads to Azure Blob Storage, and persists the image URL on the equipment document and in the new status update record. Error responses are aligned with the frontend contract so users get clear feedback (e.g., "Image selected but not saved", "Invalid image. Use PNG, JPG, or JPEG under 5MB.") and no silent failures.Related PRs (if any):
Main changes explained:
Created/Updated Files:
src/models/bmdashboard/buildingEquipment.js(+2 lines)imageUrl: Stringto theupdateRecordsubdocument so each status update can store an image URL.imageUrl: Stringat the root of the schema so the equipment has a single “current” display image (set when an image is uploaded with a status update).src/middleware/bmEquipmentStatusUpload.js(new, 44 lines)Content-Typeismultipart/form-data; JSON requests pass through withreq.fileundefined.upload.single('image')with 5 MB limit and fileFilter allowing onlyimage/pngandimage/jpeg.{ error: 'Invalid image. Use PNG, JPG, or JPEG under 5MB.' }.MAX_IMAGE_SIZE_BYTES,ALLOWED_IMAGE_MIME_TYPES,INVALID_IMAGE_ERROR,IMAGE_NOT_SAVED_ERRORfor use in controller and tests.src/routes/bmdashboard/bmEquipmentRouter.js(+5 lines)bmEquipmentStatusUploadand attaches it to the status route before the controller.PUT /equipment/:equipmentId/statusnow runs:bmEquipmentStatusUpload→controller.updateEquipmentStatus.src/controllers/bmdashboard/bmEquipmentController.js(+133 / refactor)validateAndUploadImage(file, equipmentId)— validates MIME (reuses middleware constants), checks Azure env vars (returns 503 with "Image storage is not configured on this server." if missing), builds blob pathequipment/{equipmentId}/status/{timestamp}_{safeName}.{ext}, callsuploadFileToAzureBlobStorage, returns{ imageUrl }or{ error, status }.buildUpdateRecord(fields, imageUrl)— builds the updateRecord object (date, createdBy, condition, lastUsedBy, lastUsedFor, replacementRequired, description, notes; adds imageUrl only when provided).updateEquipmentStatus:{ error: 'Invalid equipment ID.' }if invalid (previously could fall through).req.fileis present: callsvalidateAndUploadImage; on error returns 400 / 503 / 500 with the contract message (errorfield).imageUrl; if image uploaded, also$set: { imageUrl }on the root document.findByIdAndUpdatewith$push(and optional$set), then populate; returns 200 with updated equipment or 404 if not found.{ error: 'Image selected but not saved.' }and uselogExceptionfor logging.updateLogRecords: useslogExceptionon DB error (consistent error reporting).uploadFileToAzureBlobStorage,logException, and middleware constants.src/controllers/bmdashboard/__tests__/bmEquipmentController.test.js(major expansion, ~+478 lines)AzureBlobImages.uploadFileToAzureBlobStorageandlogger.logException.src/middleware/bmEquipmentStatusUpload.test.js(new, 176 lines)next()called, no multer.upload.single('image')is used.Key Implementation Details:
PUT /api/bm/equipment/:equipmentId/statusaccepts JSON (no image) or multipart/form-data with fieldimage(one file). Middleware runs multer only for multipart so existing JSON clients are unchanged.equipment/{equipmentId}/status/{timestamp}_{sanitizedOriginalName}.{ext}(same Azure container as rest of app; env:AZURE_STORAGE_CONNECTION_STRING,AZURE_STORAGE_CONTAINER_NAME).imageUrl; when an image is uploaded, root-levelimageUrlis also set soequipmentDetails.imageUrlshows the latest photo.errorin the response body. Messages:Invalid image. Use PNG, JPG, or JPEG under 5MB.(400),Image selected but not saved.(500),Image storage is not configured on this server.(503).errormessage.How to test:
git checkout Aditya-feat/Add-Network–Failure-Handling-Upload-Status-Feedback-on-Update-Tool-Equipment-Status-Pagerm -rf node_modules package-lock.json && npm cache clean --forcenpm installto install dependencies, then start the backend locally (npm run dev)PUT http://localhost:4500/api/bm/equipment/:equipmentId/statusContent-Type: application/json{ "condition": "Good", "createdBy": "<valid-user-object-id>", "lastUsedBy": "", "lastUsedFor": "", "replacementRequired": "", "description": "", "notes": "" }imageUrlin latest updateRecord.multipart/form-datacondition,createdBy,lastUsedBy,lastUsedFor,replacementRequired,description,notesimage— one PNG or JPEG file (< 5 MB).updateRecordentry withimageUrl, and rootimageUrlset.{ error: 'Invalid image. Use PNG, JPG, or JPEG under 5MB.' }.equipmentId(e.g. non-ObjectId) → 400{ error: 'Invalid equipment ID.' }.conditionorcreatedBy→ 400{ error: 'Condition and createdBy are required fields.' }.{ error: 'Image storage is not configured on this server.' }.npm test(ornpm test -- src/controllers/bmdashboard/__tests__/bmEquipmentController.test.js src/middleware/bmEquipmentStatusUpload.test.js)./api/bm/equipment/:equipmentIdreturns equipment withimageUrlandupdateRecord[].imageUrlwhen set.Screenshots or videos of changes:
TestVideo.mov
Note