Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 5 additions & 11 deletions routes/cdn/contentDelivery.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,26 @@ const { FoodListing,Review } = require("../../models");
router.get("/getImageForListing", async (req, res) => {
const { listingID, imageName } = req.query;
if (!listingID || !imageName) {
res.status(400).send("ERROR: Invalid request parameters.");
return;
return res.status(400).send("ERROR: Invalid request parameters.");
}

// Find the listing
const findListing = await FoodListing.findByPk(listingID);
if (!findListing) {
res.status(404).send("ERROR: Listing not found.");
return;
return res.status(404).send("ERROR: Listing not found.");
}

const findImageName = await FileManager.prepFile(imageName);
Comment thread
Sadliquid marked this conversation as resolved.
if (!findImageName.startsWith("SUCCESS")) {
res.status(404).send("ERROR: Image not found.");
return;
return res.status(404).send("ERROR: Image not found.");
}

const listingImages = findListing.images.split("|");

if (listingImages.includes(imageName) !== true) {
res.status(404).send("ERROR: Requested image does not belong to its corresponding listing.");
return;
return res.status(404).send("ERROR: Requested image does not belong to its corresponding listing.");
}
res.status(200).sendFile(findImageName.substring("SUCCESS: File path: ".length))
// Logger.log(`CDN GETIMAGEFORLISTING: Image(s) for listing ${listingID} sent successfully.`)
return;
return res.status(200).sendFile(findImageName.substring("SUCCESS: File path: ".length));
});

router.get("/getImageForReview", async (req, res) => {
Expand Down
88 changes: 79 additions & 9 deletions routes/cdn/coreData.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ const express = require("express");
const router = express.Router();
const path = require("path");
const FileManager = require("../../services/FileManager");
const Extensions = require("../../services/Extensions");
const { FoodListing, Host, Guest, Admin, Review, Reservation, ReviewLike } = require("../../models");
const Logger = require("../../services/Logger");
const { Sequelize } = require('sequelize');
const Universal = require("../../services/Universal");
const { validateToken, checkUser } = require("../../middleware/auth");
const Extensions = require("../../services/Extensions");
const { Op } = require("sequelize");

router.get('/myAccount', validateToken, (req, res) => {
const userInfo = req.user;
Expand Down Expand Up @@ -43,11 +44,29 @@ router.get("/listings", async (req, res) => { // GET all food listings
where: whereClause,
include: includeClause
});
foodListings.map(listing => (listing.images == null || listing.images == "") ? listing.images = [] : listing.images = listing.images.split("|"));
res.status(200).json(foodListings);

const listingsWithImagesArray = foodListings.map(listing => {
var listingJson = listing.toJSON();
listingJson.images = listingJson.images ? listingJson.images.split("|") : [];
listingJson = Extensions.sanitiseData(
listingJson,
[],
[
"password",
"address",
"createdAt",
"updatedAt",
"HostUserID"
],
[]
)
return listingJson;
});

return res.status(200).json(listingsWithImagesArray);
} catch (error) {
Logger.log("CDN COREDATA LISTINGS ERROR: Failed to retrieve all published listings; error: " + error)
res.status(500).send("ERROR: Internal server error");
Logger.log("CDN COREDATA LISTINGS ERROR: Failed to retrieve all published listings; error: " + error);
return res.status(500).send("ERROR: Internal server error");
}
});

Expand All @@ -57,16 +76,16 @@ router.get("/checkFavouriteListing", async (req, res) => { // GET favourite list
const userID = req.query.userID;
const guest = await Guest.findByPk(userID);
if (!guest) {
return res.status(404).send("Guest not found.");
return res.status(404).send("UERROR: Your account details were not found");
}
const favouriteCuisines = guest.favCuisine.split("|");
if (favouriteCuisines.includes(listingID)) {
res.status(200).json({ message: "SUCCESS: Listing is a favourite", listingIsFavourite: true });
return res.status(200).json({ message: "SUCCESS: Listing is a favourite", listingIsFavourite: true });
} else {
res.status(200).json({ message: "SUCCESS: Listing is not a favourite", listingIsFavourite: false });
return res.status(200).json({ message: "SUCCESS: Listing is not a favourite", listingIsFavourite: false });
}
} catch (error) {
res.status(500).send("ERROR: Internal server error");
return res.status(500).send("ERROR: Internal server error");
}
});

Expand Down Expand Up @@ -294,4 +313,55 @@ router.get("/getReviews", checkUser, async (req, res) => { // GET full reviews l
}
})

router.get("/consolidateReviewsStatistics", async (req, res) => { // GET full reservations list
Comment thread
Sadliquid marked this conversation as resolved.
const { hostID } = req.query;
if (!hostID) {
return res.status(400).send("UERROR: One or more required payloads were not provided");
}
try {
const findHost = await Host.findByPk(hostID);
if (!findHost) {
return res.status(404).send("ERROR: Host doesn't exist");
} else {
const hostFoodRatings = await Review.findAll({
where: { hostID },
attributes: ['foodRating']
});
if (hostFoodRatings.length > 0) {
const oneStarRatings = hostFoodRatings.filter(rating => rating.foodRating === 1).length;
const twoStarRatings = hostFoodRatings.filter(rating => rating.foodRating === 2).length;
const threeStarRatings = hostFoodRatings.filter(rating => rating.foodRating === 3).length;
const fourStarRatings = hostFoodRatings.filter(rating => rating.foodRating === 4).length;
const fiveStarRatings = hostFoodRatings.filter(rating => rating.foodRating === 5).length;
const totalRatings = hostFoodRatings.length;

const consolidatedData = {
oneStar: (oneStarRatings / totalRatings) * 100,
twoStar: (twoStarRatings / totalRatings) * 100,
threeStar: (threeStarRatings / totalRatings) * 100,
fourStar: (fourStarRatings / totalRatings) * 100,
fiveStar: (fiveStarRatings / totalRatings) * 100
}
return res.status(200).json(consolidatedData);
} else {
return res.status(200).json(
{
message: "No reviews found.",
consolidatedData: {
oneStar: 0,
twoStar: 0,
threeStar: 0,
fourStar: 0,
fiveStar: 0
}
}
);
}
}
} catch (err) {
Logger.log(`CDN COREDATA CONSOLIDATEREVIEWSSTATISTICS ERROR: Failed to consolidate review statistics: ${err}.`);
return res.status(500).send("ERROR: An error occured while retrieving review statistics");
}
});

module.exports = { router, at: '/cdn' };
62 changes: 62 additions & 0 deletions routes/identity/MakanHistory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const express = require("express");
const router = express.Router();
const path = require("path");
const FileManager = require("../../services/FileManager");
const Extensions = require("../../services/Extensions");
const { FoodListing, Host, Guest, Admin, Review, Reservation, ReviewLike } = require("../../models");
const Logger = require("../../services/Logger");
const { Sequelize } = require('sequelize');
const Universal = require("../../services/Universal");
const { validateToken, checkUser } = require("../../middleware/auth");
const { Op } = require("sequelize");

router.get("/getGuestPastReservations", validateToken, async(req, res) => {
const userID = req.user.userID;
if (!userID) {
return res.status(400).send("ERROR: One or more required payloads were not provided");
}
try {
const user = await Guest.findByPk(userID) || await Host.findByPk(userID);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do take note that, in the future, you have to just do Guest.findByPk as we discussed that Hosts will just be solely hosts and unable to make reservations. @Sadliquid

if (!user) {
return res.status(404).send("ERROR: User doesn't exist");
} else {
const pastReservations = await Reservation.findAll({
where: {
guestID: userID,
datetime: {
[Op.lt]: new Date().toISOString()
}
}
});
if (pastReservations.length > 0) {
const foodListings = await FoodListing.findAll({
where: {
listingID: {
[Op.in]: pastReservations.map(reservation => reservation.listingID)
}
},
include: [{
model: Host,
attributes: ["username", "foodRating"]
}]
});
if (foodListings) {
if (foodListings.length > 0) {
return res.status(200).json({ pastReservations: pastReservations, foodListings: foodListings });
Comment thread
Sadliquid marked this conversation as resolved.
} else {
return res.status(400).send("ERROR: Could not find any food listings that were tied to this reservation");
}
} else {
return res.status(400).send("ERROR: An error occured while retrieving food listings for the past reservations");
}
} else {
return res.status(200).json({ pastReservations: [], foodListings: [] });
}
}
} catch (err) {
Logger.log(`MAKAN_HISTORY GETGUESTPASTRESERVATIONS ERROR: ${err}`)
return res.status(500).send("ERROR: An error occured while retrieving user's past reservations");
}
});

module.exports = { router, at: '/makanHistory' };
68 changes: 27 additions & 41 deletions routes/listings/listings.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,28 @@ router.post("/addListing", validateToken, async (req, res) => {
title: yup.string().trim().required(),
shortDescription: yup.string().trim().required(),
longDescription: yup.string().trim().required(),
portionPrice: yup.number().required(),
totalSlots: yup.number().required(),
datetime: yup.string().trim().required()
portionPrice: yup.number().min(1).max(10).required(),
totalSlots: yup.number().min(1).max(10).required(),
datetime: yup.string().trim().required(),
publishInstantly: yup.boolean().required()
});

if (req.files.length === 0) {
res.status(400).send("ERROR: No image uploaded");
return;
return res.status(400).send("UERROR: No image was uploaded");
} else {
var validatedData;
try {
validatedData = await addListingSchema.validate(req.body, { abortEarly: false });
} catch (validationError) {
res.status(400).send(`ERROR: ${validationError.errors.join(', ')}`);
return;
return res.status(400).send("UERROR: One or more entered fields are invalid");
}

if (err instanceof multer.MulterError) {
Logger.log(`LISTINGS ADDLISTING: Image upload error: ${err}`);
res.status(400).send("ERROR: Image upload error");
return res.status(400).send("UERROR: Image(s) not accepted");
} else if (err) {
Logger.log(`LISTINGS ADDLISTING: Internal server error: ${err}`);
res.status(500).send("ERROR: Internal server error");
return res.status(500).send("ERROR: Failed to process image(s)");
}
var allImagesSuccess = false;
for (let i = 0; i < req.files.length; i++) {
Expand All @@ -57,15 +56,13 @@ router.post("/addListing", validateToken, async (req, res) => {
for (let i = 0; i < req.files.length; i++) {
await FileManager.deleteFile(req.files[i].filename);
}
Logger.log(`LISTINGS ADDLISTING: One or more image checks failed. ${req.files.length} image(s) deleted successfully.`)
res.status(400).send("ERROR: Failed to upload image");
return;
Logger.log(`LISTINGS ADDLISTING ERROR: One or more image checks failed. ${req.files.length} image(s) deleted successfully.`)
return res.status(400).send("ERROR: Failed to upload image(s)");
}

const hostInfo = await Host.findByPk(req.user.userID);
if (!hostInfo) {
res.status(404).send("ERROR: Host not found");
return;
return res.status(404).send("UERROR: Your account details were not found");
}
try {
const encodedAddress = encodeURIComponent(String(hostInfo.address));
Expand Down Expand Up @@ -93,7 +90,7 @@ router.post("/addListing", validateToken, async (req, res) => {
});
let approximateAddress = `${street}, ${city}`;
if (state) {
approximateAddress += `, ${state}`; // For contexts outside of Singapore
approximateAddress += `, ${state}`;
}

const listingDetails = {
Expand All @@ -109,24 +106,21 @@ router.post("/addListing", validateToken, async (req, res) => {
address: hostInfo.address,
hostID: hostInfo.userID,
coordinates: coordinates.lat + "," + coordinates.lng,
published: true,
published: validatedData.publishInstantly,
};
const addListingResponse = await FoodListing.create(listingDetails);
if (addListingResponse) {
res.status(200).json({
Logger.log(`LISTINGS ADDLISTING ERROR: Listing with listingID ${listingDetails.listingID} created successfully.`)
return res.status(200).json({
message: "SUCCESS: Food listing created successfully",
listingDetails,
});
Logger.log(`LISTINGS ADDLISTING ERROR: Listing with listingID ${listingDetails.listingID} created successfully.`)
return;
} else {
res.status(400).send("ERROR: Failed to create food listing");
return;
return res.status(400).send("ERROR: Failed to create food listing");
}
} catch (error) {
res.status(500).send("ERROR: Internal server error");
Logger.log(`LISTINGS ADDLISTING ERROR: Internal server error: ${error}`);
return;
return res.status(500).send("ERROR: Internal server error");
}
}
});
Expand All @@ -136,23 +130,19 @@ router.put("/toggleFavouriteListing", validateToken, async (req, res) => {
const { userID } = req.user;
const { listingID } = req.body;
if (!userID || !listingID) {
res.status(400).send("ERROR: One or more required payloads were not provided");
return;
return res.status(400).send("ERROR: One or more required payloads were not provided");
}

const findUser = await Guest.findByPk(userID) || await Host.findByPk(userID);
if (!findUser) {
res.status(404).send("ERROR: User not found");
return;
return res.status(404).send("ERROR: Your account details were not found");
}

const findListing = await FoodListing.findByPk(listingID);
if (!findListing) {
res.status(404).send("ERROR: Listing not found");
return;
return res.status(404).send("ERROR: Listing doesn't exist");
} else if (userID === findListing.hostID) {
res.status(400).send("ERROR: Host cannot favourite their own listing");
return;
return res.status(400).send("UERROR: Hosts cannot add their own listings to favourites");
}

let favCuisine = findUser.favCuisine || '';
Expand All @@ -167,25 +157,23 @@ router.put("/toggleFavouriteListing", validateToken, async (req, res) => {
findUser.favCuisine = favCuisine;
await findUser.save();
const favourite = favCuisine.split("|").includes(listingID);
res.status(200).json({
return res.status(200).json({
message: `SUCCESS: Listing ${favourite ? 'added to' : 'removed from'} favourites successfully`,
favourite: favourite
});
} catch (error) {
res.status(400).send("ERROR: Failed to update user's favourites");
return res.status(400).send("ERROR: Failed to add/remove listing from favourites");
}
});

router.delete("/deleteListing", async (req, res) => {
const { listingID } = req.body;
if (!listingID) {
res.status(400).send("ERROR: One or more required payloads were not provided");
return;
return res.status(400).send("ERROR: One or more required payloads were not provided");
}
const findListing = await FoodListing.findByPk(listingID);
if (!findListing) {
res.status(404).send("ERROR: Listing not found");
return;
return res.status(404).send("ERROR: Listing doesn't exist");
}
const listingImages = findListing.images.split("|");
for (let i = 0; i < listingImages.length; i++) {
Expand All @@ -194,12 +182,10 @@ router.delete("/deleteListing", async (req, res) => {
}
const deleteListing = await FoodListing.destroy({ where: { listingID: listingID } });
if (deleteListing) {
res.status(200).json({ message: "SUCCESS: Listing deleted successfully" });
Logger.log(`LISTINGS DELETELISTING: Listing with listingID ${listingID} deleted successfully.`)
return;
return res.status(200).send("SUCCESS: Listing deleted successfully");
} else {
res.status(400).send("ERROR: Failed to delete listing");
return;
return res.status(400).send("ERROR: Failed to delete listing");
}
});

Expand Down