diff --git a/config/index.js b/config/index.js index cf5d39e..e3433a3 100644 --- a/config/index.js +++ b/config/index.js @@ -9,7 +9,6 @@ exports.dbPort = process.env.DB_PORT; exports.dbName = process.env.DB_NAME; exports.cookiesSecret = process.env.COOKIES_SECRET; exports.jwtSecret = process.env.JWT_SECRET; -exports.CRM_KEY = process.env.CRM_KEY; -exports.CRM_USER = process.env.CRM_USER; -exports.CRM_EMAIL = process.env.CRM_EMAIL; exports.MAIL_PASS = process.env.MAIL_PASS; +exports.s3_key = process.env.S3_KEY; +exports.s3_secret = process.env.S3_SECRET; \ No newline at end of file diff --git a/loaders/mongoose.js b/loaders/mongoose.js index 33184a8..8ae93e5 100644 --- a/loaders/mongoose.js +++ b/loaders/mongoose.js @@ -1,15 +1,12 @@ const mongoose = require("mongoose"); const { dbPass, -/* dbUser, - dbHost, - dbPort, */ dbName, } = require("../config/index.js"); const loadMongoose = async () => { const connection = await mongoose.connect( - `mongodb+srv://menui_db_user:${dbPass}@menui-database.9quwf.mongodb.net/${dbName}?retryWrites=true&w=majority`, + `mongodb+srv://restricted_user:${dbPass}@menui-database.9quwf.mongodb.net/${dbName}?retryWrites=true&w=majority`, { useNewUrlParser: true, useUnifiedTopology: true, @@ -21,14 +18,4 @@ const loadMongoose = async () => { ); }; -module.exports = loadMongoose; - - -// AZURE -/* "mongodb://" + - dbHost + - ":" + - dbPort + - "/" + - dbName + - "?ssl=true&replicaSet=globaldb", */ \ No newline at end of file +module.exports = loadMongoose; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index a162dba..5a3f73c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2036,6 +2036,53 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, + "aws-sdk": { + "version": "2.789.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.789.0.tgz", + "integrity": "sha512-Jqq+M4N0EgkyS4OPf05UHa7IWUcpuBdnpwMRgBnu4Ju6PxpOTh1UQcmYepVmIN3m6YVpLwFctEYzAMJFM3LT1A==", + "requires": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.15.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "uuid": "3.3.2", + "xml2js": "0.4.19" + }, + "dependencies": { + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + }, + "sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" + } + } + }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -2259,6 +2306,11 @@ } } }, + "base64-js": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.0.tgz", + "integrity": "sha512-Jrdy04F2EKcNggUDfubMUPNAZg2vMquLQSm8sKLYJvz40ClFL1S8GKyDshGkNsbNNE5Z+fQavzU7nSK1I9JUGA==" + }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -2378,6 +2430,16 @@ "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.4.tgz", "integrity": "sha512-S/yKGU1syOMzO86+dGpg2qGoDL0zvzcb262G+gqEy6TgP6rt6z6qxSFX/8X6vLC91P7G7C3nLs0+bvDzmvBA3Q==" }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, "buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -3435,6 +3497,11 @@ "resolved": "https://registry.npmjs.org/feature-policy/-/feature-policy-0.3.0.tgz", "integrity": "sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ==" }, + "file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -3808,6 +3875,11 @@ } } }, + "html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==" + }, "html-encoding-sniffer": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", @@ -3865,6 +3937,11 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, "ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", @@ -4113,6 +4190,14 @@ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, + "is-svg": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz", + "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=", + "requires": { + "html-comment-regex": "^1.1.0" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -5167,6 +5252,11 @@ } } }, + "jmespath": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", + "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -5711,6 +5801,16 @@ "xtend": "^4.0.0" } }, + "multer-s3": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/multer-s3/-/multer-s3-2.9.0.tgz", + "integrity": "sha512-qLF8pCD5HhXLLd954q49B63x3bk6Fe0jqD3eM0FVcGtqhiSVuTrchEDAo0mnO5pc34cMuX/CVCCbPkGTjX2xUA==", + "requires": { + "file-type": "^3.3.0", + "is-svg": "^2.1.0", + "run-parallel": "^1.1.6" + } + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -6262,6 +6362,11 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -6642,6 +6747,11 @@ "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", "dev": true }, + "run-parallel": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz", + "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==" + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -7717,6 +7827,22 @@ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", "dev": true }, + "url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } + } + }, "url-parse-lax": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", diff --git a/package.json b/package.json index 9cbbb3c..1399bef 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "license": "ISC", "dependencies": { "@azure/storage-blob": "^12.2.0-preview.1", + "aws-sdk": "^2.789.0", "axios": "^0.20.0", "bcryptjs": "^2.4.3", "body-parser": "^1.19.0", @@ -25,6 +26,7 @@ "jsonwebtoken": "^8.5.1", "mongoose": "^5.9.22", "multer": "^1.4.2", + "multer-s3": "^2.9.0", "nodemailer": "^6.4.11", "nodemon": "^2.0.4", "string-sanitizer": "^1.1.1", diff --git a/routes/routeImg.js b/routes/routeImg.js index 2c08d9f..9a04f64 100644 --- a/routes/routeImg.js +++ b/routes/routeImg.js @@ -1,7 +1,7 @@ const express = require("express"); const { validateUserToken, handleError } = require("../services/services.js"); -const { uploadBlob } = require("../services/azureServices.js"); -// Azure +const { uploadBlob } = require("../services/oceanServices.js"); +// FileStorage const multer = require("multer"); var router = express.Router(); diff --git a/services/azureServices.js b/services/azureServices.js deleted file mode 100644 index be3611b..0000000 --- a/services/azureServices.js +++ /dev/null @@ -1,101 +0,0 @@ -const azureBlob = require("@azure/storage-blob"); -const getStream = require("into-stream"); -const { newError } = require("./services.js"); - -// SETUP -const containerURL = `https://${process.env.AZURE_STORAGE_ACCOUNT_NAME}.blob.core.windows.net/img/`; -const container = "img"; -const OneMB = 1024 * 1024; -const uploadOptions = { bufferSize: 4 * OneMB, maxBuffers: 2 }; -const sharedKeyCredential = new azureBlob.StorageSharedKeyCredential( - process.env.AZURE_STORAGE_ACCOUNT_NAME, - process.env.AZURE_STORAGE_ACCOUNT_KEY -); -const pipeline = azureBlob.newPipeline(sharedKeyCredential); -const blobServiceClient = new azureBlob.BlobServiceClient( - `https://${process.env.AZURE_STORAGE_ACCOUNT_NAME}.blob.core.windows.net`, - pipeline -); - -// CODE -async function renameBlob(blobURL) { - try { - const blobName = blobURL.replace(containerURL, ""); - const containerClient = blobServiceClient.getContainerClient(container); - const tempBlob = containerClient.getBlobClient(blobName); - const newBlob = containerClient.getBlobClient(removePrefix(blobName)); - - await newBlob.syncCopyFromURL(tempBlob.url); - return newBlob.url; - } catch (e) { - throw newError("Unable to save image", 500); - } -} - -async function uploadBlob(request, resp) { - const blobName = makeTempBlobName(request.file.originalname); - const stream = getStream(request.file.buffer); - const containerClient = blobServiceClient.getContainerClient(container); - const blockBlobClient = containerClient.getBlockBlobClient(blobName); - const response = { - imgURL: `https://${process.env.AZURE_STORAGE_ACCOUNT_NAME}.blob.core.windows.net/img/${blobName}`, - }; - - try { - await blockBlobClient - .uploadStream( - stream, - uploadOptions.bufferSize, - uploadOptions.maxBuffers, - { blobHTTPHeaders: { blobContentType: "image/jpeg" } } - ) - .then(() => { - setDeleteTempBlobTimer(blobName, containerClient, 1); - resp.send(response); - }); - } catch (err) { - console.log(err); - throw newError("Unable to save image", 500); - } -} - -function removePrefix(string) { - const newString = string.replace("TEMP_", ""); - return newString; -} - -function makeTempBlobName(originalName) { - const identifier = Math.random().toString().replace(/0\./, ""); - return `TEMP_${identifier}-${originalName}`; -} - -function setDeleteTempBlobTimer(blobName, containerClient, minutes) { - let blob = containerClient.getBlobClient(blobName); - setTimeout(() => { - blob.delete(); - }, 1000 * 60 * minutes); -} - -async function deleteImage(url) { - if (!url || url === "" || url === "empty") { - return; - } else { - try { - const containerClient = blobServiceClient.getContainerClient(container); - const containerUrl = containerClient.url + "/"; - const blobName = url.replace(containerUrl, ""); - console.log(`BLOB NAME = ${blobName}`); - const blob = containerClient.getBlobClient(blobName); - await blob.delete(); - } catch (error) { - console.log(error); - } - } -} - -exports.renameBlob = renameBlob; -exports.uploadBlob = uploadBlob; -exports.removePrefix = removePrefix; -exports.makeTempBlobName = makeTempBlobName; -exports.setDeleteTempBlobTimer = setDeleteTempBlobTimer; -exports.deleteImage = deleteImage; diff --git a/services/dataPrepServices.js b/services/dataPrepServices.js index 311ceb3..94f0da7 100644 --- a/services/dataPrepServices.js +++ b/services/dataPrepServices.js @@ -5,7 +5,7 @@ const Dish = require("../models/dish.js"); const User = require("../models/users.js"); const Restaurant = require("../models/restaurant.js"); const { fetchMultipleRestaurants } = require("./databaseServices.js"); -const { deleteImage } = require("./azureServices.js"); +const { deleteImage } = require("./oceanServices.js"); async function createUser(request) { const password = await hashPass(request.body.password); diff --git a/services/databaseServices.js b/services/databaseServices.js index 62a75a1..63426de 100644 --- a/services/databaseServices.js +++ b/services/databaseServices.js @@ -2,7 +2,7 @@ const Restaurant = require("../models/restaurant.js"); const Dish = require("../models/dish.js"); const User = require("../models/users.js"); const Payments = require("../models/payments.js"); -const { deleteImage } = require("./azureServices.js"); +const { deleteImage } = require("./oceanServices.js"); const { appendDishToLunchSet, removeDishFromLunchSet, diff --git a/services/oceanServices.js b/services/oceanServices.js new file mode 100644 index 0000000..63ee879 --- /dev/null +++ b/services/oceanServices.js @@ -0,0 +1,106 @@ +const getStream = require("into-stream"); +const { s3_key, s3_secret } = require('../config/index.js'); +const aws = require('aws-sdk'); +const spacesEndpoint = new aws.Endpoint('fra1.digitaloceanspaces.com'); +const s3 = new aws.S3({ + endpoint: spacesEndpoint, + accessKeyId: s3_key, + secretAccessKey: s3_secret +}); +const { newError } = require("./services.js"); + +// SETUP + +// CODE +async function renameBlob(blobURL) { + try { + const containerURL = "https://menuicdn.fra1.digitaloceanspaces.com/"; + const key = blobURL.replace(containerURL, ""); + s3.copyObject({ + CopySource: "menuicdn/" + key, + Bucket: "menuicdn", + Key: removePrefix(key) + }, (err) => { + if (err) { + console.log(err) + } else { + deleteImage(blobURL) + } + }); + const newUrl = containerURL + removePrefix(key); + return newUrl; + } catch (e) { + throw newError("Unable to save image", 500); + } +} + +async function uploadBlob(request, resp) { + const blobName = makeTempBlobName(request.file.originalname); + const stream = getStream(request.file.buffer); + const response = { + imgURL: `https://menuicdn.fra1.digitaloceanspaces.com/${blobName}`, + }; + + try { + s3.upload({ + Bucket: 'menuicdn', + Body: stream, + Key: blobName, + ACL: 'public-read', + ContentType: request.file.mimetype + }, (err, data) => {{ + setDeleteTempBlobTimer(blobName, 15); + resp.send(response); + } + }); + } catch (err) { + throw newError("Unable to save image", 500); + } +} + +function removePrefix(string) { + const newString = string.replace("TEMP_", ""); + return newString; +} + +function makeTempBlobName(originalName) { + const identifier = Math.random().toString().replace(/0\./, ""); + return `TEMP_${identifier}-${originalName}`; +} + +function setDeleteTempBlobTimer(blobName, minutes) { + setTimeout(() => { + s3.deleteObject({ + Key: blobName, + Bucket: "menuicdn" + }, (err) => { + console.log(err) + }); + }, 1000 * 60 * minutes); +} + +async function deleteImage(url) { + if (!url || url === "" || url === "empty") { + return; + } else { + try { + const containerUrl = "https://menuicdn.fra1.digitaloceanspaces.com/"; + const key = url.replace(containerUrl, ""); + s3.deleteObject({ + Key: key, + Bucket: "menuicdn" + }, (err) => { + console.log(err) + }) + } catch (error) { + console.log(error); + } + } +} + +exports.renameBlob = renameBlob; +exports.uploadBlob = uploadBlob; +exports.removePrefix = removePrefix; +exports.makeTempBlobName = makeTempBlobName; +exports.setDeleteTempBlobTimer = setDeleteTempBlobTimer; +exports.deleteImage = deleteImage; diff --git a/services/services.js b/services/services.js index 5ed9864..4d742f7 100644 --- a/services/services.js +++ b/services/services.js @@ -3,7 +3,7 @@ const Dish = require("../models/dish.js"); const User = require("../models/users.js"); const mongoose = require("mongoose"); const sanitizer = require("string-sanitizer"); -const { renameBlob } = require("./azureServices.js"); +const { renameBlob } = require("./oceanServices.js"); const jwt = require("jsonwebtoken"); const bcrypt = require("bcryptjs"); const { jwtSecret } = require("../config/index.js");