From b4b9c99e05ff28610ae38e22020d483013bf0084 Mon Sep 17 00:00:00 2001 From: alex91-html Date: Wed, 4 Jun 2025 15:47:00 +0200 Subject: [PATCH 01/30] installed dependencies --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index bf25bb6..44cce74 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,9 @@ "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", "cors": "^2.8.5", + "dotenv": "^16.5.0", "express": "^4.17.3", - "nodemon": "^3.0.1" + "express-list-endpoints": "^7.1.1", + "nodemon": "^3.1.10" } } From dd0fcb9d2a9048d52aee61701525858386dd8efa Mon Sep 17 00:00:00 2001 From: alex91-html Date: Wed, 4 Jun 2025 16:21:25 +0200 Subject: [PATCH 02/30] getting --- server.js | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/server.js b/server.js index f47771b..8496d03 100644 --- a/server.js +++ b/server.js @@ -1,19 +1,42 @@ import cors from "cors" import express from "express" +// import dotenv from "dotenv" +import Data from "./data.json" // Defines the port the app will run on. Defaults to 8080, but can be overridden // when starting the server. Example command to overwrite PORT env variable value: // PORT=9000 npm start -const port = process.env.PORT || 8080 +const port = process.env.PORT || 8080 // right now its the locahost port const app = express() // Add middlewares to enable cors and json body parsing app.use(cors()) app.use(express.json()) -// Start defining your routes here + +// END POINTS +// Start defining your routes here app.get("/", (req, res) => { - res.send("Hello Technigo!") + res.send("Hello Technigo! hej hej hej!") +}) + +// Endpoint to get all data +app.get("/thoughts", (req, res) => { + res.json(Data) +}); + + +// endpoint to get one thought by id +app.get("/thoughts/:id", (req, res) => { + console.log("Requested id:", req.params.id, "Type:", typeof req.params.id) + console.log("All IDs in Data:", Data.map(t => t.id)) + const id = Number(req.params.id) + const thought = Data.find(thought => thought.id === id) + if (thought) { + res.json(thought) + } else { + res.status(404).send({ error: "I'm sorry the thought was not found" }) + } }) // Start the server From cf516686a1792b0748560776c25fe968d922ac8b Mon Sep 17 00:00:00 2001 From: alex91-html Date: Wed, 4 Jun 2025 16:22:52 +0200 Subject: [PATCH 03/30] getting data by id problem solved --- server.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/server.js b/server.js index 8496d03..1a16fe7 100644 --- a/server.js +++ b/server.js @@ -28,10 +28,7 @@ app.get("/thoughts", (req, res) => { // endpoint to get one thought by id app.get("/thoughts/:id", (req, res) => { - console.log("Requested id:", req.params.id, "Type:", typeof req.params.id) - console.log("All IDs in Data:", Data.map(t => t.id)) - const id = Number(req.params.id) - const thought = Data.find(thought => thought.id === id) + const thought = Data.find(thought => thought._id === req.params.id) if (thought) { res.json(thought) } else { From 412a63bf6bc7e32f6f1120fafd60acb9381b944a Mon Sep 17 00:00:00 2001 From: alex91-html Date: Wed, 4 Jun 2025 16:34:49 +0200 Subject: [PATCH 04/30] trying to fix crash --- server.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/server.js b/server.js index 1a16fe7..936fda0 100644 --- a/server.js +++ b/server.js @@ -36,6 +36,17 @@ app.get("/thoughts/:id", (req, res) => { } }) +//TODO: endpoint to get thoughts by hearts +app.get("/thoughts/hearts/:hearts", (req, res) => { + const hearts = req.params.hearts + if (!hearts) { + return res.status(400).send({ error: "Please provide a number of hearts" }) + } + + const filteredThoughts = Data.filter(thought => thought.hearts === Number(hearts)) + res.json(filteredThoughts) +}) + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) From b01328dc2bd744ef3f652e3b7b594b11f436bb80 Mon Sep 17 00:00:00 2001 From: alex91-html Date: Wed, 4 Jun 2025 16:35:32 +0200 Subject: [PATCH 05/30] trying to fix crash --- package.json | 2 +- server.js | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 44cce74..9b28baf 100644 --- a/package.json +++ b/package.json @@ -18,4 +18,4 @@ "express-list-endpoints": "^7.1.1", "nodemon": "^3.1.10" } -} +} \ No newline at end of file diff --git a/server.js b/server.js index 936fda0..f2421a5 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,6 @@ import cors from "cors" import express from "express" +import listEndpoints from "express-list-endpoints" // import dotenv from "dotenv" import Data from "./data.json" @@ -17,9 +18,11 @@ app.use(express.json()) // END POINTS // Start defining your routes here app.get("/", (req, res) => { - res.send("Hello Technigo! hej hej hej!") + res.json({ + message: "Welcome to the Thoughts API!", + endpoints: listEndpoints(app) + }) }) - // Endpoint to get all data app.get("/thoughts", (req, res) => { res.json(Data) @@ -36,14 +39,14 @@ app.get("/thoughts/:id", (req, res) => { } }) -//TODO: endpoint to get thoughts by hearts -app.get("/thoughts/hearts/:hearts", (req, res) => { - const hearts = req.params.hearts - if (!hearts) { - return res.status(400).send({ error: "Please provide a number of hearts" }) +//endpoint to get thoughts by certain number of hearts or more +app.get("/thoughts/hearts/:minHearts", (req, res) => { + const minHearts = Number(req.params.minHearts) + if (isNaN(minHearts)) { + return res.status(400).send({ error: "Please provide a valid number of hearts" }) } - const filteredThoughts = Data.filter(thought => thought.hearts === Number(hearts)) + const filteredThoughts = Data.filter(thought => thought.hearts >= minHearts) res.json(filteredThoughts) }) From 218ed2dd29812c996249c70fa86df498d253c4eb Mon Sep 17 00:00:00 2001 From: alex91-html Date: Wed, 4 Jun 2025 16:41:12 +0200 Subject: [PATCH 06/30] added to do md --- todo.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 todo.md diff --git a/todo.md b/todo.md new file mode 100644 index 0000000..e69de29 From 1de4fa543a3310d68dce1be6c7fa7e6490eaa0ac Mon Sep 17 00:00:00 2001 From: alex91-html Date: Fri, 6 Jun 2025 21:12:15 +0200 Subject: [PATCH 07/30] intalled mongoose --- data.json | 10 +++++----- package.json | 3 ++- server.js | 3 +++ todo.md | 3 +++ 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/data.json b/data.json index a2c844f..62b0fd7 100644 --- a/data.json +++ b/data.json @@ -1,5 +1,5 @@ [ - { + { "_id": "682bab8c12155b00101732ce", "message": "Berlin baby", "hearts": 37, @@ -7,7 +7,7 @@ "__v": 0 }, { - "_id": "682e53cc4fddf50010bbe739", + "_id": "682e53cc4fddf50010bbe739", "message": "My family!", "hearts": 0, "createdAt": "2025-05-22T22:29:32.232Z", @@ -25,7 +25,7 @@ "message": "Newly washed bedlinen, kids that sleeps through the night.. FINGERS CROSSED ๐Ÿคž๐Ÿผ\n", "hearts": 6, "createdAt": "2025-05-21T21:42:23.862Z", - "__v": 0 + "__v": 0 }, { "_id": "682e45804fddf50010bbe736", @@ -53,7 +53,7 @@ "message": "A god joke: \nWhy did the scarecrow win an award?\nBecause he was outstanding in his field!", "hearts": 12, "createdAt": "2025-05-20T20:54:51.082Z", - "__v": 0 + "__v": 0 }, { "_id": "682cebbe17487d0010a298b5", @@ -74,7 +74,7 @@ "message": "Summer is coming...", "hearts": 2, "createdAt": "2025-05-20T15:03:22.379Z", - "__v": 0 + "__v": 0 }, { "_id": "682c706c951f7a0017130024", diff --git a/package.json b/package.json index 9b28baf..9c9d350 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "dotenv": "^16.5.0", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", + "mongoose": "^8.15.1", "nodemon": "^3.1.10" } -} \ No newline at end of file +} diff --git a/server.js b/server.js index f2421a5..a1d4da3 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,7 @@ import cors from "cors" import express from "express" import listEndpoints from "express-list-endpoints" +import mongoose from "mongoose" // import dotenv from "dotenv" import Data from "./data.json" @@ -54,3 +55,5 @@ app.get("/thoughts/hearts/:minHearts", (req, res) => { app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) }) + + diff --git a/todo.md b/todo.md index e69de29..e0e21f0 100644 --- a/todo.md +++ b/todo.md @@ -0,0 +1,3 @@ +- [x] start week 19 assignmetn +- [x] fix app crash +- [x] make week 18 assignment more funky \ No newline at end of file From f91e12638162952d65d448078e0f0afb403acec7 Mon Sep 17 00:00:00 2001 From: alex91-html Date: Fri, 6 Jun 2025 21:23:08 +0200 Subject: [PATCH 08/30] mongo URL' --- server.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/server.js b/server.js index a1d4da3..6a1c430 100644 --- a/server.js +++ b/server.js @@ -5,6 +5,13 @@ import mongoose from "mongoose" // import dotenv from "dotenv" import Data from "./data.json" + + +// the mongo URL to connect to the database +const mongoUrl = process.env.MONGO_URL || "mongodb://localhost:27017/thoughts" + + + // Defines the port the app will run on. Defaults to 8080, but can be overridden // when starting the server. Example command to overwrite PORT env variable value: // PORT=9000 npm start From f72a39fe62cd9f88b7e3f123ca5590e068e5512a Mon Sep 17 00:00:00 2001 From: alex91-html Date: Fri, 6 Jun 2025 21:24:12 +0200 Subject: [PATCH 09/30] mongoose.connect(mongoUrl) --- server.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/server.js b/server.js index 6a1c430..d2459e4 100644 --- a/server.js +++ b/server.js @@ -1,16 +1,15 @@ import cors from "cors" import express from "express" import listEndpoints from "express-list-endpoints" -import mongoose from "mongoose" +import mongoose, { mongo } from "mongoose" // import dotenv from "dotenv" import Data from "./data.json" // the mongo URL to connect to the database -const mongoUrl = process.env.MONGO_URL || "mongodb://localhost:27017/thoughts" - - +const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/thoughts" +mongoose.connect(mongoUrl) // Defines the port the app will run on. Defaults to 8080, but can be overridden // when starting the server. Example command to overwrite PORT env variable value: From c1d33deecf2ed9bb70e375e470b61fe73fee92e4 Mon Sep 17 00:00:00 2001 From: alex91-html Date: Fri, 6 Jun 2025 21:28:40 +0200 Subject: [PATCH 10/30] Schema added --- server.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/server.js b/server.js index d2459e4..f4edd75 100644 --- a/server.js +++ b/server.js @@ -21,6 +21,15 @@ const app = express() app.use(cors()) app.use(express.json()) +const thoughtSchema = new mongoose.Schema({ + _id: String, + message: String, + hearts: Number, + createdAt: { + type: Date, + default: Date.now + } +}) // END POINTS // Start defining your routes here From 8dcfc30779e5e9edfe8166af67e9e17811ccfce8 Mon Sep 17 00:00:00 2001 From: alex91-html Date: Fri, 6 Jun 2025 21:31:29 +0200 Subject: [PATCH 11/30] added model --- server.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server.js b/server.js index f4edd75..69743d6 100644 --- a/server.js +++ b/server.js @@ -31,6 +31,8 @@ const thoughtSchema = new mongoose.Schema({ } }) +const Thought = mongoose.model("Thought", thoughtSchema) + // END POINTS // Start defining your routes here app.get("/", (req, res) => { From 222d15d111fce1e5546faf7f14b7967a59155d46 Mon Sep 17 00:00:00 2001 From: alex91-html Date: Fri, 6 Jun 2025 21:52:49 +0200 Subject: [PATCH 12/30] updating mongoose --- server.js | 51 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/server.js b/server.js index 69743d6..f03ee67 100644 --- a/server.js +++ b/server.js @@ -24,7 +24,10 @@ app.use(express.json()) const thoughtSchema = new mongoose.Schema({ _id: String, message: String, - hearts: Number, + hearts: { + type: Number, + default: 0, + }, createdAt: { type: Date, default: Date.now @@ -33,6 +36,19 @@ const thoughtSchema = new mongoose.Schema({ const Thought = mongoose.model("Thought", thoughtSchema) + +if (process.env.RESET_DB) { + const seedData = async () => { + await Thought.deleteMany({}) // Clear the collection before seeding + thoughtData.forEach(thought => { + new Thought(thought).save() + }) + } + seedData() +} + + + // END POINTS // Start defining your routes here app.get("/", (req, res) => { @@ -41,30 +57,39 @@ app.get("/", (req, res) => { endpoints: listEndpoints(app) }) }) + // Endpoint to get all data -app.get("/thoughts", (req, res) => { - res.json(Data) +app.get("/thoughts", async (req, res) => { + try { + const thoughts = await Thought.find().sort({ createdAt: -1 }).limit(20); + res.json(thoughts); + } catch (err) { + res.status(500).json({ error: "Failed to fetch thoughts" }); + } }); - // endpoint to get one thought by id -app.get("/thoughts/:id", (req, res) => { - const thought = Data.find(thought => thought._id === req.params.id) - if (thought) { - res.json(thought) - } else { - res.status(404).send({ error: "I'm sorry the thought was not found" }) +app.get("/thoughts/:id", async (req, res) => { + try { + const thought = await Thought.findById(req.params.id); + if (thought) { + res.json(thought); + } else { + res.status(404).json({ error: "Thought not found" }); + } + } catch { + res.status(400).json({ error: "Invalid ID format" }); } -}) +}); //endpoint to get thoughts by certain number of hearts or more -app.get("/thoughts/hearts/:minHearts", (req, res) => { +app.get("/thoughts/hearts/:minHearts", async (req, res) => { const minHearts = Number(req.params.minHearts) if (isNaN(minHearts)) { return res.status(400).send({ error: "Please provide a valid number of hearts" }) } - const filteredThoughts = Data.filter(thought => thought.hearts >= minHearts) + const filteredThoughts = await Thought.find({ hearts: { $gte: minHearts } }) res.json(filteredThoughts) }) From 9b4509950fc69c4ad34c07c5689775c1e51a62ae Mon Sep 17 00:00:00 2001 From: alex91-html Date: Mon, 9 Jun 2025 15:52:19 +0200 Subject: [PATCH 13/30] deployed --- server.js | 82 +++++++++++++++++++++++++++++++++++++++++++++++++------ todo.md | 4 ++- 2 files changed, 76 insertions(+), 10 deletions(-) diff --git a/server.js b/server.js index f03ee67..245d553 100644 --- a/server.js +++ b/server.js @@ -3,7 +3,9 @@ import express from "express" import listEndpoints from "express-list-endpoints" import mongoose, { mongo } from "mongoose" // import dotenv from "dotenv" -import Data from "./data.json" +// import Data from "./data.json" + + @@ -61,24 +63,24 @@ app.get("/", (req, res) => { // Endpoint to get all data app.get("/thoughts", async (req, res) => { try { - const thoughts = await Thought.find().sort({ createdAt: -1 }).limit(20); + let thoughts = await Thought.find().sort({ createdAt: -1 }).limit(20); res.json(thoughts); - } catch (err) { - res.status(500).json({ error: "Failed to fetch thoughts" }); + } catch (error) { + res.status(404).json({ error: "Failed to fetch thoughts" }); } }); // endpoint to get one thought by id app.get("/thoughts/:id", async (req, res) => { try { - const thought = await Thought.findById(req.params.id); + const thought = await Thought.findById(req.params.id) if (thought) { - res.json(thought); + res.json(thought) } else { - res.status(404).json({ error: "Thought not found" }); + res.status(404).json({ error: "Thought not found" }) } - } catch { - res.status(400).json({ error: "Invalid ID format" }); + } catch (error) { + res.status(400).json({ error: "Invalid ID format" }) } }); @@ -93,6 +95,68 @@ app.get("/thoughts/hearts/:minHearts", async (req, res) => { res.json(filteredThoughts) }) +// Endpoint to create a new thought +app.post("/thoughts", async (req, res) => { + const { message, hearts } = req.body + + if (!message || typeof message !== "string") { + return res.status(400).json({ error: "Message is required and must be a string" }) + } + + if (hearts !== undefined && typeof hearts !== "number") { + return res.status(400).json({ error: "Hearts must be a number" }) + } + + try { + const newThought = await new Thought({ message, hearts }).save() + res.status(201).json(newThought) + } catch (error) { + res.status(500).json({ error: "Failed to create thought" }) + } +}) + +// Endpoint to update a thought +app.put("/thoughts/:id", async (req, res) => { + const { message, hearts } = req.body + + if (message && typeof message !== "string") { + return res.status(400).json({ error: "Message must be a string" }) + } + + if (hearts !== undefined && typeof hearts !== "number") { + return res.status(400).json({ error: "Hearts must be a number" }) + } + + try { + const updatedThought = await Thought.findByIdAndUpdate( + req.params.id, + { message, hearts }, + { new: true, runValidators: true } + ) + if (updatedThought) { + res.json(updatedThought) + } else { + res.status(404).json({ error: "Thought not found" }) + } + } catch (err) { + res.status(400).json({ error: "Invalid ID format" }) + } +}) + +// Endpoint to delete a thought +app.delete("/thoughts/:id", async (req, res) => { + try { + const deletedThought = await Thought.findByIdAndDelete(req.params.id) + if (deletedThought) { + res.json({ message: "Thought deleted successfully" }) + } else { + res.status(404).json({ error: "Thought not found" }) + } + } catch (err) { + res.status(400).json({ error: "Invalid ID format" }) + } +}) + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) diff --git a/todo.md b/todo.md index e0e21f0..32765f5 100644 --- a/todo.md +++ b/todo.md @@ -1,3 +1,5 @@ - [x] start week 19 assignmetn - [x] fix app crash -- [x] make week 18 assignment more funky \ No newline at end of file +- [x] make week 18 assignment more funky +- [x] deploy the backend in render +- [] update the front end \ No newline at end of file From cd5aa31bf938c7bfd161c9680b484a026037315c Mon Sep 17 00:00:00 2001 From: alex91-html Date: Thu, 12 Jun 2025 14:03:38 +0200 Subject: [PATCH 14/30] updated to do list --- todo.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/todo.md b/todo.md index 32765f5..8022b42 100644 --- a/todo.md +++ b/todo.md @@ -2,4 +2,16 @@ - [x] fix app crash - [x] make week 18 assignment more funky - [x] deploy the backend in render -- [] update the front end \ No newline at end of file +- [x] Your API should use Mongoose models to model your data and use these models to fetch data from the database. +- [] Your API should validate user input and return appropriate errors if the input is invalid. +- [x] You should implement error handling for all your routes, with proper response statuses. +- [] Your frontend should be updated with the possibility to Update and Delete a thought. +- [] check the render deployment if it works + +- [] Your API should have routes to register and log in +- [] Your endpoints to Create, Update and Delete should be authenticated +- [] Your frontend should have a registration form which POSTs to the API to create a new user. +- [] Your frontend should have a login form to authenticate the user. +- [] Your passwords in the database should be encrypted with bcrypt. +- [] You should implement error handling. Your API should let the user know if something went wrong. Be as specific as possible to help the user, e.g. by validating the user input when creating a new user, and return "That email address already exists". Include correct status codes. Error messages should also be shown on the frontend. +- [] The validation should ensure unique email addresses and/or usernames, depending on how you'd like to structure your User model. \ No newline at end of file From 33ef28ac66a7ed22f96416f95f91e99cb5849dd8 Mon Sep 17 00:00:00 2001 From: alex91-html Date: Thu, 12 Jun 2025 15:32:57 +0200 Subject: [PATCH 15/30] fixing problem api --- package.json | 1 + todo.md | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 9c9d350..cf868d1 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "dotenv": "^16.5.0", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", + "mongodb": "^6.17.0", "mongoose": "^8.15.1", "nodemon": "^3.1.10" } diff --git a/todo.md b/todo.md index 8022b42..ebd55c2 100644 --- a/todo.md +++ b/todo.md @@ -3,10 +3,20 @@ - [x] make week 18 assignment more funky - [x] deploy the backend in render - [x] Your API should use Mongoose models to model your data and use these models to fetch data from the database. -- [] Your API should validate user input and return appropriate errors if the input is invalid. +- [x] Your API should validate user input and return appropriate errors if the input is invalid. - [x] You should implement error handling for all your routes, with proper response statuses. -- [] Your frontend should be updated with the possibility to Update and Delete a thought. -- [] check the render deployment if it works +- [x] Your frontend should be updated with the possibility to Update and Delete a thought. + + + +- [] why is there no happy thought been shown? + - [x] check the render deployment if it works + - [] check MongoDB +- [] make the update and delete look a bit better + + + + - [] Your API should have routes to register and log in - [] Your endpoints to Create, Update and Delete should be authenticated From 102ddea0d2184731f540bfacb456efe32df1c8b2 Mon Sep 17 00:00:00 2001 From: alex91-html Date: Fri, 13 Jun 2025 17:13:05 +0200 Subject: [PATCH 16/30] trying to debugg --- package.json | 2 +- server.js | 143 +++++++++++++++++++++++++++++++++++++-------------- todo.md | 51 +++++++++++------- 3 files changed, 136 insertions(+), 60 deletions(-) diff --git a/package.json b/package.json index cf868d1..07f4d42 100644 --- a/package.json +++ b/package.json @@ -20,4 +20,4 @@ "mongoose": "^8.15.1", "nodemon": "^3.1.10" } -} +} \ No newline at end of file diff --git a/server.js b/server.js index 245d553..438b26b 100644 --- a/server.js +++ b/server.js @@ -1,16 +1,9 @@ import cors from "cors" import express from "express" import listEndpoints from "express-list-endpoints" -import mongoose, { mongo } from "mongoose" -// import dotenv from "dotenv" -// import Data from "./data.json" +import mongoose from "mongoose" - - - - -// the mongo URL to connect to the database -const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/thoughts" +const mongoUrl = process.env.MONGO_URL || "mongodb://localhost:27017/thoughts" mongoose.connect(mongoUrl) // Defines the port the app will run on. Defaults to 8080, but can be overridden @@ -50,26 +43,41 @@ if (process.env.RESET_DB) { } - // END POINTS // Start defining your routes here app.get("/", (req, res) => { + const endpoints = listEndpoints(app) res.json({ - message: "Welcome to the Thoughts API!", - endpoints: listEndpoints(app) + message: "Welcome to the Happy Thoughts API!", + endpoints: endpoints, }) }) -// Endpoint to get all data -app.get("/thoughts", async (req, res) => { - try { - let thoughts = await Thought.find().sort({ createdAt: -1 }).limit(20); - res.json(thoughts); - } catch (error) { - res.status(404).json({ error: "Failed to fetch thoughts" }); - } +//TODO: somthing is not working here, need to debug +//TODO: add query params to filter by quantity of hearts or date it has been created +// Endpoint to get all data, like all the thoughts + +app.get("/thoughts", (req, res) => { + + const { time, hearts } = req.query; + let filter = {}; + if (time) filter.createdAt = { $gte: new Date(time) }; + if (hearts) filter.hearts = { $gte: Number(hearts) }; + + const thoughts = await Thought.find(filter).sort({ createdAt: -1 }).limit(20); + res.json(thoughts); }); +// try { +// let thoughts = await Thought.find().sort({ createdAt: -1 }).limit(20); +// console.log("Fetched thoughts:", thoughts); // Debug the query result +// res.json(thoughts); +// } catch (error) { +// console.error("Error fetching thoughts:", error); // Log the error details +// res.status(500).json({ error: "Failed to fetch thoughts", details: error.message }); +// } + +//TODO: somthing is not working here, need to debug // endpoint to get one thought by id app.get("/thoughts/:id", async (req, res) => { try { @@ -84,6 +92,7 @@ app.get("/thoughts/:id", async (req, res) => { } }); +//TODO: maybe i can delete this endpoint? //endpoint to get thoughts by certain number of hearts or more app.get("/thoughts/hearts/:minHearts", async (req, res) => { const minHearts = Number(req.params.minHearts) @@ -95,6 +104,7 @@ app.get("/thoughts/hearts/:minHearts", async (req, res) => { res.json(filteredThoughts) }) +//TODO: check if this endpoint works // Endpoint to create a new thought app.post("/thoughts", async (req, res) => { const { message, hearts } = req.body @@ -117,45 +127,98 @@ app.post("/thoughts", async (req, res) => { // Endpoint to update a thought app.put("/thoughts/:id", async (req, res) => { - const { message, hearts } = req.body - - if (message && typeof message !== "string") { - return res.status(400).json({ error: "Message must be a string" }) - } - - if (hearts !== undefined && typeof hearts !== "number") { - return res.status(400).json({ error: "Hearts must be a number" }) - } + const { message, hearts } = req.body; try { const updatedThought = await Thought.findByIdAndUpdate( req.params.id, { message, hearts }, { new: true, runValidators: true } - ) + ); if (updatedThought) { - res.json(updatedThought) + res.json(updatedThought); } else { - res.status(404).json({ error: "Thought not found" }) + res.status(404).json({ error: "Thought not found" }); } - } catch (err) { - res.status(400).json({ error: "Invalid ID format" }) + } catch (error) { + res.status(400).json({ error: "Invalid ID format" }); } }) // Endpoint to delete a thought app.delete("/thoughts/:id", async (req, res) => { try { - const deletedThought = await Thought.findByIdAndDelete(req.params.id) + const deletedThought = await Thought.findByIdAndDelete(req.params.id); if (deletedThought) { - res.json({ message: "Thought deleted successfully" }) + res.json({ message: "Thought deleted successfully" }); } else { - res.status(404).json({ error: "Thought not found" }) + res.status(404).json({ error: "Thought not found" }); } - } catch (err) { - res.status(400).json({ error: "Invalid ID format" }) + } catch (error) { + res.status(400).json({ error: "Invalid ID format" }); } -}) +}); + +// Endpoint to like a thought +app.post("/thoughts/:id/like", async (req, res) => { + try { + const thought = await Thought.findByIdAndUpdate( + req.params.id, + { $inc: { hearts: 1 } }, + { new: true } + ); + if (thought) { + res.json(thought); + } else { + res.status(404).json({ error: "Thought not found" }); + } + } catch (error) { + res.status(400).json({ error: "Invalid ID format" }); + } +}); + +// Endpoint to update a thought by ID with prompt +app.put("/thoughts/:id/prompt", async (req, res) => { + const { id } = req.params; + + const newMessage = prompt("Enter the updated message:"); + if (!newMessage) return; + + try { + const response = await fetch(`${API_URL}/thoughts/${id}`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ message: newMessage }), + }); + + if (response.ok) { + const updatedThought = await response.json(); + setThoughts(thoughts.map((thought) => + thought._id === id ? updatedThought : thought + )); + } else { + console.error("Failed to update thought:", response.status, response.statusText); + } + } catch (error) { + console.error("Error updating thought:", error); + } +}); + +const deleteThought = async (id) => { + try { + const response = await fetch(`${API_URL}/thoughts/${id}`, { + method: "DELETE", + }); + + if (response.ok) { + setThoughts(thoughts.filter((thought) => thought._id !== id)); + } else { + console.error("Failed to delete thought:", response.status, response.statusText); + } + } catch (error) { + console.error("Error deleting thought:", error); + } +}; // Start the server app.listen(port, () => { diff --git a/todo.md b/todo.md index ebd55c2..8f7c47a 100644 --- a/todo.md +++ b/todo.md @@ -1,27 +1,40 @@ -- [x] start week 19 assignmetn -- [x] fix app crash -- [x] make week 18 assignment more funky -- [x] deploy the backend in render -- [x] Your API should use Mongoose models to model your data and use these models to fetch data from the database. -- [x] Your API should validate user input and return appropriate errors if the input is invalid. -- [x] You should implement error handling for all your routes, with proper response statuses. -- [x] Your frontend should be updated with the possibility to Update and Delete a thought. +- [x] week 18 - seting up with local data, + - [x] video tue 27 + - [x] video wend 28 > maybe something is wrong here, idk + **NOTES**: maybe I have to fix the endpoints? Have to look at week 19 to check what are the mistaked with the diployed data, i think the problem is there. + - **13.06 - 16:08** it is fetching data from the deployed data, but seems i can't add likes, remove or edit anythinh + +- [] week 19 - [place-things-into-the-database] + - [x] deploy the backend in render + - [x] Your API should use Mongoose models to model your data and use these models to fetch data from the database. + - [x] Your API should validate user input and return appropriate errors if the input is invalid. + - [x] You should implement error handling for all your routes, with proper response statuses. + - [] Your frontend should be updated with the possibility to Update and Delete a thought. + - [] problem: -- [] why is there no happy thought been shown? - - [x] check the render deployment if it works - - [] check MongoDB -- [] make the update and delete look a bit better -- [] Your API should have routes to register and log in -- [] Your endpoints to Create, Update and Delete should be authenticated -- [] Your frontend should have a registration form which POSTs to the API to create a new user. -- [] Your frontend should have a login form to authenticate the user. -- [] Your passwords in the database should be encrypted with bcrypt. -- [] You should implement error handling. Your API should let the user know if something went wrong. Be as specific as possible to help the user, e.g. by validating the user input when creating a new user, and return "That email address already exists". Include correct status codes. Error messages should also be shown on the frontend. -- [] The validation should ensure unique email addresses and/or usernames, depending on how you'd like to structure your User model. \ No newline at end of file + +- [x] why is there no happy thought been shown? + - [x] check the render deployment if it works + - [x] check MongoDB + - [x] render nad mongo are connected + - [x] test the frontend connection to render with postman + - [] try to fix error + - [] look throught all classes again and try to fix problem with my code + +- [] week 20 + - [] Your API should have routes to register and log in + - [] Your endpoints to Create, Update and Delete should be authenticated + - [] Your frontend should have a registration form which POSTs to the API to create a new user. + - [] Your frontend should have a login form to authenticate the user. + - [] Your passwords in the database should be encrypted with bcrypt. + - [] You should implement error handling. Your API should let the user know if something went wrong. Be as specific as possible to help the user, e.g. by validating the user input when creating a new user, and return "That email address already exists". Include correct status codes. Error messages should also be shown on the frontend. + - [] The validation should ensure unique email addresses and/or usernames, depending on how you'd like to structure your User model. + + \ No newline at end of file From 0e5ee01c70a94f084328584ddf7e4abc0421a70a Mon Sep 17 00:00:00 2001 From: alex91-html Date: Mon, 16 Jun 2025 15:55:03 +0200 Subject: [PATCH 17/30] fixed bugs but liking and posting still not working --- data.json | 121 ------------------------------------------------------ server.js | 102 ++++++++++++++++++++++++--------------------- todo.md | 52 +++++++++++++++-------- 3 files changed, 91 insertions(+), 184 deletions(-) delete mode 100644 data.json diff --git a/data.json b/data.json deleted file mode 100644 index 62b0fd7..0000000 --- a/data.json +++ /dev/null @@ -1,121 +0,0 @@ -[ - { - "_id": "682bab8c12155b00101732ce", - "message": "Berlin baby", - "hearts": 37, - "createdAt": "2025-05-19T22:07:08.999Z", - "__v": 0 - }, - { - "_id": "682e53cc4fddf50010bbe739", - "message": "My family!", - "hearts": 0, - "createdAt": "2025-05-22T22:29:32.232Z", - "__v": 0 - }, - { - "_id": "682e4f844fddf50010bbe738", - "message": "The smell of coffee in the morning....", - "hearts": 23, - "createdAt": "2025-05-22T22:11:16.075Z", - "__v": 0 - }, - { - "_id": "682e48bf4fddf50010bbe737", - "message": "Newly washed bedlinen, kids that sleeps through the night.. FINGERS CROSSED ๐Ÿคž๐Ÿผ\n", - "hearts": 6, - "createdAt": "2025-05-21T21:42:23.862Z", - "__v": 0 - }, - { - "_id": "682e45804fddf50010bbe736", - "message": "I am happy that I feel healthy and have energy again", - "hearts": 13, - "createdAt": "2025-05-21T21:28:32.196Z", - "__v": 0 - }, - { - "_id": "682e23fecf615800105107aa", - "message": "cold beer", - "hearts": 2, - "createdAt": "2025-05-21T19:05:34.113Z", - "__v": 0 - }, - { - "_id": "682e22aecf615800105107a9", - "message": "My friend is visiting this weekend! <3", - "hearts": 6, - "createdAt": "2025-05-21T18:59:58.121Z", - "__v": 0 - }, - { - "_id": "682cec1b17487d0010a298b6", - "message": "A god joke: \nWhy did the scarecrow win an award?\nBecause he was outstanding in his field!", - "hearts": 12, - "createdAt": "2025-05-20T20:54:51.082Z", - "__v": 0 - }, - { - "_id": "682cebbe17487d0010a298b5", - "message": "Tacos and tequila๐ŸŒฎ๐Ÿน", - "hearts": 2, - "createdAt": "2025-05-19T20:53:18.899Z", - "__v": 0 - }, - { - "_id": "682ceb5617487d0010a298b4", - "message": "Netflix and late night ice-cream๐Ÿฆ", - "hearts": 1, - "createdAt": "2025-05-18T20:51:34.494Z", - "__v": 0 - }, - { - "_id": "682c99ba3bff2d0010f5d44e", - "message": "Summer is coming...", - "hearts": 2, - "createdAt": "2025-05-20T15:03:22.379Z", - "__v": 0 - }, - { - "_id": "682c706c951f7a0017130024", - "message": "Exercise? I thought you said extra fries! ๐ŸŸ๐Ÿ˜‚", - "hearts": 14, - "createdAt": "2025-05-20T12:07:08.185Z", - "__v": 0 - }, - { - "_id": "682c6fe1951f7a0017130023", - "message": "Iโ€™m on a seafood diet. I see food, and I eat it.", - "hearts": 4, - "createdAt": "2025-05-20T12:04:49.978Z", - "__v": 0 - }, - { - "_id": "682c6f0e951f7a0017130022", - "message": "Cute monkeys๐Ÿ’", - "hearts": 2, - "createdAt": "2025-05-20T12:01:18.308Z", - "__v": 0 - }, - { - "_id": "682c6e65951f7a0017130021", - "message": "The weather is nice!", - "hearts": 0, - "createdAt": "2025-05-20T11:58:29.662Z", - "__v": 0 - }, - { - "_id": "682bfdb4270ca300105af221", - "message": "good vibes and good things", - "hearts": 3, - "createdAt": "2025-05-20T03:57:40.322Z", - "__v": 0 - }, - { - "_id": "682bab8c12155b00101732ce", - "message": "Berlin baby", - "hearts": 37, - "createdAt": "2025-05-19T22:07:08.999Z", - "__v": 0 - } -] \ No newline at end of file diff --git a/server.js b/server.js index 438b26b..e395b5f 100644 --- a/server.js +++ b/server.js @@ -2,8 +2,9 @@ import cors from "cors" import express from "express" import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" +import dotenv from "dotenv" -const mongoUrl = process.env.MONGO_URL || "mongodb://localhost:27017/thoughts" +const mongoUrl = process.env.MONGO_URL || "mongodb://localhost:27017/happy-thoughts-api" mongoose.connect(mongoUrl) // Defines the port the app will run on. Defaults to 8080, but can be overridden @@ -15,8 +16,9 @@ const app = express() // Add middlewares to enable cors and json body parsing app.use(cors()) app.use(express.json()) +dotenv.config() -const thoughtSchema = new mongoose.Schema({ +const thoughtSchema = new mongoose.Schema({ // Schema for the thoughts _id: String, message: String, hearts: { @@ -29,9 +31,7 @@ const thoughtSchema = new mongoose.Schema({ } }) -const Thought = mongoose.model("Thought", thoughtSchema) - - +const Thought = mongoose.model("Thought", thoughtSchema) // name and schema for the model if (process.env.RESET_DB) { const seedData = async () => { await Thought.deleteMany({}) // Clear the collection before seeding @@ -57,8 +57,8 @@ app.get("/", (req, res) => { //TODO: add query params to filter by quantity of hearts or date it has been created // Endpoint to get all data, like all the thoughts -app.get("/thoughts", (req, res) => { - +app.get("/thoughts", async (req, res) => { + console.log(" GET / thoughts endpoint hit!!! PARTY TIME!!!") const { time, hearts } = req.query; let filter = {}; if (time) filter.createdAt = { $gte: new Date(time) }; @@ -68,28 +68,37 @@ app.get("/thoughts", (req, res) => { res.json(thoughts); }); -// try { -// let thoughts = await Thought.find().sort({ createdAt: -1 }).limit(20); -// console.log("Fetched thoughts:", thoughts); // Debug the query result -// res.json(thoughts); -// } catch (error) { -// console.error("Error fetching thoughts:", error); // Log the error details -// res.status(500).json({ error: "Failed to fetch thoughts", details: error.message }); -// } //TODO: somthing is not working here, need to debug // endpoint to get one thought by id + app.get("/thoughts/:id", async (req, res) => { + const { id } = req.params; + try { - const thought = await Thought.findById(req.params.id) - if (thought) { - res.json(thought) - } else { - res.status(404).json({ error: "Thought not found" }) + const thought = await Thought.findById(req.params.id); // Query the database + + if (!thought) { + res.status(404).json({ + success: false, + response: null, + message: "Thought not found" + }); // Handle not found } + res.status(200).json({ + success: true, + response: thought, + message: "Thought fetched successfully" + }); // Return the thought } catch (error) { - res.status(400).json({ error: "Invalid ID format" }) + res.status(500).json({ + success: false, + response: null, + message: "Error fetching thought", + error: error.message + }); // Handle errors } + }); //TODO: maybe i can delete this endpoint? @@ -159,6 +168,7 @@ app.delete("/thoughts/:id", async (req, res) => { } }); +// TODO: check if this endpoint works, // Endpoint to like a thought app.post("/thoughts/:id/like", async (req, res) => { try { @@ -178,31 +188,31 @@ app.post("/thoughts/:id/like", async (req, res) => { }); // Endpoint to update a thought by ID with prompt -app.put("/thoughts/:id/prompt", async (req, res) => { - const { id } = req.params; - - const newMessage = prompt("Enter the updated message:"); - if (!newMessage) return; - - try { - const response = await fetch(`${API_URL}/thoughts/${id}`, { - method: "PUT", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ message: newMessage }), - }); - - if (response.ok) { - const updatedThought = await response.json(); - setThoughts(thoughts.map((thought) => - thought._id === id ? updatedThought : thought - )); - } else { - console.error("Failed to update thought:", response.status, response.statusText); - } - } catch (error) { - console.error("Error updating thought:", error); - } -}); +// app.put("/thoughts/:id/prompt", async (req, res) => { +// const { id } = req.params; + +// const newMessage = prompt("Enter the updated message:"); +// if (!newMessage) return; + +// try { +// const response = await fetch(`${API_URL}/thoughts/${id}`, { +// method: "PUT", +// headers: { "Content-Type": "application/json" }, +// body: JSON.stringify({ message: newMessage }), +// }); + +// if (response.ok) { +// const updatedThought = await response.json(); +// setThoughts(thoughts.map((thought) => +// thought._id === id ? updatedThought : thought +// )); +// } else { +// console.error("Failed to update thought:", response.status, response.statusText); +// } +// } catch (error) { +// console.error("Error updating thought:", error); +// } +// }); const deleteThought = async (id) => { try { diff --git a/todo.md b/todo.md index 8f7c47a..d90f4b8 100644 --- a/todo.md +++ b/todo.md @@ -1,34 +1,45 @@ - [x] week 18 - seting up with local data, - [x] video tue 27 - [x] video wend 28 > maybe something is wrong here, idk +- [x] week 19 - [place-things-into-the-database] - **NOTES**: maybe I have to fix the endpoints? Have to look at week 19 to check what are the mistaked with the diployed data, i think the problem is there. - - **13.06 - 16:08** it is fetching data from the deployed data, but seems i can't add likes, remove or edit anythinh -- [] week 19 - [place-things-into-the-database] - [x] deploy the backend in render - [x] Your API should use Mongoose models to model your data and use these models to fetch data from the database. - [x] Your API should validate user input and return appropriate errors if the input is invalid. - [x] You should implement error handling for all your routes, with proper response statuses. - - [] Your frontend should be updated with the possibility to Update and Delete a thought. - - [] problem: - - - - - - - - -- [x] why is there no happy thought been shown? + - [x] video of tue + - [x] i have commented out the back end, data seems to be fetch from the front, fix that! and fix the back end, i feel i'm almost there. + - [x] Ensure the frontend is sending the correct requests to the backend: + - Check the request URLs and payloads. + - Add logs to the frontend functions to debug the requests. + - [x] video of wen jun 4th + - [x] why is there no happy thought been shown? - [x] check the render deployment if it works - [x] check MongoDB - [x] render nad mongo are connected - [x] test the frontend connection to render with postman - - [] try to fix error - - [] look throught all classes again and try to fix problem with my code + - [x] try to fix error + - [x] look throught all classes again and try to fix problem with my code + - [x] seems not possible to add a thought, edit or remove a thuoght not even to like + - [x] Your frontend should be updated with the possibility to Update and Delete a thought. + + + + - [] week 20 + - [] use postman to test the endpoint, results: + - ADD THOUGHT POST /thoughts - **!!!FAILD!!!** + "error": "Failed to create thought" - 500 Internal Server Error + - LIKE THOUGHT - error 404 not found **!!!FAILD!!!** + - EDIT A THOUGHT **!!WORKS!!** + - DELETE A THOUGHT **!!WORKS!!** + - [] make the edit text frame look nicer + - [x] add a btn for edit, + - [x] add a btn for delete + - [] make the text frame in edit expandable + - [] place the edit, and delete in better places - [] Your API should have routes to register and log in - [] Your endpoints to Create, Update and Delete should be authenticated - [] Your frontend should have a registration form which POSTs to the API to create a new user. @@ -36,5 +47,12 @@ - [] Your passwords in the database should be encrypted with bcrypt. - [] You should implement error handling. Your API should let the user know if something went wrong. Be as specific as possible to help the user, e.g. by validating the user input when creating a new user, and return "That email address already exists". Include correct status codes. Error messages should also be shown on the frontend. - [] The validation should ensure unique email addresses and/or usernames, depending on how you'd like to structure your User model. + - [] should i use react router? + - [] clean up components in frontend - \ No newline at end of file + + + + **NOTES**: maybe I have to fix the endpoints? Have to look at week 19 to check what are the mistaked with the diployed data, i think the problem is there. + - **13.06 - 16:08** it is fetching data from the deployed data, but seems i can't add likes, remove or edit anything + - **video of we** got at min 00:34 \ No newline at end of file From c5a218ec2df9de79c5737233854e4ec79521e9f2 Mon Sep 17 00:00:00 2001 From: alex91-html Date: Mon, 16 Jun 2025 17:12:29 +0200 Subject: [PATCH 18/30] fixes posting new thought, have to fix edit, save and cancel and liking --- server.js | 251 ++++++++++-------------------------------------------- todo.md | 22 +++-- 2 files changed, 58 insertions(+), 215 deletions(-) diff --git a/server.js b/server.js index e395b5f..0ed39a4 100644 --- a/server.js +++ b/server.js @@ -1,238 +1,77 @@ -import cors from "cors" -import express from "express" -import listEndpoints from "express-list-endpoints" -import mongoose from "mongoose" -import dotenv from "dotenv" +import cors from "cors"; +import express from "express"; +import mongoose from "mongoose"; +import dotenv from "dotenv"; -const mongoUrl = process.env.MONGO_URL || "mongodb://localhost:27017/happy-thoughts-api" -mongoose.connect(mongoUrl) +dotenv.config(); -// Defines the port the app will run on. Defaults to 8080, but can be overridden -// when starting the server. Example command to overwrite PORT env variable value: -// PORT=9000 npm start -const port = process.env.PORT || 8080 // right now its the locahost port -const app = express() +const mongoUrl = process.env.MONGO_URL || "mongodb://localhost:27017/happy-thoughts-api"; +mongoose.connect(mongoUrl); -// Add middlewares to enable cors and json body parsing -app.use(cors()) -app.use(express.json()) -dotenv.config() +mongoose.connection.on("error", (error) => { + console.error("MongoDB connection error:", error); +}); + +mongoose.connection.once("open", () => { + console.log("Connected to MongoDB"); +}); + +const port = process.env.PORT || 8080; +const app = express(); -const thoughtSchema = new mongoose.Schema({ // Schema for the thoughts - _id: String, - message: String, +app.use(cors()); +app.use(express.json()); + +// Define the Thought schema +const thoughtSchema = new mongoose.Schema({ + message: { + type: String, + required: true, + minLength: 5, + maxLength: 140, + }, hearts: { type: Number, default: 0, + min: 0, }, createdAt: { type: Date, - default: Date.now - } -}) - -const Thought = mongoose.model("Thought", thoughtSchema) // name and schema for the model -if (process.env.RESET_DB) { - const seedData = async () => { - await Thought.deleteMany({}) // Clear the collection before seeding - thoughtData.forEach(thought => { - new Thought(thought).save() - }) - } - seedData() -} - - -// END POINTS -// Start defining your routes here -app.get("/", (req, res) => { - const endpoints = listEndpoints(app) - res.json({ - message: "Welcome to the Happy Thoughts API!", - endpoints: endpoints, - }) -}) - -//TODO: somthing is not working here, need to debug -//TODO: add query params to filter by quantity of hearts or date it has been created -// Endpoint to get all data, like all the thoughts - -app.get("/thoughts", async (req, res) => { - console.log(" GET / thoughts endpoint hit!!! PARTY TIME!!!") - const { time, hearts } = req.query; - let filter = {}; - if (time) filter.createdAt = { $gte: new Date(time) }; - if (hearts) filter.hearts = { $gte: Number(hearts) }; - - const thoughts = await Thought.find(filter).sort({ createdAt: -1 }).limit(20); - res.json(thoughts); + default: Date.now, + }, }); +const Thought = mongoose.model("Thought", thoughtSchema); -//TODO: somthing is not working here, need to debug -// endpoint to get one thought by id - -app.get("/thoughts/:id", async (req, res) => { - const { id } = req.params; - +// Endpoint to get all thoughts +app.get("/thoughts", async (req, res) => { try { - const thought = await Thought.findById(req.params.id); // Query the database - - if (!thought) { - res.status(404).json({ - success: false, - response: null, - message: "Thought not found" - }); // Handle not found - } - res.status(200).json({ - success: true, - response: thought, - message: "Thought fetched successfully" - }); // Return the thought + const thoughts = await Thought.find().sort({ createdAt: -1 }).limit(20); + res.status(200).json(thoughts); } catch (error) { - res.status(500).json({ - success: false, - response: null, - message: "Error fetching thought", - error: error.message - }); // Handle errors + res.status(500).json({ error: "Failed to fetch thoughts", details: error.message }); } - }); -//TODO: maybe i can delete this endpoint? -//endpoint to get thoughts by certain number of hearts or more -app.get("/thoughts/hearts/:minHearts", async (req, res) => { - const minHearts = Number(req.params.minHearts) - if (isNaN(minHearts)) { - return res.status(400).send({ error: "Please provide a valid number of hearts" }) - } - - const filteredThoughts = await Thought.find({ hearts: { $gte: minHearts } }) - res.json(filteredThoughts) -}) - -//TODO: check if this endpoint works // Endpoint to create a new thought app.post("/thoughts", async (req, res) => { - const { message, hearts } = req.body - - if (!message || typeof message !== "string") { - return res.status(400).json({ error: "Message is required and must be a string" }) - } + const { message } = req.body; - if (hearts !== undefined && typeof hearts !== "number") { - return res.status(400).json({ error: "Hearts must be a number" }) + if (!message || message.length < 5 || message.length > 140) { + return res.status(400).json({ error: "Message must be between 5 and 140 characters" }); } try { - const newThought = await new Thought({ message, hearts }).save() - res.status(201).json(newThought) + const newThought = await new Thought({ message }).save(); + res.status(201).json(newThought); } catch (error) { - res.status(500).json({ error: "Failed to create thought" }) - } -}) - -// Endpoint to update a thought -app.put("/thoughts/:id", async (req, res) => { - const { message, hearts } = req.body; - - try { - const updatedThought = await Thought.findByIdAndUpdate( - req.params.id, - { message, hearts }, - { new: true, runValidators: true } - ); - if (updatedThought) { - res.json(updatedThought); - } else { - res.status(404).json({ error: "Thought not found" }); - } - } catch (error) { - res.status(400).json({ error: "Invalid ID format" }); - } -}) - -// Endpoint to delete a thought -app.delete("/thoughts/:id", async (req, res) => { - try { - const deletedThought = await Thought.findByIdAndDelete(req.params.id); - if (deletedThought) { - res.json({ message: "Thought deleted successfully" }); - } else { - res.status(404).json({ error: "Thought not found" }); - } - } catch (error) { - res.status(400).json({ error: "Invalid ID format" }); + res.status(500).json({ error: "Failed to create thought", details: error.message }); } }); -// TODO: check if this endpoint works, -// Endpoint to like a thought -app.post("/thoughts/:id/like", async (req, res) => { - try { - const thought = await Thought.findByIdAndUpdate( - req.params.id, - { $inc: { hearts: 1 } }, - { new: true } - ); - if (thought) { - res.json(thought); - } else { - res.status(404).json({ error: "Thought not found" }); - } - } catch (error) { - res.status(400).json({ error: "Invalid ID format" }); - } -}); - -// Endpoint to update a thought by ID with prompt -// app.put("/thoughts/:id/prompt", async (req, res) => { -// const { id } = req.params; - -// const newMessage = prompt("Enter the updated message:"); -// if (!newMessage) return; - -// try { -// const response = await fetch(`${API_URL}/thoughts/${id}`, { -// method: "PUT", -// headers: { "Content-Type": "application/json" }, -// body: JSON.stringify({ message: newMessage }), -// }); - -// if (response.ok) { -// const updatedThought = await response.json(); -// setThoughts(thoughts.map((thought) => -// thought._id === id ? updatedThought : thought -// )); -// } else { -// console.error("Failed to update thought:", response.status, response.statusText); -// } -// } catch (error) { -// console.error("Error updating thought:", error); -// } -// }); - -const deleteThought = async (id) => { - try { - const response = await fetch(`${API_URL}/thoughts/${id}`, { - method: "DELETE", - }); - - if (response.ok) { - setThoughts(thoughts.filter((thought) => thought._id !== id)); - } else { - console.error("Failed to delete thought:", response.status, response.statusText); - } - } catch (error) { - console.error("Error deleting thought:", error); - } -}; - // Start the server app.listen(port, () => { - console.log(`Server running on http://localhost:${port}`) -}) + console.log(`Server running on http://localhost:${port}`); +}); diff --git a/todo.md b/todo.md index d90f4b8..d1686aa 100644 --- a/todo.md +++ b/todo.md @@ -29,17 +29,14 @@ - [] week 20 - - [] use postman to test the endpoint, results: - - ADD THOUGHT POST /thoughts - **!!!FAILD!!!** - "error": "Failed to create thought" - 500 Internal Server Error - - LIKE THOUGHT - error 404 not found **!!!FAILD!!!** - - EDIT A THOUGHT **!!WORKS!!** - - DELETE A THOUGHT **!!WORKS!!** - - [] make the edit text frame look nicer - [x] add a btn for edit, - [x] add a btn for delete - - [] make the text frame in edit expandable - - [] place the edit, and delete in better places + - [] use postman to test the endpoint, results: + - [x] ADD THOUGHT POST /thoughts - **!!!FAILD!!!** + "error": "Failed to create thought" - 500 Internal Server Error + - [] LIKE THOUGHT - error 404 not found **!!!FAILD!!!** + - [x] EDIT A THOUGHT **!!WORKS!!** + - [x] DELETE A THOUGHT **!!WORKS!!** - [] Your API should have routes to register and log in - [] Your endpoints to Create, Update and Delete should be authenticated - [] Your frontend should have a registration form which POSTs to the API to create a new user. @@ -47,8 +44,15 @@ - [] Your passwords in the database should be encrypted with bcrypt. - [] You should implement error handling. Your API should let the user know if something went wrong. Be as specific as possible to help the user, e.g. by validating the user input when creating a new user, and return "That email address already exists". Include correct status codes. Error messages should also be shown on the frontend. - [] The validation should ensure unique email addresses and/or usernames, depending on how you'd like to structure your User model. + + = = = extras + + - [] make the edit text frame look nicer + - [] make the text frame in edit expandable - [] should i use react router? - [] clean up components in frontend + - [] move the edit and delte btns + From 961ffeefda6f930e2dde01647b77620c69a6b6f1 Mon Sep 17 00:00:00 2001 From: alex91-html Date: Mon, 16 Jun 2025 17:55:00 +0200 Subject: [PATCH 19/30] changes to the front end --- server.js | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/server.js b/server.js index 0ed39a4..ad4a852 100644 --- a/server.js +++ b/server.js @@ -69,6 +69,44 @@ app.post("/thoughts", async (req, res) => { } }); +// Endpoint to like a thought +app.post("/thoughts/:id/like", async (req, res) => { + const { id } = req.params; + + try { + const updatedThought = await Thought.findByIdAndUpdate( + id, + { $inc: { hearts: 1 } }, // Increment the hearts count + { new: true } // Return the updated document + ); + + if (!updatedThought) { + return res.status(404).json({ error: "Thought not found" }); + } + + res.status(200).json(updatedThought); + } catch (error) { + res.status(500).json({ error: "Failed to like the thought", details: error.message }); + } +}); + +// Endpoint to delete a thought +app.delete("/thoughts/:id", async (req, res) => { + const { id } = req.params; + + try { + const deletedThought = await Thought.findByIdAndDelete(id); + + if (!deletedThought) { + return res.status(404).json({ error: "Thought not found" }); + } + + res.status(200).json({ message: "Thought deleted successfully" }); + } catch (error) { + res.status(500).json({ error: "Failed to delete the thought", details: error.message }); + } +}); + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`); From 56231214f5819568089d58fc221368e23cdf6cd4 Mon Sep 17 00:00:00 2001 From: alex91-html Date: Mon, 16 Jun 2025 18:23:07 +0200 Subject: [PATCH 20/30] added authentication --- server.js | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/server.js b/server.js index ad4a852..8dd3489 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,7 @@ import cors from "cors"; import express from "express"; +import listEndpoints from "express-list-endpoints"; + import mongoose from "mongoose"; import dotenv from "dotenv"; @@ -43,6 +45,12 @@ const thoughtSchema = new mongoose.Schema({ const Thought = mongoose.model("Thought", thoughtSchema); +// Endpoint to get API documentation +app.get("/", (req, res) => { + res.json(listEndpoints(app)); +}); + + // Endpoint to get all thoughts app.get("/thoughts", async (req, res) => { try { @@ -62,7 +70,7 @@ app.post("/thoughts", async (req, res) => { } try { - const newThought = await new Thought({ message }).save(); + const newThought = await new Thought({ message, createdBy: req.user.userId }).save(); res.status(201).json(newThought); } catch (error) { res.status(500).json({ error: "Failed to create thought", details: error.message }); @@ -95,15 +103,61 @@ app.delete("/thoughts/:id", async (req, res) => { const { id } = req.params; try { - const deletedThought = await Thought.findByIdAndDelete(id); + const deletedThought = await Thought.findOneAndDelete({ + _id: id, + createdBy: req.user.userId, + }); if (!deletedThought) { - return res.status(404).json({ error: "Thought not found" }); + return res.status(404).json({ error: "Thought not found or not authorized" }); } res.status(200).json({ message: "Thought deleted successfully" }); } catch (error) { - res.status(500).json({ error: "Failed to delete the thought", details: error.message }); + res.status(500).json({ error: "Failed to delete thought", details: error.message }); + } +}); + +// Endpoint to get a single thought by ID +app.get("/thoughts/:id", async (req, res) => { + const { id } = req.params; + + try { + const thought = await Thought.findById(id); + + if (!thought) { + return res.status(404).json({ error: "Thought not found" }); + } + + res.status(200).json(thought); + } catch (error) { + res.status(500).json({ error: "Failed to fetch the thought", details: error.message }); + } +}); + +// Endpoint to update a thought +app.put("/thoughts/:id", async (req, res) => { + const { id } = req.params; + const { message } = req.body; + + if (!message || message.length < 5 || message.length > 140) { + return res.status(400).json({ error: "Message must be between 5 and 140 characters" }); + } + + try { + const updatedThought = await Thought.findOneAndUpdate( + { _id: id, createdBy: req.user.userId }, + { message }, + { new: true } + ); + + if (!updatedThought) { + return res.status(404).json({ error: "Thought not found or not authorized" }); + } + + res.status(200).json(updatedThought); + } catch (error) { + res.status(500).json({ error: "Failed to update thought", details: error.message }); } }); From 0c7ba1f3902e40f19dbd3ae4c2ec96d90c213cad Mon Sep 17 00:00:00 2001 From: alex91-html Date: Mon, 16 Jun 2025 18:42:18 +0200 Subject: [PATCH 21/30] added folders: endpoints, middleware, models --- middleware/authMiddleware.js | 0 models/Thought.js | 0 models/user.js | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 middleware/authMiddleware.js create mode 100644 models/Thought.js create mode 100644 models/user.js diff --git a/middleware/authMiddleware.js b/middleware/authMiddleware.js new file mode 100644 index 0000000..e69de29 diff --git a/models/Thought.js b/models/Thought.js new file mode 100644 index 0000000..e69de29 diff --git a/models/user.js b/models/user.js new file mode 100644 index 0000000..e69de29 From f680318c13971e26a04a14cf29bb465b1c2148c6 Mon Sep 17 00:00:00 2001 From: alex91-html Date: Mon, 16 Jun 2025 19:03:27 +0200 Subject: [PATCH 22/30] moved schema --- models/Thought.js | 22 ++++++++++++++++++++++ server.js | 20 +------------------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/models/Thought.js b/models/Thought.js index e69de29..46c49cc 100644 --- a/models/Thought.js +++ b/models/Thought.js @@ -0,0 +1,22 @@ +import mongoose, { Schema } from "mongoose"; + +const thoughtSchema = new mongoose.Schema({ + message: { + type: String, + required: true, + minLength: 5, + maxLength: 140, + }, + hearts: { + type: Number, + default: 0, + min: 0, + }, + createdAt: { + type: Date, + default: Date.now, + }, +}); + +export const Thought = mongoose.model("Thought", thoughtSchema); + diff --git a/server.js b/server.js index 8dd3489..0bd7220 100644 --- a/server.js +++ b/server.js @@ -4,6 +4,7 @@ import listEndpoints from "express-list-endpoints"; import mongoose from "mongoose"; import dotenv from "dotenv"; +import { Thought } from "./models/Thought.js"; // Adjust the import path as necessary dotenv.config(); @@ -24,26 +25,7 @@ const app = express(); app.use(cors()); app.use(express.json()); -// Define the Thought schema -const thoughtSchema = new mongoose.Schema({ - message: { - type: String, - required: true, - minLength: 5, - maxLength: 140, - }, - hearts: { - type: Number, - default: 0, - min: 0, - }, - createdAt: { - type: Date, - default: Date.now, - }, -}); -const Thought = mongoose.model("Thought", thoughtSchema); // Endpoint to get API documentation app.get("/", (req, res) => { From bf4c068dd109412649f1c35ece77f638af0e4ca4 Mon Sep 17 00:00:00 2001 From: alex91-html Date: Wed, 18 Jun 2025 13:07:09 +0200 Subject: [PATCH 23/30] testing with hout userID --- server.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/server.js b/server.js index 0bd7220..6323eec 100644 --- a/server.js +++ b/server.js @@ -26,7 +26,6 @@ app.use(cors()); app.use(express.json()); - // Endpoint to get API documentation app.get("/", (req, res) => { res.json(listEndpoints(app)); @@ -52,7 +51,9 @@ app.post("/thoughts", async (req, res) => { } try { - const newThought = await new Thought({ message, createdBy: req.user.userId }).save(); + console.log("Creating new thought:", message); + const placeholderUserId = "testUserId"; // Hardcoded user ID for testing + const newThought = await new Thought({ message, createdBy: placeholderUserId }).save(); res.status(201).json(newThought); } catch (error) { res.status(500).json({ error: "Failed to create thought", details: error.message }); @@ -85,9 +86,10 @@ app.delete("/thoughts/:id", async (req, res) => { const { id } = req.params; try { + const placeholderUserId = "testUserId"; // Hardcoded user ID for testing const deletedThought = await Thought.findOneAndDelete({ _id: id, - createdBy: req.user.userId, + createdBy: placeholderUserId, }); if (!deletedThought) { @@ -127,8 +129,9 @@ app.put("/thoughts/:id", async (req, res) => { } try { + const placeholderUserId = "testUserId"; // Hardcoded user ID for testing const updatedThought = await Thought.findOneAndUpdate( - { _id: id, createdBy: req.user.userId }, + { _id: id, createdBy: placeholderUserId }, { message }, { new: true } ); From 0e4be3d0df799942f1338d24619ec4e9f8cbc4bd Mon Sep 17 00:00:00 2001 From: alex91-html Date: Wed, 18 Jun 2025 13:18:21 +0200 Subject: [PATCH 24/30] debugging --- server.js | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/server.js b/server.js index 6323eec..1122767 100644 --- a/server.js +++ b/server.js @@ -52,8 +52,7 @@ app.post("/thoughts", async (req, res) => { try { console.log("Creating new thought:", message); - const placeholderUserId = "testUserId"; // Hardcoded user ID for testing - const newThought = await new Thought({ message, createdBy: placeholderUserId }).save(); + const newThought = await new Thought({ message }).save(); res.status(201).json(newThought); } catch (error) { res.status(500).json({ error: "Failed to create thought", details: error.message }); @@ -86,14 +85,10 @@ app.delete("/thoughts/:id", async (req, res) => { const { id } = req.params; try { - const placeholderUserId = "testUserId"; // Hardcoded user ID for testing - const deletedThought = await Thought.findOneAndDelete({ - _id: id, - createdBy: placeholderUserId, - }); + const deletedThought = await Thought.findByIdAndDelete(id); // No user association if (!deletedThought) { - return res.status(404).json({ error: "Thought not found or not authorized" }); + return res.status(404).json({ error: "Thought not found" }); } res.status(200).json({ message: "Thought deleted successfully" }); @@ -129,15 +124,14 @@ app.put("/thoughts/:id", async (req, res) => { } try { - const placeholderUserId = "testUserId"; // Hardcoded user ID for testing - const updatedThought = await Thought.findOneAndUpdate( - { _id: id, createdBy: placeholderUserId }, - { message }, + const updatedThought = await Thought.findByIdAndUpdate( + id, + { message }, // Update the message only { new: true } ); if (!updatedThought) { - return res.status(404).json({ error: "Thought not found or not authorized" }); + return res.status(404).json({ error: "Thought not found" }); } res.status(200).json(updatedThought); From 394b5efd2e4bddb5c24b2667cf2826ad75bc290b Mon Sep 17 00:00:00 2001 From: alex91-html Date: Thu, 19 Jun 2025 14:02:41 +0200 Subject: [PATCH 25/30] debugged --- todo.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/todo.md b/todo.md index d1686aa..c013c64 100644 --- a/todo.md +++ b/todo.md @@ -31,12 +31,18 @@ - [] week 20 - [x] add a btn for edit, - [x] add a btn for delete - - [] use postman to test the endpoint, results: + - [x] use postman to test the endpoint, results: - [x] ADD THOUGHT POST /thoughts - **!!!FAILD!!!** "error": "Failed to create thought" - 500 Internal Server Error - - [] LIKE THOUGHT - error 404 not found **!!!FAILD!!!** + - [x] LIKE THOUGHT - error 404 not found **!!!FAILD!!!** - [x] EDIT A THOUGHT **!!WORKS!!** - [x] DELETE A THOUGHT **!!WORKS!!** + + - [] could the error be related to authentication? + + - [x] Editing, cancelling and creatign a new thought when working with the deployed database is not working. + + - [] Your API should have routes to register and log in - [] Your endpoints to Create, Update and Delete should be authenticated - [] Your frontend should have a registration form which POSTs to the API to create a new user. From e10fc7e2d4348ef5652ca037479a84970e90876e Mon Sep 17 00:00:00 2001 From: alex91-html Date: Tue, 24 Jun 2025 17:16:17 +0200 Subject: [PATCH 26/30] updated to do list --- todo.md | 106 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 89 insertions(+), 17 deletions(-) diff --git a/todo.md b/todo.md index c013c64..5f6b556 100644 --- a/todo.md +++ b/todo.md @@ -23,26 +23,17 @@ - [x] look throught all classes again and try to fix problem with my code - [x] seems not possible to add a thought, edit or remove a thuoght not even to like - [x] Your frontend should be updated with the possibility to Update and Delete a thought. - - - - - - [] week 20 - [x] add a btn for edit, - [x] add a btn for delete - [x] use postman to test the endpoint, results: - - [x] ADD THOUGHT POST /thoughts - **!!!FAILD!!!** - "error": "Failed to create thought" - 500 Internal Server Error - - [x] LIKE THOUGHT - error 404 not found **!!!FAILD!!!** - - [x] EDIT A THOUGHT **!!WORKS!!** - - [x] DELETE A THOUGHT **!!WORKS!!** - - - [] could the error be related to authentication? - + - [x] ADD THOUGHT POST /thoughts - **!!!FAILD!!!** + "error": "Failed to create thought" - 500 Internal Server Error + - [x] LIKE THOUGHT - error 404 not found **!!!FAILD!!!** + - [x] EDIT A THOUGHT **!!WORKS!!** + - [x] DELETE A THOUGHT **!!WORKS!!** + - [x] could the error be related to authentication? - [x] Editing, cancelling and creatign a new thought when working with the deployed database is not working. - - - [] Your API should have routes to register and log in - [] Your endpoints to Create, Update and Delete should be authenticated - [] Your frontend should have a registration form which POSTs to the API to create a new user. @@ -60,9 +51,90 @@ - [] move the edit and delte btns - +- [] Completion of one peer code review - on the backend repo. **NOTES**: maybe I have to fix the endpoints? Have to look at week 19 to check what are the mistaked with the diployed data, i think the problem is there. - **13.06 - 16:08** it is fetching data from the deployed data, but seems i can't add likes, remove or edit anything - - **video of we** got at min 00:34 \ No newline at end of file + - **video of we** got at min 00:34 + + = = = + + API ROUTES & FEATURES +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +[โœ”] Documentation (Express List Endpoints) +[โœ”] Read all thoughts +[โœ”] Read a single thought +[โœ”] Like a thought +[โœ”] Create a thought +[โœ”] Update a thought +[โœ”] Delete a thought +[ ] Create a thought (authenticated) +[ ] Update a thought (authenticated) +[ ] Delete a thought (authenticated) +[ ] Sign up +[ ] Log in + +API DESIGN & QUALITY +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +[โœ”] RESTful API +[โœ”] Clean code guidelines (partially, review for improvements) +[โœ”] Mongoose models for data +[โœ”] Input validation for thoughts +[ ] Input validation for users (unique email/username) +[โœ”] Error handling for thoughts +[ ] Error handling for users/auth +[ ] Password encryption with bcrypt + +FRONTEND FEATURES +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +[โœ”] Read thoughts +[โœ”] Like a thought +[โœ”] Create a thought +[โœ”] Update a thought +[โœ”] Delete a thought +[ ] Sign up +[ ] Log in +[ ] Error handling for auth + +DEPLOYMENT +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +[โœ”] API deployed to Render + +SYNC FRONTEND & BACKEND +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +[ ] Everything in backend reflected in frontend (auth, error handling, etc.) + + + + +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ API โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ Docs [โœ”] โ”‚ +โ”‚ Read [โœ”] โ”‚ +โ”‚ Read 1 [โœ”] โ”‚ +โ”‚ Like [โœ”] โ”‚ +โ”‚ Create [โœ”] (auth [ ]) โ”‚ +โ”‚ Update [โœ”] (auth [ ]) โ”‚ +โ”‚ Delete [โœ”] (auth [ ]) โ”‚ +โ”‚ Signup [ ] โ”‚ +โ”‚ Login [ ] โ”‚ +โ”‚ Validation [โœ”] (users [ ]) โ”‚ +โ”‚ Error handling [โœ”] (users[ ])โ”‚ +โ”‚ Bcrypt [ ] โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ + โ–ผ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ FRONTEND โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ Read [โœ”] โ”‚ +โ”‚ Like [โœ”] โ”‚ +โ”‚ Create [โœ”] โ”‚ +โ”‚ Update [โœ”] โ”‚ +โ”‚ Delete [โœ”] โ”‚ +โ”‚ Signup [ ] โ”‚ +โ”‚ Login [ ] โ”‚ +โ”‚ Auth error handling [ ] โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ \ No newline at end of file From 35d33d291b92664fe65b58f27fbedca00ed59ae8 Mon Sep 17 00:00:00 2001 From: alex91-html Date: Tue, 24 Jun 2025 17:30:14 +0200 Subject: [PATCH 27/30] implementing user.js with user model --- models/user.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/models/user.js b/models/user.js index e69de29..a2aae85 100644 --- a/models/user.js +++ b/models/user.js @@ -0,0 +1,27 @@ +import mongoose from "mongoose"; + +const userSchema = new mongoose.Schema({ + username: { + type: String, + required: true, + unique: true, + trim: true, + minlength: 3, + maxlength: 10 + }, + email: { + type: String, + required: true, + unique: true, + trim: true, + lowercase: true + }, + password: { + type: String, + required: true, + minlength: 6 + } +}); + +export const User = mongoose.model("User", userSchema); + From cd0507c310cdaa759a16b63c633f5655beee296d Mon Sep 17 00:00:00 2001 From: alex91-html Date: Tue, 24 Jun 2025 17:44:38 +0200 Subject: [PATCH 28/30] installaed bcrypt --- package.json | 4 +++- routes/auth.js | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ server.js | 3 +++ todo.md | 6 +++--- 4 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 routes/auth.js diff --git a/package.json b/package.json index 07f4d42..18f9769 100644 --- a/package.json +++ b/package.json @@ -12,12 +12,14 @@ "@babel/core": "^7.17.9", "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", + "bcrypt": "^6.0.0", "cors": "^2.8.5", "dotenv": "^16.5.0", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", + "jsonwebtoken": "^9.0.2", "mongodb": "^6.17.0", "mongoose": "^8.15.1", "nodemon": "^3.1.10" } -} \ No newline at end of file +} diff --git a/routes/auth.js b/routes/auth.js new file mode 100644 index 0000000..fe40fd7 --- /dev/null +++ b/routes/auth.js @@ -0,0 +1,51 @@ +import express from "express"; +import bcrypt from "bcrypt"; +import jwt from "jsonwebtoken"; +import { User } from "../models/user.js"; + +const router = express.Router(); +const JWT_SECRET = process.env.JWT_SECRET || "supersecret"; + +// Register endpoint +router.post("/register", async (req, res) => { + const { username, email, password } = req.body; + if (!username || !email || !password) { + return res.status(400).json({ error: "All fields are required." }); + } + try { + const existingUser = await User.findOne({ $or: [{ email }, { username }] }); + if (existingUser) { + return res.status(400).json({ error: "Username or email already exists." }); + } + const hashedPassword = await bcrypt.hash(password, 10); + const user = new User({ username, email, password: hashedPassword }); + await user.save(); + res.status(201).json({ message: "User registered successfully." }); + } catch (error) { + res.status(500).json({ error: "Failed to register user.", details: error.message }); + } +}); + +// Login endpoint +router.post("/login", async (req, res) => { + const { email, password } = req.body; + if (!email || !password) { + return res.status(400).json({ error: "Email and password are required." }); + } + try { + const user = await User.findOne({ email }); + if (!user) { + return res.status(401).json({ error: "Invalid email or password." }); + } + const passwordMatch = await bcrypt.compare(password, user.password); + if (!passwordMatch) { + return res.status(401).json({ error: "Invalid email or password." }); + } + const token = jwt.sign({ userId: user._id, username: user.username }, JWT_SECRET, { expiresIn: "24h" }); + res.status(200).json({ token, username: user.username }); + } catch (error) { + res.status(500).json({ error: "Failed to log in.", details: error.message }); + } +}); + +export default router; \ No newline at end of file diff --git a/server.js b/server.js index 1122767..6a2c8ed 100644 --- a/server.js +++ b/server.js @@ -5,6 +5,7 @@ import listEndpoints from "express-list-endpoints"; import mongoose from "mongoose"; import dotenv from "dotenv"; import { Thought } from "./models/Thought.js"; // Adjust the import path as necessary +import authRouter from "./routes/auth.js"; dotenv.config(); @@ -140,6 +141,8 @@ app.put("/thoughts/:id", async (req, res) => { } }); +app.use("/auth", authRouter); + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`); diff --git a/todo.md b/todo.md index 5f6b556..eb55b78 100644 --- a/todo.md +++ b/todo.md @@ -69,9 +69,9 @@ [โœ”] Create a thought [โœ”] Update a thought [โœ”] Delete a thought -[ ] Create a thought (authenticated) -[ ] Update a thought (authenticated) -[ ] Delete a thought (authenticated) +[โœ”] Create a thought (authenticated) +[โœ”] Update a thought (authenticated) +[โœ”] Delete a thought (authenticated) [ ] Sign up [ ] Log in From f36a7971c16dcd62dfa9e98d15a8af785e4643b4 Mon Sep 17 00:00:00 2001 From: alex91-html Date: Tue, 24 Jun 2025 21:00:15 +0200 Subject: [PATCH 29/30] final --- middleware/authMiddleware.js | 22 ++++++ models/Thought.js | 5 ++ models/user.js | 4 + package.json | 2 +- routes/auth.js | 17 +++-- server.js | 48 ++++++------ todo.md | 140 ----------------------------------- 7 files changed, 65 insertions(+), 173 deletions(-) delete mode 100644 todo.md diff --git a/middleware/authMiddleware.js b/middleware/authMiddleware.js index e69de29..92f10f5 100644 --- a/middleware/authMiddleware.js +++ b/middleware/authMiddleware.js @@ -0,0 +1,22 @@ +import { User } from "../models/user.js"; + +export const authenticateUser = async (req, res, next) => { + try { + const accessToken = req.header("Authorization"); + const user = await User.findOne({ accessToken }); + if (user) { + req.user = user; + next(); + } else { + res.status(401).json({ + message: "Authentication missing or invalid.", + loggedOut: true + }); + } + } catch (error) { + res.status(500).json({ + message: "Internal server error", + error: error.message + }); + } +}; diff --git a/models/Thought.js b/models/Thought.js index 46c49cc..26b8d69 100644 --- a/models/Thought.js +++ b/models/Thought.js @@ -16,6 +16,11 @@ const thoughtSchema = new mongoose.Schema({ type: Date, default: Date.now, }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: "User", + required: true + } }); export const Thought = mongoose.model("Thought", thoughtSchema); diff --git a/models/user.js b/models/user.js index a2aae85..525d029 100644 --- a/models/user.js +++ b/models/user.js @@ -20,6 +20,10 @@ const userSchema = new mongoose.Schema({ type: String, required: true, minlength: 6 + }, + accessToken: { + type: String, + default: null } }); diff --git a/package.json b/package.json index 18f9769..5b7bb32 100644 --- a/package.json +++ b/package.json @@ -22,4 +22,4 @@ "mongoose": "^8.15.1", "nodemon": "^3.1.10" } -} +} \ No newline at end of file diff --git a/routes/auth.js b/routes/auth.js index fe40fd7..e8e8159 100644 --- a/routes/auth.js +++ b/routes/auth.js @@ -1,10 +1,12 @@ import express from "express"; import bcrypt from "bcrypt"; -import jwt from "jsonwebtoken"; +import crypto from "crypto"; import { User } from "../models/user.js"; const router = express.Router(); -const JWT_SECRET = process.env.JWT_SECRET || "supersecret"; + +// Helper to generate a random access token +const generateAccessToken = () => crypto.randomBytes(32).toString("hex"); // Register endpoint router.post("/register", async (req, res) => { @@ -18,9 +20,10 @@ router.post("/register", async (req, res) => { return res.status(400).json({ error: "Username or email already exists." }); } const hashedPassword = await bcrypt.hash(password, 10); - const user = new User({ username, email, password: hashedPassword }); + const accessToken = generateAccessToken(); + const user = new User({ username, email, password: hashedPassword, accessToken }); await user.save(); - res.status(201).json({ message: "User registered successfully." }); + res.status(201).json({ message: "User registered successfully.", accessToken, username: user.username }); } catch (error) { res.status(500).json({ error: "Failed to register user.", details: error.message }); } @@ -41,8 +44,10 @@ router.post("/login", async (req, res) => { if (!passwordMatch) { return res.status(401).json({ error: "Invalid email or password." }); } - const token = jwt.sign({ userId: user._id, username: user.username }, JWT_SECRET, { expiresIn: "24h" }); - res.status(200).json({ token, username: user.username }); + // Generate a new accessToken on login + user.accessToken = generateAccessToken(); + await user.save(); + res.status(200).json({ accessToken: user.accessToken, username: user.username }); } catch (error) { res.status(500).json({ error: "Failed to log in.", details: error.message }); } diff --git a/server.js b/server.js index 6a2c8ed..126b192 100644 --- a/server.js +++ b/server.js @@ -6,6 +6,7 @@ import mongoose from "mongoose"; import dotenv from "dotenv"; import { Thought } from "./models/Thought.js"; // Adjust the import path as necessary import authRouter from "./routes/auth.js"; +import { authenticateUser } from "./middleware/authMiddleware.js"; dotenv.config(); @@ -43,17 +44,14 @@ app.get("/thoughts", async (req, res) => { } }); -// Endpoint to create a new thought -app.post("/thoughts", async (req, res) => { +// Endpoint to create a new thought (authenticated) +app.post("/thoughts", authenticateUser, async (req, res) => { const { message } = req.body; - if (!message || message.length < 5 || message.length > 140) { return res.status(400).json({ error: "Message must be between 5 and 140 characters" }); } - try { - console.log("Creating new thought:", message); - const newThought = await new Thought({ message }).save(); + const newThought = await new Thought({ message, user: req.user._id }).save(); res.status(201).json(newThought); } catch (error) { res.status(500).json({ error: "Failed to create thought", details: error.message }); @@ -81,17 +79,18 @@ app.post("/thoughts/:id/like", async (req, res) => { } }); -// Endpoint to delete a thought -app.delete("/thoughts/:id", async (req, res) => { +// Endpoint to delete a thought (authenticated, only owner) +app.delete("/thoughts/:id", authenticateUser, async (req, res) => { const { id } = req.params; - try { - const deletedThought = await Thought.findByIdAndDelete(id); // No user association - - if (!deletedThought) { + const thought = await Thought.findById(id); + if (!thought) { return res.status(404).json({ error: "Thought not found" }); } - + if (String(thought.user) !== String(req.user._id)) { + return res.status(403).json({ error: "You are not authorized to delete this thought" }); + } + await thought.deleteOne(); res.status(200).json({ message: "Thought deleted successfully" }); } catch (error) { res.status(500).json({ error: "Failed to delete thought", details: error.message }); @@ -115,27 +114,24 @@ app.get("/thoughts/:id", async (req, res) => { } }); -// Endpoint to update a thought -app.put("/thoughts/:id", async (req, res) => { +// Endpoint to update a thought (authenticated, only owner) +app.put("/thoughts/:id", authenticateUser, async (req, res) => { const { id } = req.params; const { message } = req.body; - if (!message || message.length < 5 || message.length > 140) { return res.status(400).json({ error: "Message must be between 5 and 140 characters" }); } - try { - const updatedThought = await Thought.findByIdAndUpdate( - id, - { message }, // Update the message only - { new: true } - ); - - if (!updatedThought) { + const thought = await Thought.findById(id); + if (!thought) { return res.status(404).json({ error: "Thought not found" }); } - - res.status(200).json(updatedThought); + if (String(thought.user) !== String(req.user._id)) { + return res.status(403).json({ error: "You are not authorized to update this thought" }); + } + thought.message = message; + await thought.save(); + res.status(200).json(thought); } catch (error) { res.status(500).json({ error: "Failed to update thought", details: error.message }); } diff --git a/todo.md b/todo.md deleted file mode 100644 index eb55b78..0000000 --- a/todo.md +++ /dev/null @@ -1,140 +0,0 @@ -- [x] week 18 - seting up with local data, - - [x] video tue 27 - - [x] video wend 28 > maybe something is wrong here, idk -- [x] week 19 - [place-things-into-the-database] - - - - [x] deploy the backend in render - - [x] Your API should use Mongoose models to model your data and use these models to fetch data from the database. - - [x] Your API should validate user input and return appropriate errors if the input is invalid. - - [x] You should implement error handling for all your routes, with proper response statuses. - - [x] video of tue - - [x] i have commented out the back end, data seems to be fetch from the front, fix that! and fix the back end, i feel i'm almost there. - - [x] Ensure the frontend is sending the correct requests to the backend: - - Check the request URLs and payloads. - - Add logs to the frontend functions to debug the requests. - - [x] video of wen jun 4th - - [x] why is there no happy thought been shown? - - [x] check the render deployment if it works - - [x] check MongoDB - - [x] render nad mongo are connected - - [x] test the frontend connection to render with postman - - [x] try to fix error - - [x] look throught all classes again and try to fix problem with my code - - [x] seems not possible to add a thought, edit or remove a thuoght not even to like - - [x] Your frontend should be updated with the possibility to Update and Delete a thought. -- [] week 20 - - [x] add a btn for edit, - - [x] add a btn for delete - - [x] use postman to test the endpoint, results: - - [x] ADD THOUGHT POST /thoughts - **!!!FAILD!!!** - "error": "Failed to create thought" - 500 Internal Server Error - - [x] LIKE THOUGHT - error 404 not found **!!!FAILD!!!** - - [x] EDIT A THOUGHT **!!WORKS!!** - - [x] DELETE A THOUGHT **!!WORKS!!** - - [x] could the error be related to authentication? - - [x] Editing, cancelling and creatign a new thought when working with the deployed database is not working. - - [] Your API should have routes to register and log in - - [] Your endpoints to Create, Update and Delete should be authenticated - - [] Your frontend should have a registration form which POSTs to the API to create a new user. - - [] Your frontend should have a login form to authenticate the user. - - [] Your passwords in the database should be encrypted with bcrypt. - - [] You should implement error handling. Your API should let the user know if something went wrong. Be as specific as possible to help the user, e.g. by validating the user input when creating a new user, and return "That email address already exists". Include correct status codes. Error messages should also be shown on the frontend. - - [] The validation should ensure unique email addresses and/or usernames, depending on how you'd like to structure your User model. - - = = = extras - - - [] make the edit text frame look nicer - - [] make the text frame in edit expandable - - [] should i use react router? - - [] clean up components in frontend - - [] move the edit and delte btns - - -- [] Completion of one peer code review - on the backend repo. - - - **NOTES**: maybe I have to fix the endpoints? Have to look at week 19 to check what are the mistaked with the diployed data, i think the problem is there. - - **13.06 - 16:08** it is fetching data from the deployed data, but seems i can't add likes, remove or edit anything - - **video of we** got at min 00:34 - - = = = - - API ROUTES & FEATURES -โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -[โœ”] Documentation (Express List Endpoints) -[โœ”] Read all thoughts -[โœ”] Read a single thought -[โœ”] Like a thought -[โœ”] Create a thought -[โœ”] Update a thought -[โœ”] Delete a thought -[โœ”] Create a thought (authenticated) -[โœ”] Update a thought (authenticated) -[โœ”] Delete a thought (authenticated) -[ ] Sign up -[ ] Log in - -API DESIGN & QUALITY -โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -[โœ”] RESTful API -[โœ”] Clean code guidelines (partially, review for improvements) -[โœ”] Mongoose models for data -[โœ”] Input validation for thoughts -[ ] Input validation for users (unique email/username) -[โœ”] Error handling for thoughts -[ ] Error handling for users/auth -[ ] Password encryption with bcrypt - -FRONTEND FEATURES -โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -[โœ”] Read thoughts -[โœ”] Like a thought -[โœ”] Create a thought -[โœ”] Update a thought -[โœ”] Delete a thought -[ ] Sign up -[ ] Log in -[ ] Error handling for auth - -DEPLOYMENT -โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -[โœ”] API deployed to Render - -SYNC FRONTEND & BACKEND -โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -[ ] Everything in backend reflected in frontend (auth, error handling, etc.) - - - - -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ API โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ Docs [โœ”] โ”‚ -โ”‚ Read [โœ”] โ”‚ -โ”‚ Read 1 [โœ”] โ”‚ -โ”‚ Like [โœ”] โ”‚ -โ”‚ Create [โœ”] (auth [ ]) โ”‚ -โ”‚ Update [โœ”] (auth [ ]) โ”‚ -โ”‚ Delete [โœ”] (auth [ ]) โ”‚ -โ”‚ Signup [ ] โ”‚ -โ”‚ Login [ ] โ”‚ -โ”‚ Validation [โœ”] (users [ ]) โ”‚ -โ”‚ Error handling [โœ”] (users[ ])โ”‚ -โ”‚ Bcrypt [ ] โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ”‚ - โ–ผ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ FRONTEND โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ Read [โœ”] โ”‚ -โ”‚ Like [โœ”] โ”‚ -โ”‚ Create [โœ”] โ”‚ -โ”‚ Update [โœ”] โ”‚ -โ”‚ Delete [โœ”] โ”‚ -โ”‚ Signup [ ] โ”‚ -โ”‚ Login [ ] โ”‚ -โ”‚ Auth error handling [ ] โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ \ No newline at end of file From b7c0b259d8cc762966d5fa6078a3a1a3cc50ee40 Mon Sep 17 00:00:00 2001 From: alex91-html Date: Tue, 24 Jun 2025 21:13:57 +0200 Subject: [PATCH 30/30] removed email --- models/user.js | 7 ------- routes/auth.js | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/models/user.js b/models/user.js index 525d029..4c39948 100644 --- a/models/user.js +++ b/models/user.js @@ -9,13 +9,6 @@ const userSchema = new mongoose.Schema({ minlength: 3, maxlength: 10 }, - email: { - type: String, - required: true, - unique: true, - trim: true, - lowercase: true - }, password: { type: String, required: true, diff --git a/routes/auth.js b/routes/auth.js index e8e8159..789d6bc 100644 --- a/routes/auth.js +++ b/routes/auth.js @@ -10,18 +10,18 @@ const generateAccessToken = () => crypto.randomBytes(32).toString("hex"); // Register endpoint router.post("/register", async (req, res) => { - const { username, email, password } = req.body; - if (!username || !email || !password) { - return res.status(400).json({ error: "All fields are required." }); + const { username, password } = req.body; + if (!username || !password) { + return res.status(400).json({ error: "Username and password are required." }); } try { - const existingUser = await User.findOne({ $or: [{ email }, { username }] }); + const existingUser = await User.findOne({ username }); if (existingUser) { - return res.status(400).json({ error: "Username or email already exists." }); + return res.status(400).json({ error: "Username already exists." }); } const hashedPassword = await bcrypt.hash(password, 10); const accessToken = generateAccessToken(); - const user = new User({ username, email, password: hashedPassword, accessToken }); + const user = new User({ username, password: hashedPassword, accessToken }); await user.save(); res.status(201).json({ message: "User registered successfully.", accessToken, username: user.username }); } catch (error) { @@ -31,18 +31,18 @@ router.post("/register", async (req, res) => { // Login endpoint router.post("/login", async (req, res) => { - const { email, password } = req.body; - if (!email || !password) { - return res.status(400).json({ error: "Email and password are required." }); + const { username, password } = req.body; + if (!username || !password) { + return res.status(400).json({ error: "Username and password are required." }); } try { - const user = await User.findOne({ email }); + const user = await User.findOne({ username }); if (!user) { - return res.status(401).json({ error: "Invalid email or password." }); + return res.status(401).json({ error: "Invalid username or password." }); } const passwordMatch = await bcrypt.compare(password, user.password); if (!passwordMatch) { - return res.status(401).json({ error: "Invalid email or password." }); + return res.status(401).json({ error: "Invalid username or password." }); } // Generate a new accessToken on login user.accessToken = generateAccessToken();