From fec9b68d21664cfe009c6e28dd1f167c25ad97df Mon Sep 17 00:00:00 2001 From: anaspacheco Date: Tue, 28 Nov 2023 10:16:26 -0500 Subject: [PATCH] feedback routes and testing --- back-end/app.js | 134 ++++++++++++++--------- back-end/models/Feedback.js | 27 +++++ back-end/routes/authentication-routes.js | 73 ++++++------ back-end/routes/feedback-routes.js | 85 ++++++++++++++ back-end/test/feedback.test.js | 83 ++++++++++++++ back-end/test/register.test.js | 47 -------- 6 files changed, 314 insertions(+), 135 deletions(-) create mode 100644 back-end/models/Feedback.js create mode 100644 back-end/routes/feedback-routes.js create mode 100644 back-end/test/feedback.test.js delete mode 100644 back-end/test/register.test.js diff --git a/back-end/app.js b/back-end/app.js index 2bc8aca..91c30bd 100644 --- a/back-end/app.js +++ b/back-end/app.js @@ -1,70 +1,102 @@ // import and instantiate express -const express = require("express") -const app = express() -const cors = require("cors") -const morgan = require("morgan") -require("dotenv").config({ silent: true }) -const jwt = require("jsonwebtoken") -const passport = require("passport") +const express = require("express"); +const app = express(); +const cors = require("cors"); +const morgan = require("morgan"); +require("dotenv").config({ silent: true }); +const jwt = require("jsonwebtoken"); +const passport = require("passport"); +const jwtStrategy = require("./config/jwt-config.js"); +passport.use(jwtStrategy); -const jwtStrategy = require("./config/jwt-config.js") -passport.use(jwtStrategy) +app.use(passport.initialize()); -app.use(passport.initialize()) - -const mongoose = require("mongoose") -const User = require("./models/User.js") +const mongoose = require("mongoose"); +const User = require("./models/User.js"); +const Feedback = require("./models/Feedback.js"); // connect to the database try { - mongoose.connect(process.env.MONGODB_URI) - console.log(`Connected to MongoDB.`) + mongoose.connect(process.env.MONGODB_URI); + console.log(`Connected to MongoDB.`); } catch (err) { console.log( `Error connecting to MongoDB user account authentication will fail: ${err}` - ) + ); } +app.use(morgan("dev", { skip: (req, res) => process.env.NODE_ENV === "test" })); +app.use(express.json()); +app.use(express.urlencoded({ extended: true })); -app.use(morgan("dev", { skip: (req, res) => process.env.NODE_ENV === "test" })) -app.use(express.json()) -app.use(express.urlencoded({ extended: true })) +app.use(cors({ origin: process.env.FRONT_END_DOMAIN, credentials: true })); -app.use(cors({ origin: process.env.FRONT_END_DOMAIN, credentials: true })) +const authenticationRoutes = require("./routes/authentication-routes.js"); +const feedbackRoutes = require("./routes/feedback-routes.js"); -const authenticationRoutes = require("./routes/authentication-routes.js") +app.use("/auth", authenticationRoutes()); +app.use("/feedback", feedbackRoutes()); -app.use("/auth", authenticationRoutes()) +app.get("/getRoute", (req, res) => { + const busStops = { + unionsquare: [40.73498551788369, -73.990696048825], + tompkins: [40.7251277537963, -73.98121749968648], + hamilton: [40.720213039417494, -73.980207088181], + eastbroadway: [40.7141707879376, -73.9901227463216], + chinatown: [40.71559782189394, -73.99850504010124], + financial: [40.70811320415039, -74.00798229139403], + tribeca: [40.716765448621125, -74.00913568860388], + canal: [40.721857387647354, -74.00518353611693], + soho: [40.72488113646396, -74.00162848801607], + greenwich: [40.733368703161425, -74.00412600650982], + washingtonsquare: [40.731522867853634, -73.9971283464239], + jayst: [40.69225251854892, -73.98648974152808], + dumbo: [40.70372584858276, -73.98861865993923], + ikea: [40.672611811522145, -74.01009335210519], + }; + const routes = { + route1: [ + busStops.washingtonsquare, + busStops.unionsquare, + busStops.tompkins, + busStops.hamilton, + busStops.eastbroadway, + busStops.chinatown, + busStops.financial, + busStops.tribeca, + busStops.canal, + busStops.soho, + busStops.greenwich, + busStops.washingtonsquare, + ], + route2: [busStops.jayst, busStops.dumbo, busStops.ikea], + route3: [ + busStops.jayst, + busStops.eastbroadway, + busStops.washingtonsquare, + busStops.chinatown, + busStops.financial, + ], + route4: [ + busStops.eastbroadway, + busStops.washingtonsquare, + busStops.unionsquare, + busStops.tompkins, + busStops.hamilton, + busStops.eastbroadway, + ], + }; + const graph = createGraph(routes); + let optimalRoute = findOptimalRoute( + graph, + req.query.origin, + req.query.destination + ); + console.log(optimalRoute); + res.send("Hello World!"); -app.get('/getRoute', (req, res) => { - const busStops = { - unionsquare: [40.73498551788369, -73.990696048825], - tompkins: [40.7251277537963, -73.98121749968648], - hamilton: [40.720213039417494, -73.980207088181], - eastbroadway: [40.7141707879376, -73.9901227463216], - chinatown: [40.71559782189394, -73.99850504010124], - financial: [40.70811320415039, -74.00798229139403], - tribeca: [40.716765448621125, -74.00913568860388], - canal: [40.721857387647354, -74.00518353611693], - soho: [40.72488113646396, -74.00162848801607], - greenwich: [40.733368703161425, -74.00412600650982], - washingtonsquare: [40.731522867853634, -73.9971283464239], - jayst: [40.69225251854892, -73.98648974152808], - dumbo: [40.70372584858276, -73.98861865993923], - ikea: [40.672611811522145, -74.01009335210519] - } - const routes = { - route1: [busStops.washingtonsquare, busStops.unionsquare, busStops.tompkins, busStops.hamilton, busStops.eastbroadway, busStops.chinatown, busStops.financial, busStops.tribeca, busStops.canal, busStops.soho, busStops.greenwich, busStops.washingtonsquare], - route2: [busStops.jayst, busStops.dumbo, busStops.ikea], - route3: [busStops.jayst, busStops.eastbroadway, busStops.washingtonsquare, busStops.chinatown, busStops.financial], - route4: [busStops.eastbroadway, busStops.washingtonsquare, busStops.unionsquare, busStops.tompkins, busStops.hamilton, busStops.eastbroadway], - } - const graph = createGraph(routes); - let optimalRoute = findOptimalRoute(graph, req.query.origin, req.query.destination); - console.log(optimalRoute); - res.send('Hello World!'); -}) +}); -module.exports = app +module.exports = app; diff --git a/back-end/models/Feedback.js b/back-end/models/Feedback.js new file mode 100644 index 0000000..b85c78a --- /dev/null +++ b/back-end/models/Feedback.js @@ -0,0 +1,27 @@ +// a mongoose model of a feedback entry +const mongoose = require("mongoose") +const Schema = mongoose.Schema + +const FeedbackSchema = new Schema({ + user: { + type: String, + unique: true, + required: true, + }, + timestamp: { + type: Date, + required: true, + }, + category: { + type: String, + required: true, + }, + feedback:{ + type: String, + required: true, + }, +}) + +const Feedback = mongoose.model("Feedback", FeedbackSchema) + +module.exports = Feedback \ No newline at end of file diff --git a/back-end/routes/authentication-routes.js b/back-end/routes/authentication-routes.js index e7063a4..ba2154c 100644 --- a/back-end/routes/authentication-routes.js +++ b/back-end/routes/authentication-routes.js @@ -1,8 +1,9 @@ -const express = require("express"); +const express = require("express"); const mongoose = require("mongoose"); const User = require("../models/User.js"); +// a method that constains code to handle authentication-specific routes const authenticationRouter = () => { const router = express.Router(); @@ -22,13 +23,13 @@ const authenticationRouter = () => { try { const user = await new User({ username, password }).save(); console.error(`New user: ${user}`); - const token = user.generateJWT(); + const token = user.generateJWT(); res.json({ success: true, message: "User saved successfully.", token: token, username: user.username, - }); + }); next(); } catch (err) { console.error(`Failed to save user: ${err}`); @@ -53,50 +54,48 @@ const authenticationRouter = () => { next(); } - try { - const user = await User.findOne({ username: username }).exec(); - if (!user) { - console.error(`User not found.`); - return res.status(401).json({ - success: false, - message: "User not found in the database.", + try { + const user = await User.findOne({ username: username }).exec(); + if (!user) { + console.error(`User not found.`); + return res.status(401).json({ + success: false, + message: "User not found in the database.", + }); + next(); + } else if (!user.validPassword(password)) { + console.error(`Incorrect password.`); + return res.status(401).json({ + success: false, + message: "Incorrect password.", + }); + next(); + } + console.log("User logged in successfully."); + const token = user.generateJWT(); + return res.json({ + success: true, + message: "User logged in successfully.", + token: token, + username: user.username, }); next(); - } else if (!user.validPassword(password)) { - console.error(`Incorrect password.`); - return res.status(401).json({ + } catch (err) { + console.error(`Error looking up user: ${err}`); + return res.status(500).json({ success: false, - message: "Incorrect password.", + message: "Error looking up user in the database.", + error: err, }); next(); } - console.log("User logged in successfully."); - const token = user.generateJWT(); - return res.json({ - success: true, - message: "User logged in successfully.", - token: token, - username: user.username, - }); - next(); - } catch (err) { - console.error(`Error looking up user: ${err}`); - return res.status(500).json({ - success: false, - message: "Error looking up user in the database.", - error: err, - }); - next(); - } - } - ); + }); // a route to handle logging out requests to /auth/logout router.get("/logout", function (req, res, next) { res.json({ success: true, - message: - "Successfully logged out", + message: "Successfully logged out", }); next(); }); @@ -104,4 +103,4 @@ const authenticationRouter = () => { return router; }; -module.exports = authenticationRouter; \ No newline at end of file +module.exports = authenticationRouter; diff --git a/back-end/routes/feedback-routes.js b/back-end/routes/feedback-routes.js new file mode 100644 index 0000000..d23e5c1 --- /dev/null +++ b/back-end/routes/feedback-routes.js @@ -0,0 +1,85 @@ +const express = require("express"); +const mongoose = require("mongoose"); +const Feedback = require("../models/Feedback.js"); + +// a method that constains code to handle feedback-specific routes +const feedbackRouter = () => { + const router = express.Router(); + + router.post("/newfeedback", async (req, res, next) => { + const { user, timestamp, category, feedback } = req.body; + if (!user || !timestamp || !category || !feedback) { + return res.status(401).json({ + success: false, + message: "Invalid request. Please provide all required fields.", + }); + next(); + } + try { + const newFeedback = await new Feedback({ user, timestamp, category, feedback }).save(); + console.error(`New feedback: ${newFeedback}`); + return res.json({ + success: true, + message: "Feedback saved successfully.", + feedback: newFeedback, + }); + next(); + } catch (err) { + console.error(`Failed to save feedback: ${err}`); + return res.status(500).json({ + success: false, + message:"Error saving feedback to database.", + error: err, + }); + next(); + } + }); + + // READ: Get all feedback entries + router.get("/allfeedback", async (req, res, next) => { + try { + const feedbackEntries = await Feedback.find(); + return res.json({ + success: true, + message: "Feedback retrieved successfully.", + entries: feedbackEntries, + }); + next(); + } catch (error) { + console.error(`Error fetching entries: ${err}`); + return res.status(500).json({ + success: false, + message: "Error looking up feedback in database.", + error: err, + }); + next(); + } + }); + + //Delete feedback entry + router.delete("/:id", async (req, res, next) => { + const id = req.params.id; + try { + const deletedFeedback = await Feedback.findByIdAndDelete(id); + return res.json({ + success: true, + message: "Feedback deleted successfully.", + feedback: deletedFeedback, + }); + next(); + } catch (error) { + console.error(`Error deleting feedback: ${err}`); + return res.status(500).json({ + success: false, + message: "Error deleting feedback in database.", + error: err, + }); + next(); + } + }); + + + return router; + }; + + module.exports = feedbackRouter; \ No newline at end of file diff --git a/back-end/test/feedback.test.js b/back-end/test/feedback.test.js new file mode 100644 index 0000000..2935d04 --- /dev/null +++ b/back-end/test/feedback.test.js @@ -0,0 +1,83 @@ +process.env.NODE_ENV = "test"; + +const chai = require("chai"); +const chaiHttp = require("chai-http"); +chai.use(chaiHttp); +const expect = chai.expect; +const should = chai.should(); +const server = require("../app"); + +describe("Feedback Routes", () => { + const formData = { + user: "blxyaaa", + timestamp: new Date(), + category: "test_category", + feedback: "Test feedback content", + }; + + describe("POST /feedback/newfeedback", () => { + let createdFeedbackId; + + it("should create a new feedback entry", (done) => { + chai + .request(server) + .post("/feedback/newfeedback") + .send(formData) + .end((err, res) => { + if (err) { + console.error("Error in POST /feedback/newfeedback:", err); + return done(err); + } + + expect(res).to.have.status(200); + expect(res.body).to.have.property("success").to.equal(true); + expect(res.body).to.have.property("message").to.equal("Feedback saved successfully."); + expect(res.body).to.have.property("feedback"); + + // Store the created feedback ID for cleanup + createdFeedbackId = res.body.feedback._id; + + done(); + }); + }); + + // Cleanup after the test + after((done) => { + chai + .request(server) + .delete(`/feedback/${createdFeedbackId}`) + .end((deleteErr, deleteRes) => { + if (deleteErr) { + console.error("Error in DELETE /feedback/:id", deleteErr); + return done(deleteErr); + } + + expect(deleteRes).to.have.status(200); + expect(deleteRes.body).to.have.property("success").to.equal(true); + expect(deleteRes.body).to.have.property("message").to.equal("Feedback deleted successfully."); + expect(deleteRes.body).to.have.property("feedback"); + + done(); + }); + }); + }); + }); + + describe("GET /feedback", () => { + it("should get all feedback entries", (done) => { + chai + .request(server) + .get("/feedback/allfeedback") + .end((err, res) => { + if (err) { + console.error("Error in GET /feedback:", err); + } + expect(res).to.have.status(200); + expect(res.body).to.have.property("success").to.equal(true); + expect(res.body).to.have.property("message").to.equal("Feedback retrieved successfully."); + expect(res.body).to.have.property("entries"); + done(); + }); + }); + }); + diff --git a/back-end/test/register.test.js b/back-end/test/register.test.js deleted file mode 100644 index 721ff55..0000000 --- a/back-end/test/register.test.js +++ /dev/null @@ -1,47 +0,0 @@ -process.env.NODE_ENV = "test" -const chai = require("chai") -const chaiHttp = require("chai-http") -chai.use(chaiHttp) -const expect = chai.expect -const should = chai.should() - -const app = require("../app") - -// a group of tests related to the /auth/signup route -describe("User Registration", () => { - /** - * Test the POST /auth/signup route - */ - const validFormData = { username: "new_user", password: "new_password" }; - const invalidFormData = { username: "", password: "password" }; - - describe("POST /auth/signup with valid data", () => { - it("should return a 200 HTTP response code", (done) => { - chai - .request(app) - .post("/auth/signup") - .type("form") - .send(validFormData) - .end((err, res) => { - expect(res).to.have.status(200); - done(); - }); - }); - - }); - - describe("POST /auth/signup with invalid data", () => { - it("should return a 401 HTTP response code", (done) => { - chai - .request(app) - .post("/auth/signup") - .type("form") - .send(invalidFormData) - .end((err, res) => { - expect(res).to.have.status(401); - done(); - }); - }); - - }); - }); \ No newline at end of file