diff --git a/README.md b/README.md index b44acc0..2e8add8 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ Read registered resources: - `GET /meta-data`: List registered meta-data. - `GET /meta-groups`: List registered meta-data. - `GET /product-categories`: List registered product-categories. + - `GET /public-load-attachments/download/:id`: Downloads the attachment of the load identified by Id. - `GET /public-vehicles`: List registered product-categories. - `GET /states`: List registered states. @@ -40,6 +41,10 @@ All these endpoints support the following parameters (except for those with `pub The following list of endpoints requires a JWT. + - `GET /loads`: List loads related to my company. + - `GET /load-attachments`: List load attachments related to my company or load id. + + ## Test Endpoint A private endpoint to test the JWT and the api response. diff --git a/config/apiConfig.json b/config/apiConfig.json index c8a2733..88842a3 100644 --- a/config/apiConfig.json +++ b/config/apiConfig.json @@ -22,6 +22,7 @@ "accessKeyId": "AKIAXTQEUF6MLCHTUIKW", "secretAccessKey": "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", "bucket": "enruta", + "key":"loadattachments", "region": "us-west-1" }, "sendgrid" : { diff --git a/package.json b/package.json index b3437ff..f26f8c7 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,8 @@ }, "homepage": "https://gitlab.com/jcruzbaasworkspace/enruta/etaapi#readme", "dependencies": { + "@aws-sdk/client-s3": "^3.427.0", "audit": "^0.0.6", - "aws-sdk": "^2.1470.0", "axios": "^1.5.1", "body-parser": "^1.20.2", "compression": "^1.7.4", diff --git a/sections/load-attachments/services.js b/sections/load-attachments/services.js index 5655f10..002d082 100644 --- a/sections/load-attachments/services.js +++ b/sections/load-attachments/services.js @@ -1,6 +1,19 @@ "use strict"; -const { ROOT_PATH, LIB_PATH, MODELS_PATH, HANDLERS_PATH } = process.env; +const { ROOT_PATH, LIB_PATH, MODELS_PATH, API_CONFIG } = process.env; const { getPagination , getPage } = require( `${ROOT_PATH}/${LIB_PATH}/Misc.js` ); +const apiConfig = require( `${ROOT_PATH}/${API_CONFIG}` ); + +const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3'); +const s3Client = new S3Client({ + region : apiConfig.S3.region, + credentials : { + accessKeyId : apiConfig.S3.accessKeyId, + secretAccessKey : apiConfig.S3.secretAccessKey + } +}); +const s3Bucket = apiConfig.S3.bucket; +const s3BucketKey = apiConfig.S3.key; + const Model = require( `${ROOT_PATH}/${MODELS_PATH}/load-attachments.model.js` ); const UserModel = require( `${ROOT_PATH}/${MODELS_PATH}/users.model.js` ); const LoadsModel = require( `${ROOT_PATH}/${MODELS_PATH}/loads.model.js` ); @@ -17,7 +30,7 @@ async function getAuthorizationFilter( userId ){ } const getAttachment = async(req, res) => { - const attachmentId = req.query.id; + const attachmentId = req.params.id; const CompanyAccessFilter = await getAuthorizationFilter( req.JWT.payload.sub ); const filter = { $and : [ @@ -37,8 +50,9 @@ const getAttachmentList = async(req, res) => { }; const getLoadAttachmentList = async(req, res) => { - const loadId = req.query.id; + const loadId = req.params.id; const CompanyAccessFilter = await getAuthorizationFilter( req.JWT.payload.sub ); + console.log( loadId ); const filter = { $and : [ { load : loadId }, @@ -62,7 +76,7 @@ async function getLoadById( loadId , companyId ){ } ] }; - return await Model.findOne( filter ) || null; + return await LoadsModel.findOne( filter ) || null; } async function createLoadAttachment( type , userId , loadId ){ @@ -83,7 +97,7 @@ async function createLoadAttachment( type , userId , loadId ){ await attachment.save(); } else if( load && prevAttachment ){ - prevAttachment.updatedAt = new Date.now(); + prevAttachment.updatedAt = Date.now(); await prevAttachment.save(); attachment = prevAttachment; }else{ @@ -95,10 +109,22 @@ async function createLoadAttachment( type , userId , loadId ){ return attachment; } +async function uploadFile( bucket, key, file , obj_id ){ + const params = { + Bucket: bucket, + Key : `${key}/${obj_id}`, + ContentType : file.mimetype, + Body : file.data + }; + const s3resp = await s3Client.send( new PutObjectCommand( params ) ); + return s3resp; +} const postLoadingAttachment = async(req, res) => { const loadId = req.params.id; const attachment = await createLoadAttachment( "Loading", req.JWT.payload.sub , loadId ); - if( attachment ){ + const file = req.files.attachment; + if( attachment && file ){ + const s3resp = await uploadFile( s3Bucket, s3BucketKey, file , attachment._id ); res.send( attachment ); }else{ res.status(401).send({error:"Unauthorized",code:401}); @@ -108,7 +134,9 @@ const postLoadingAttachment = async(req, res) => { const postDownloadingAttachment = async(req, res) => { const loadId = req.params.id; const attachment = await createLoadAttachment( "Downloading", req.JWT.payload.sub , loadId ); + const file = req.files.attachment; if( attachment ){ + const s3resp = await uploadFile( s3Bucket, s3BucketKey, file , attachment._id ); res.send( attachment ); }else{ res.status(401).send({error:"Unauthorized",code:401}); diff --git a/sections/public-load-attachments/routes.js b/sections/public-load-attachments/routes.js new file mode 100644 index 0000000..b9589e6 --- /dev/null +++ b/sections/public-load-attachments/routes.js @@ -0,0 +1,7 @@ +'use strict'; +const router = require('express').Router(); +const services= require('./services.js'); + +router.get('/download/:id', services.getAttachmentFile ); + +module.exports = router; diff --git a/sections/public-load-attachments/services.js b/sections/public-load-attachments/services.js new file mode 100644 index 0000000..4e1b914 --- /dev/null +++ b/sections/public-load-attachments/services.js @@ -0,0 +1,38 @@ +"use strict"; +const { ROOT_PATH, LIB_PATH, MODELS_PATH, API_CONFIG } = process.env; +const apiConfig = require( `${ROOT_PATH}/${API_CONFIG}` ); + +const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3'); +const s3Client = new S3Client({ + region : apiConfig.S3.region, + credentials : { + accessKeyId : apiConfig.S3.accessKeyId, + secretAccessKey : apiConfig.S3.secretAccessKey + } +}); +const s3Bucket = apiConfig.S3.bucket; +const s3BucketKey = apiConfig.S3.key; + +async function downloadFile( bucket, key, obj_id ){ + const params = { + Bucket: bucket, + Key : `${key}/${obj_id}` + }; + const s3resp = await s3Client.send( new GetObjectCommand( params ) ); + const chunks = [] + for await (const chunk of s3resp.Body) { + chunks.push(chunk) + } + const body = Buffer.concat(chunks); + s3resp.Body = body; + return s3resp; +} +const getAttachmentFile = async(req, res) => { + const attachmentId = req.params.id; + const file = await downloadFile( s3Bucket, s3BucketKey, attachmentId ); + res.attachment( attachmentId ); + res.setHeader('Content-Type', file.ContentType ); + res.send( file.Body ); +} + +module.exports = { getAttachmentFile }; diff --git a/sections/sections.js b/sections/sections.js index 23fdbc3..fabd2f8 100644 --- a/sections/sections.js +++ b/sections/sections.js @@ -14,6 +14,7 @@ const metaGroups = require('./meta-groups/routes.js'); const productCategories = require('./product-categories/routes.js'); const products = require('./products/routes.js'); const publicVehicles = require('./public-vehicles/routes.js'); +const publicLoadAttachments = require('./public-load-attachments/routes.js'); const states = require('./states/routes.js'); const test = require('./test/routes.js'); const users = require('./users/routes.js'); @@ -25,6 +26,7 @@ router.use('/meta-groups', metaGroups); router.use('/product-categories', productCategories); router.use('/products', products); router.use("/public-vehicles", publicVehicles); +router.use('/public-load-attachments', publicLoadAttachments ); router.use('/states', states); router.use("/test", test);