diff --git a/dbTools.js b/dbTools.js new file mode 100644 index 0000000..35c8d06 --- /dev/null +++ b/dbTools.js @@ -0,0 +1,46 @@ +const { v4: uuidv4 } = require('uuid') +const { Admin, ChatHistory, ChatMessage, FoodListing, Guest, Host, Reservation, Review, Warning, sequelize } = require('./models') +require('dotenv').config() + +async function resetDB() { + console.log("Dropping tables...") + try { + await sequelize.drop() + console.log("Tables dropped!") + } catch (err) { + console.error(err) + } +} + +async function clearFiles() { + console.log("Clearing files...") + const FileManager = require("./services/FileManager") + const setupResult = await FileManager.setup(); + if (setupResult !== true) { + console.error(setupResult) + process.exit() + } + + const deleteAllResult = await FileManager.deleteAll(); + if (deleteAllResult !== true) { + console.error(deleteAllResult) + process.exit() + } + console.log("Files cleared!") +} + +sequelize.sync({ alter: true }) + .then(() => { + if (process.argv[2].toLowerCase() == "reset") { + resetDB() + } else if (process.argv[2].toLowerCase() == "clearfiles") { + clearFiles() + } else { + console.log("No tool activated.") + return + } + }) + .catch(err => { + console.error(err) + process.exit() + }) \ No newline at end of file diff --git a/index.js b/index.js index afbb97d..21f6791 100644 --- a/index.js +++ b/index.js @@ -2,7 +2,7 @@ require('./services/BootCheck').check() const express = require('express'); const cors = require('cors'); const { v4: uuidv4 } = require('uuid') -const { FoodListing } = require('./models') +const { FoodListing, Host } = require('./models') require('dotenv').config() const env = process.env.DB_CONFIG || 'development'; @@ -58,7 +58,7 @@ app.use("/createAccount", require('./routes/identity/createAccount')); app.use("/loginAccount", require('./routes/identity/loginAccount')); app.use("/accountRecovery", require('./routes/identity/accountRecovery')); app.use("/listings", require("./routes/listings/listings")); -app.use("/", require("./routes/orders/reservation")); +app.use("/", require("./routes/orders/listingDetails")); async function onDBSynchronise() { const currentDatetime = new Date() @@ -85,6 +85,32 @@ async function onDBSynchronise() { Universal.data["DUMMY_LISTING_ID"] = newListing.listingID console.log(`Created dummy listing with ID: ${newListing.listingID}`) } + + const joshuasHost = await Host.findByPk("272d3d17-fa63-49c4-b1ef-1a3b7fe63cf4") + if (!joshuasHost) { + const newHost = await Host.create({ + "userID": "272d3d17-fa63-49c4-b1ef-1a3b7fe63cf4", + "username": "Jamie Oliver", + "email": "jamie_oliver@gmail.com", + "password": "123456789", + "contactNum": "81118222", + "address": "12 Washington Avenue", + "emailVerified": false, + "favCuisine": "Mexican", + "mealsMatched": "0", + "foodRating": "4", + "hygieneGrade": "5", + "paymentImage": "https://savh.org.sg/wp-content/uploads/2020/05/QRCodeS61SS0119JDBS.png" + }) + + if (!newHost) { + console.log("WARNING: Failed to create dummy host.") + } else { + console.log("Created dummy host.") + } + } else { + console.log("Found dummy host existing already, skipping creation.") + } } // Start server diff --git a/models/index.js b/models/index.js index e963ec5..d5cb4b1 100644 --- a/models/index.js +++ b/models/index.js @@ -46,7 +46,6 @@ if (config.logging == true) { * @type {Sequelize.Sequelize} */ let sequelize; -process.env.DB_MODE = "mysql" if (process.env.DB_MODE == "mysql") { if (config.use_env_variable) { sequelize = new Sequelize(process.env[config.use_env_variable], config); diff --git a/routes/cdn/contentDelivery.js b/routes/cdn/contentDelivery.js index 9820771..7d1e2ce 100644 --- a/routes/cdn/contentDelivery.js +++ b/routes/cdn/contentDelivery.js @@ -32,7 +32,7 @@ router.get("/getImageForListing", async (req, res) => { return; } res.status(200).sendFile(findImageName.substring("SUCCESS: File path: ".length)) - Logger.log(`CDN GETIMAGEFORLISTING: Image(s) for listing ${listingID} sent successfully.`) + // Logger.log(`CDN GETIMAGEFORLISTING: Image(s) for listing ${listingID} sent successfully.`) return; }); diff --git a/routes/cdn/coreData.js b/routes/cdn/coreData.js index a800288..e44053b 100644 --- a/routes/cdn/coreData.js +++ b/routes/cdn/coreData.js @@ -7,13 +7,29 @@ const { FoodListing, Host, Guest, Admin } = require("../../models"); router.get("/listings", async (req, res) => { // GET all food listings try { const foodListings = await FoodListing.findAll(); - foodListings.map(listing => listing.images = listing.images.split("|")); + foodListings.map(listing => (listing.images == null || listing.images == "") ? listing.images = [] : listing.images = listing.images.split("|")); res.status(200).json(foodListings); } catch (error) { res.status(500).send("ERROR: Internal server error"); } }); +router.get("/getListing", async (req, res) => { + const listingID = req.query.id || req.body.listingID; + if (!listingID) { + res.status(400).send("ERROR: Listing ID not provided.") + return + } + + const listing = await FoodListing.findByPk(listingID) + if (!listing || listing == null) { + res.status(404).send("ERROR: Listing not found") + return + } + res.json(listing) + return +}) + router.get("/accountInfo", async (req, res) => { // GET account information try { const targetUserID = req.query.userID; @@ -64,7 +80,7 @@ router.get("/accountInfo", async (req, res) => { // GET account information accountInfo.mealsMatched = user.mealsMatched; } - console.log(`Account info for userID ${targetUserID}: ${JSON.stringify(accountInfo)}`) + // console.log(`Account info for userID ${targetUserID}: ${JSON.stringify(accountInfo)}`) res.status(200).json(accountInfo); } catch (err) { diff --git a/routes/orders/reservation.js b/routes/orders/listingDetails.js similarity index 50% rename from routes/orders/reservation.js rename to routes/orders/listingDetails.js index 052cbfb..b88262a 100644 --- a/routes/orders/reservation.js +++ b/routes/orders/listingDetails.js @@ -4,16 +4,7 @@ const { FoodListing } = require('../../models') const Universal = require('../../services/Universal'); const FileManager = require('../../services/FileManager'); const { storeFile } = require('../../middleware/storeFile'); - -router.get("/listingDetails", async (req, res) => { - const dummyListingID = Universal.data["DUMMY_LISTING_ID"] - const listing = await FoodListing.findByPk(dummyListingID) - if (!listing || listing == null) { - res.status(404).send("ERROR: Listing not found") - return - } - res.json(listing) -}) +const Logger = require('../../services/Logger'); router.post("/uploadListingImage", async (req, res) => { storeFile(req, res, async (err) => { @@ -22,8 +13,7 @@ router.post("/uploadListingImage", async (req, res) => { return } - // const listingID = req.listingID - const listingID = Universal.data["DUMMY_LISTING_ID"] + const listingID = req.body.listingID const listing = await FoodListing.findByPk(listingID) if (!listing) { res.status(404).send("ERROR: Listing not found.") @@ -50,11 +40,60 @@ router.post("/uploadListingImage", async (req, res) => { } await listing.save() res.send("SUCCESS: File uploaded successfully.") + + Logger.log(`ORDERS LISTINGDETAILS UPLOADLISTINGIMAGE: Uploaded image '${req.file.filename}' for listing '${listingID}'.`) return } }) }) +router.post("/deleteListingImage", async (req, res) => { + if (!req.body.listingID || !req.body.imageName) { + res.status(400).send("ERROR: One or more required payloads were not provided.") + return + } + + const listingID = req.body.listingID + const imageName = req.body.imageName + + const listing = await FoodListing.findByPk(listingID) + if (!listing) { + res.status(404).send("ERROR: Listing not found.") + return + } + + if (listing.images == null || !listing.images.split("|").includes(imageName)) { + res.status(404).send("ERROR: Image not found in listing.") + return + } + + try { + const fileDelete = await FileManager.deleteFile(imageName) + if (fileDelete !== true) { + if (fileDelete != "ERROR: File does not exist.") { + Logger.log("ORDERS LISTINGDETAILS DELETELISTINGIMAGE ERROR: Failed to delete image from storage; error: " + fileDelete) + res.status(500).send("ERROR: Failed to delete image.") + return + } else { + Logger.log("ORDERS LISTINGDETAILS DELETELISTINGIMAGE WARNING: Unexpected FM response in deleting image from storage; response: " + fileDelete) + } + } + + const listingImages = listing.images.split("|") + const newImages = listingImages.filter(image => image != imageName) + listing.images = newImages.join("|") + await listing.save() + } catch (err) { + Logger.log("ORDERS LISTINGDETAILS DELETELISTINGIMAGE ERROR: Failed to delete image attached to listing in database; error: " + err) + res.status(500).send("ERROR: Failed to delete image.") + return + } + + Logger.log(`ORDERS LISTINGDETAILS DELETELISTINGIMAGE: Deleted image '${imageName}' from listing '${listingID}'.`) + res.send("SUCCESS: Image deleted successfully.") + return +}) + router.post("/updateListing", async (req, res) => { if (!req.body.listingID) { res.status(400).send("ERROR: Listing ID not provided.") @@ -71,6 +110,8 @@ router.post("/updateListing", async (req, res) => { try { listing.update(req.body) await listing.save() + + Logger.log(`ORDERS LISTINGDETAILS UPDATELISTING: Listing '${listingID}' updated.`) res.send("SUCCESS: Listing updated successfully.") return } catch (err) { diff --git a/services/FileManager.js b/services/FileManager.js index 46fa80c..37501bd 100644 --- a/services/FileManager.js +++ b/services/FileManager.js @@ -319,6 +319,24 @@ class FileManager { return true; } + + static async deleteAll() { + if (!this.checkPermission()) { return "ERROR: FileManager operation permission denied." } + if (!this.#initialized) { return 'ERROR: FileManager must be setup first.' } + + // Delete files on cloud storage + const deleteAllResult = await FireStorage.deleteAll(); + if (deleteAllResult !== true) { + return `ERROR: ${deleteAllResult}` + } + + // Clear file store context and file store + this.#fileStoreContext = {} + this.persistFileStoreContext(); + this.cleanupNonmatchingFiles(); + + return true; + } } module.exports = FileManager; \ No newline at end of file diff --git a/services/FireStorage.js b/services/FireStorage.js index ae9398d..d17b1d6 100644 --- a/services/FireStorage.js +++ b/services/FireStorage.js @@ -65,6 +65,18 @@ class FireStorage { } } + static async deleteAll() { + if (!this.checkPermission()) { return "ERROR: FireStorage operation permission denied." } + if (!this.#initialized) { return 'ERROR: FireStorage must be initialized first.' } + + try { + await this.#bucket.deleteFiles({ force: true }); + return true; + } catch (err) { + return `ERROR: ${err}` + } + } + static async fileExistsAt(filePath) { if (!this.checkPermission()) { return "ERROR: FireStorage operation permission denied." } if (!this.#initialized) { return 'ERROR: FireStorage must be initialized first.' }