From 4ffef482c14df1973d9981c23d371a3f3e99f66d Mon Sep 17 00:00:00 2001 From: Matilda Brunemalm Date: Thu, 22 May 2025 09:35:29 +0200 Subject: [PATCH 01/31] Initial commit --- .babelrc | 3 +++ .gitignore | 8 ++++++++ README.md | 11 +++++++++++ package.json | 19 +++++++++++++++++++ server.js | 22 ++++++++++++++++++++++ 5 files changed, 63 insertions(+) create mode 100644 .babelrc create mode 100644 .gitignore create mode 100644 README.md create mode 100644 package.json create mode 100644 server.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..1320b9a --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["@babel/preset-env"] +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f1ff414 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +node_modules +.DS_Store +.env +.env.local +.env.development.local +.env.test.local +.env.production.local +package-lock.json \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..2c47b4f --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# Express API Starter Project + +This project includes the packages and babel setup for an express server, and is just meant to make things a little simpler to get up and running with. + +## Getting started + +Install dependencies with `npm install`, then start the server by running `npm run dev` + +## View it live + +Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. diff --git a/package.json b/package.json new file mode 100644 index 0000000..b4e8ccd --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "express-api-starter", + "version": "1.0.0", + "description": "Starter project to get up and running with express quickly", + "scripts": { + "start": "babel-node server.js", + "dev": "nodemon server.js --exec babel-node" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@babel/core": "^7.17.9", + "@babel/node": "^7.16.8", + "@babel/preset-env": "^7.16.11", + "cors": "^2.8.5", + "express": "^4.17.3", + "nodemon": "^3.0.1" + } +} diff --git a/server.js b/server.js new file mode 100644 index 0000000..7724e36 --- /dev/null +++ b/server.js @@ -0,0 +1,22 @@ +import express from "express"; +import cors from "cors"; + +// 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 app = express(); + +// Add middlewares to enable cors and json body parsing +app.use(cors()); +app.use(express.json()); + +// Start defining your routes here +app.get("/", (req, res) => { + res.send("Hello Technigo!"); +}); + +// Start the server +app.listen(port, () => { + console.log(`Server running on http://localhost:${port}`); +}); From 878b1a88c940583ac4edb136be7b26bce02a4a83 Mon Sep 17 00:00:00 2001 From: Matilda Brunemalm <> Date: Thu, 22 May 2025 09:38:29 +0200 Subject: [PATCH 02/31] Change name on project --- README.md | 2 +- package.json | 4 ++-- pull_request_template.md | 1 + server.js | 20 ++++++++++---------- 4 files changed, 14 insertions(+), 13 deletions(-) create mode 100644 pull_request_template.md diff --git a/README.md b/README.md index 2c47b4f..0f9f073 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Express API Starter Project +# Project API This project includes the packages and babel setup for an express server, and is just meant to make things a little simpler to get up and running with. diff --git a/package.json b/package.json index b4e8ccd..bf25bb6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "express-api-starter", + "name": "project-api", "version": "1.0.0", - "description": "Starter project to get up and running with express quickly", + "description": "Project API", "scripts": { "start": "babel-node server.js", "dev": "nodemon server.js --exec babel-node" diff --git a/pull_request_template.md b/pull_request_template.md new file mode 100644 index 0000000..fb9fdc3 --- /dev/null +++ b/pull_request_template.md @@ -0,0 +1 @@ +Please include your Render link here. \ No newline at end of file diff --git a/server.js b/server.js index 7724e36..15f6876 100644 --- a/server.js +++ b/server.js @@ -1,22 +1,22 @@ -import express from "express"; -import cors from "cors"; +import express from "express" +import cors from "cors" // 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 app = express(); +const port = process.env.PORT || 8080 +const app = express() // Add middlewares to enable cors and json body parsing -app.use(cors()); -app.use(express.json()); +app.use(cors()) +app.use(express.json()) // Start defining your routes here app.get("/", (req, res) => { - res.send("Hello Technigo!"); -}); + res.send("Hello Technigo!") +}) // Start the server app.listen(port, () => { - console.log(`Server running on http://localhost:${port}`); -}); + console.log(`Server running on http://localhost:${port}`) +}) From 6f36df90acea8b593d17cb6aca24c30ed6f7552f Mon Sep 17 00:00:00 2001 From: Matilda Brunemalm <> Date: Thu, 22 May 2025 11:00:33 +0200 Subject: [PATCH 03/31] Create dataset --- data.json | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ server.js | 2 +- 2 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 data.json diff --git a/data.json b/data.json new file mode 100644 index 0000000..a2c844f --- /dev/null +++ b/data.json @@ -0,0 +1,121 @@ +[ + { + "_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 15f6876..f47771b 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,5 @@ -import express from "express" import cors from "cors" +import express from "express" // 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 c219fef43f712806e1af339f5a38568941ab9332 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Fri, 30 May 2025 00:08:29 +0200 Subject: [PATCH 04/31] initial com, adding all dependencies --- data.json => data/data.json | 0 package.json | 12 +++++++----- server.js | 3 +-- 3 files changed, 8 insertions(+), 7 deletions(-) rename data.json => data/data.json (100%) diff --git a/data.json b/data/data.json similarity index 100% rename from data.json rename to data/data.json diff --git a/package.json b/package.json index bf25bb6..082210b 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,13 @@ "author": "", "license": "ISC", "dependencies": { - "@babel/core": "^7.17.9", - "@babel/node": "^7.16.8", - "@babel/preset-env": "^7.16.11", + "@babel/core": "^7.27.3", + "@babel/node": "^7.27.1", + "@babel/preset-env": "^7.27.2", "cors": "^2.8.5", - "express": "^4.17.3", - "nodemon": "^3.0.1" + "dotenv": "^16.5.0", + "express": "^4.21.2", + "express-list-endpoints": "^7.1.1", + "nodemon": "^3.1.10" } } diff --git a/server.js b/server.js index f47771b..877a9c8 100644 --- a/server.js +++ b/server.js @@ -1,10 +1,9 @@ import cors from "cors" import express from "express" -// 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 || 8000 const app = express() // Add middlewares to enable cors and json body parsing From 4cbcffb4bf56caa322b1c23bb90047c155d2157b Mon Sep 17 00:00:00 2001 From: Bianka R Date: Fri, 30 May 2025 00:40:09 +0200 Subject: [PATCH 05/31] code endpoints for collection of thoughts and single thought return --- data/{data.json => thoughtsList.json} | 0 server.js | 23 ++++++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) rename data/{data.json => thoughtsList.json} (100%) diff --git a/data/data.json b/data/thoughtsList.json similarity index 100% rename from data/data.json rename to data/thoughtsList.json diff --git a/server.js b/server.js index 877a9c8..bdb6eab 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,8 @@ import cors from "cors" import express from "express" +import thoughtsList from "./data/thoughtsList.json" + // when starting the server. Example command to overwrite PORT env variable value: // PORT=9000 npm start const port = process.env.PORT || 8000 @@ -12,7 +14,26 @@ app.use(express.json()) // Start defining your routes here app.get("/", (req, res) => { - res.send("Hello Technigo!") + res.send("Hello !") +}) + +// Endpoint for all thought +app.get("/thoughts", (req, res) => { + res.json(thoughtsList) +}) + +// Endpoint for one thought +app.get("/thoughts/:id", (req, res) => { + + console.log("req.params", req.params.id) + + const aThought = thoughtsList.find(t => t._id === req.params.id) + + if (!aThought) { + return res.status(404).json({ error: "thought not found" }) + } + + res.json(aThought) }) // Start the server From db2663f8cbb14184f11e4571c1ddda09de396c60 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Mon, 2 Jun 2025 18:42:54 +0200 Subject: [PATCH 06/31] add list endpoints, api doc --- server.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/server.js b/server.js index bdb6eab..7c868cd 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 thoughtsList from "./data/thoughtsList.json" @@ -14,12 +15,26 @@ app.use(express.json()) // Start defining your routes here app.get("/", (req, res) => { - res.send("Hello !") + const endpoints = listEndpoints(app) + res.json({ + message: "Hello Happy Thoughts API", + endpoints: endpoints + }) }) -// Endpoint for all thought +// Endpoint for all thoughts +// Query params to filter app.get("/thoughts", (req, res) => { - res.json(thoughtsList) + + const { hearts } = req.query + + let heartsFilter = thoughtsList + + if (hearts) { + heartsFilter = heartsFilter.filter(t => t.hearts === +hearts ) + } + + res.json(heartsFilter) }) // Endpoint for one thought From 220fe2e8b6df17dde95e86e9983cf428e81e0215 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Wed, 4 Jun 2025 22:48:56 +0200 Subject: [PATCH 07/31] mongodb, mongoose methods added for database seed --- data/thoughtsList.json | 7 ------- package.json | 2 ++ server.js | 35 +++++++++++++++++++++++++++++++---- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/data/thoughtsList.json b/data/thoughtsList.json index a2c844f..1124d7f 100644 --- a/data/thoughtsList.json +++ b/data/thoughtsList.json @@ -110,12 +110,5 @@ "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/package.json b/package.json index 082210b..a25852d 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,8 @@ "dotenv": "^16.5.0", "express": "^4.21.2", "express-list-endpoints": "^7.1.1", + "mongodb": "^6.17.0", + "mongoose": "^8.15.1", "nodemon": "^3.1.10" } } diff --git a/server.js b/server.js index 7c868cd..e58a1fe 100644 --- a/server.js +++ b/server.js @@ -1,19 +1,46 @@ import cors from "cors" import express from "express" import listEndpoints from "express-list-endpoints" +import mongoose from "mongoose" import thoughtsList from "./data/thoughtsList.json" -// when starting the server. Example command to overwrite PORT env variable value: -// PORT=9000 npm start +// CONNECTION SETTINGS const port = process.env.PORT || 8000 const app = express() -// Add middlewares to enable cors and json body parsing +const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/thoughts" +mongoose.connect(mongoUrl) + app.use(cors()) app.use(express.json()) -// Start defining your routes here +const thoughtSchema = new mongoose.Schema({ + _id: String, + message: { + type: String, + minlength: 5, + maxlength: 140}, + hearts: Number, + createdAt: { + type: Date, + default: Date.now + }, +}) + +const Thought = mongoose.model("Thought", thoughtSchema) + +if (process.env.RESET_DB) { + const seedDatabase = async () => { + await Thought.deleteMany({}) + thoughtsList.forEach(thought => { + new Thought(thought).save() + }) + } + seedDatabase() +} + +// Start defining routes here app.get("/", (req, res) => { const endpoints = listEndpoints(app) res.json({ From ef7a9f5822366027d2c118fedda6192b4c755503 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Wed, 4 Jun 2025 23:14:03 +0200 Subject: [PATCH 08/31] mongoose method to fetch all thoughts --- server.js | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/server.js b/server.js index e58a1fe..69ed35f 100644 --- a/server.js +++ b/server.js @@ -51,17 +51,28 @@ app.get("/", (req, res) => { // Endpoint for all thoughts // Query params to filter -app.get("/thoughts", (req, res) => { - - const { hearts } = req.query - - let heartsFilter = thoughtsList - - if (hearts) { - heartsFilter = heartsFilter.filter(t => t.hearts === +hearts ) +app.get("/thoughts", async (req, res) => { + +try { + if (thoughtsList.length === 0) { + return res.status(404).json({ + success: false, + response: null, + message: "No thoughts available." + }) + } + res.status(200).json({ + success: true, + response: thoughtsList, + message: "All posted thoughts available" + }) + } catch (error) { + res.status(500).json({ + success: false, + response: error, + message: "Failed to fetch thoughts." + }) } - - res.json(heartsFilter) }) // Endpoint for one thought From 83d0416130feb787ddc7ef80dd4ae5dea181d0a1 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Wed, 4 Jun 2025 23:41:03 +0200 Subject: [PATCH 09/31] edit to make frontend fetch work successfully --- server.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/server.js b/server.js index 69ed35f..13fceb6 100644 --- a/server.js +++ b/server.js @@ -52,7 +52,8 @@ app.get("/", (req, res) => { // Endpoint for all thoughts // Query params to filter app.get("/thoughts", async (req, res) => { - + const thoughts = await Thought.find() + try { if (thoughtsList.length === 0) { return res.status(404).json({ @@ -61,11 +62,7 @@ try { message: "No thoughts available." }) } - res.status(200).json({ - success: true, - response: thoughtsList, - message: "All posted thoughts available" - }) + res.status(200).json(thoughts) } catch (error) { res.status(500).json({ success: false, From 39e775d1490efe2c7c86b534a861c93b2c09635c Mon Sep 17 00:00:00 2001 From: Bianka R Date: Thu, 5 Jun 2025 00:14:25 +0200 Subject: [PATCH 10/31] success add mongoose method by id --- server.js | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/server.js b/server.js index 13fceb6..58561b2 100644 --- a/server.js +++ b/server.js @@ -63,6 +63,7 @@ try { }) } res.status(200).json(thoughts) + } catch (error) { res.status(500).json({ success: false, @@ -73,17 +74,24 @@ try { }) // Endpoint for one thought -app.get("/thoughts/:id", (req, res) => { - - console.log("req.params", req.params.id) +app.get("/thoughts/:id", async (req, res) => { - const aThought = thoughtsList.find(t => t._id === req.params.id) + const aThought = await Thought.findById(req.params.id) - if (!aThought) { - return res.status(404).json({ error: "thought not found" }) - } + try { + if (!aThought) { + return res.status(404).json({ error: "thought not found" }) + } + + res.status(200).json(aThought) - res.json(aThought) + } catch (error) { + res.status(500).json({ + success: false, + response: error, + message: "Failed to fetch thoughts." + }) + } }) // Start the server From e9ec654b7cf1156bcc51f26fc8b2bd5ac36360f5 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Thu, 5 Jun 2025 01:10:21 +0200 Subject: [PATCH 11/31] can see successful post path in postman --- server.js | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/server.js b/server.js index 58561b2..851c652 100644 --- a/server.js +++ b/server.js @@ -16,16 +16,18 @@ app.use(cors()) app.use(express.json()) const thoughtSchema = new mongoose.Schema({ - _id: String, message: { + required: true, type: String, minlength: 5, maxlength: 140}, - hearts: Number, + hearts: { + type: Number, + default: 0}, createdAt: { type: Date, default: Date.now - }, + } }) const Thought = mongoose.model("Thought", thoughtSchema) @@ -58,7 +60,7 @@ try { if (thoughtsList.length === 0) { return res.status(404).json({ success: false, - response: null, + response: [], message: "No thoughts available." }) } @@ -89,11 +91,31 @@ app.get("/thoughts/:id", async (req, res) => { res.status(500).json({ success: false, response: error, - message: "Failed to fetch thoughts." + message: "Failed to find this thought." }) } }) +app.post("/thoughts", async (req, res) => { + const { message, hearts, createdAt } = req.body + + try { + const newThought = await new Thought({ message, hearts, createdAt }).save() + + res.status(201).json({ + success: true, + response: newThought, + message: "Thought posted successfully." + }) + } catch (error){ + res.status(500).json({ + success: false, + response: error, + message: "Could not post thought" + }) + } +}) + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) From 4707209e1057af3d52a968b4c633748006fcc17f Mon Sep 17 00:00:00 2001 From: Bianka R Date: Thu, 5 Jun 2025 01:25:20 +0200 Subject: [PATCH 12/31] success delete method by id --- server.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/server.js b/server.js index 851c652..b801177 100644 --- a/server.js +++ b/server.js @@ -116,6 +116,28 @@ app.post("/thoughts", async (req, res) => { } }) +app.delete("/thoughts/:id", async (req, res) => { + + const delThought = await Thought.findByIdAndDelete(req.params.id) + + try { + if (!delThought) { + return res.status(404).json({ error: "This thought not found" }) + } + res.status(201).json({ + success: true, + response: delThought, + message: "Thought deleted successfully." + }) + } catch (error){ + res.status(500).json({ + success: false, + response: error, + message: "Could not delete thought" + }) + } +}) + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) From dd28ad0028343c24dbc2fc176ea738e86e66f5d2 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Thu, 5 Jun 2025 01:39:07 +0200 Subject: [PATCH 13/31] success patch method --- server.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/server.js b/server.js index b801177..1dd236b 100644 --- a/server.js +++ b/server.js @@ -138,6 +138,31 @@ app.delete("/thoughts/:id", async (req, res) => { } }) +app.patch("/thoughts/:id", async (req, res) => { + + const { id } = req.params + const { editThought } = req.body + + const thought = await Thought.findByIdAndUpdate( id, { message: editThought }, { new: true, runValidators: true }) + + try { + if (!thought) { + return res.status(404).json({ error: "This thought not found, no update possible." }) + } + res.status(201).json({ + success: true, + response: thought, + message: "Thought updated successfully." + }) + } catch (error){ + res.status(500).json({ + success: false, + response: error, + message: "Could not update thought" + }) + } +}) + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) From 95075fdce7d393671edc221034490da3ddd8fa40 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Tue, 10 Jun 2025 20:27:59 +0200 Subject: [PATCH 14/31] udpate dotenv to link properly, update post a like fx --- server.js | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/server.js b/server.js index 1dd236b..f3b2ca3 100644 --- a/server.js +++ b/server.js @@ -2,6 +2,7 @@ import cors from "cors" import express from "express" import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" +import dotenv from "dotenv" import thoughtsList from "./data/thoughtsList.json" @@ -9,12 +10,14 @@ import thoughtsList from "./data/thoughtsList.json" const port = process.env.PORT || 8000 const app = express() +dotenv.config() const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/thoughts" mongoose.connect(mongoUrl) app.use(cors()) app.use(express.json()) +// MONGOOSE METHODS const thoughtSchema = new mongoose.Schema({ message: { required: true, @@ -42,7 +45,7 @@ if (process.env.RESET_DB) { seedDatabase() } -// Start defining routes here +// ENDPOINTS DOC app.get("/", (req, res) => { const endpoints = listEndpoints(app) res.json({ @@ -51,8 +54,7 @@ app.get("/", (req, res) => { }) }) -// Endpoint for all thoughts -// Query params to filter +// GET ALL THOUGHTS app.get("/thoughts", async (req, res) => { const thoughts = await Thought.find() @@ -64,7 +66,11 @@ try { message: "No thoughts available." }) } - res.status(200).json(thoughts) + res.status(200).json({ + success: true, + response: thoughts, + message: "thoughts available." + }) } catch (error) { res.status(500).json({ @@ -75,7 +81,7 @@ try { } }) -// Endpoint for one thought +// GET ONE THOUGHT app.get("/thoughts/:id", async (req, res) => { const aThought = await Thought.findById(req.params.id) @@ -96,6 +102,7 @@ app.get("/thoughts/:id", async (req, res) => { } }) +// POST THOUGHT app.post("/thoughts", async (req, res) => { const { message, hearts, createdAt } = req.body @@ -116,6 +123,7 @@ app.post("/thoughts", async (req, res) => { } }) +// DELETE ONE THOUGHT app.delete("/thoughts/:id", async (req, res) => { const delThought = await Thought.findByIdAndDelete(req.params.id) @@ -138,6 +146,7 @@ app.delete("/thoughts/:id", async (req, res) => { } }) +// UPDATE THOUGHT app.patch("/thoughts/:id", async (req, res) => { const { id } = req.params @@ -163,6 +172,31 @@ app.patch("/thoughts/:id", async (req, res) => { } }) +// POST A LIKE +app.post("/thoughts/:id/like", async (req, res) => { + + const { id } = req.params + + const thought = await Thought.findByIdAndUpdate( id, { $inc: { hearts: 1 } }, { new: true, runValidators: true }) + + try { + if (!thought) { + return res.status(404).json({ error: "This thought not found, no update possible." }) + } + res.status(201).json({ + success: true, + response: thought, + message: "New like added." + }) + } catch (error){ + res.status(500).json({ + success: false, + response: error, + message: "Could not update likes." + }) + } +}) + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) From caeb78f9581b242f2dc2df2387d58791e03810ff Mon Sep 17 00:00:00 2001 From: Bianka R Date: Tue, 10 Jun 2025 23:15:26 +0200 Subject: [PATCH 15/31] fix _id path for post a like --- server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index f3b2ca3..448bf51 100644 --- a/server.js +++ b/server.js @@ -175,9 +175,9 @@ app.patch("/thoughts/:id", async (req, res) => { // POST A LIKE app.post("/thoughts/:id/like", async (req, res) => { - const { id } = req.params + const { _id } = req.params - const thought = await Thought.findByIdAndUpdate( id, { $inc: { hearts: 1 } }, { new: true, runValidators: true }) + const thought = await Thought.findByIdAndUpdate( _id, { $inc: { hearts: 1 } }, { new: true, runValidators: true }) try { if (!thought) { From fcf4ff3c048acee83c2ff90174e347e8a4c57963 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Tue, 10 Jun 2025 23:54:22 +0200 Subject: [PATCH 16/31] update await fx inside of try block --- server.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/server.js b/server.js index 448bf51..7128c9f 100644 --- a/server.js +++ b/server.js @@ -84,9 +84,9 @@ try { // GET ONE THOUGHT app.get("/thoughts/:id", async (req, res) => { - const aThought = await Thought.findById(req.params.id) - try { + const aThought = await Thought.findById(req.params.id) + if (!aThought) { return res.status(404).json({ error: "thought not found" }) } @@ -126,9 +126,9 @@ app.post("/thoughts", async (req, res) => { // DELETE ONE THOUGHT app.delete("/thoughts/:id", async (req, res) => { - const delThought = await Thought.findByIdAndDelete(req.params.id) - try { + const delThought = await Thought.findByIdAndDelete(req.params.id) + if (!delThought) { return res.status(404).json({ error: "This thought not found" }) } @@ -152,9 +152,9 @@ app.patch("/thoughts/:id", async (req, res) => { const { id } = req.params const { editThought } = req.body - const thought = await Thought.findByIdAndUpdate( id, { message: editThought }, { new: true, runValidators: true }) - try { + const thought = await Thought.findByIdAndUpdate( id, { message: editThought }, { new: true, runValidators: true }) + if (!thought) { return res.status(404).json({ error: "This thought not found, no update possible." }) } @@ -177,9 +177,9 @@ app.post("/thoughts/:id/like", async (req, res) => { const { _id } = req.params - const thought = await Thought.findByIdAndUpdate( _id, { $inc: { hearts: 1 } }, { new: true, runValidators: true }) - try { + const thought = await Thought.findByIdAndUpdate( _id, { $inc: { hearts: 1 } }, { new: true, runValidators: true }) + if (!thought) { return res.status(404).json({ error: "This thought not found, no update possible." }) } From ff9bd4eb6ae5d94d6b830280e3f04e0d5718d3ff Mon Sep 17 00:00:00 2001 From: Bianka R Date: Wed, 11 Jun 2025 00:20:52 +0200 Subject: [PATCH 17/31] update id path again, for real? --- server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 7128c9f..93f59ff 100644 --- a/server.js +++ b/server.js @@ -175,10 +175,10 @@ app.patch("/thoughts/:id", async (req, res) => { // POST A LIKE app.post("/thoughts/:id/like", async (req, res) => { - const { _id } = req.params + const { id } = req.params try { - const thought = await Thought.findByIdAndUpdate( _id, { $inc: { hearts: 1 } }, { new: true, runValidators: true }) + const thought = await Thought.findByIdAndUpdate( id, { $inc: { hearts: 1 } }, { new: true, runValidators: true }) if (!thought) { return res.status(404).json({ error: "This thought not found, no update possible." }) From 841e7e393a5d1eb717e57ec450c7dc1e68b04912 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Mon, 16 Jun 2025 12:51:12 +0200 Subject: [PATCH 18/31] create user, login user paths work, codecleanup --- .gitignore | 3 +- models/Thought.js | 18 +++++++ models/User.js | 25 ++++++++++ package.json | 2 + server.js | 122 ++++++++++++++++++++++++++++++---------------- 5 files changed, 126 insertions(+), 44 deletions(-) create mode 100644 models/Thought.js create mode 100644 models/User.js diff --git a/.gitignore b/.gitignore index f1ff414..7bfe6e0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ node_modules .env.development.local .env.test.local .env.production.local -package-lock.json \ No newline at end of file +package-lock.json +todo.md \ No newline at end of file diff --git a/models/Thought.js b/models/Thought.js new file mode 100644 index 0000000..28418e0 --- /dev/null +++ b/models/Thought.js @@ -0,0 +1,18 @@ +import mongoose from "mongoose"; + +const thoughtSchema = new mongoose.Schema({ + message: { + required: true, + type: String, + minlength: 5, + maxlength: 140}, + hearts: { + type: Number, + default: 0}, + createdAt: { + type: Date, + default: Date.now + } +}) + +export const Thought = mongoose.model("Thought", thoughtSchema) \ No newline at end of file diff --git a/models/User.js b/models/User.js new file mode 100644 index 0000000..6142c87 --- /dev/null +++ b/models/User.js @@ -0,0 +1,25 @@ +import mongoose from "mongoose" +import crypto from "crypto" + +const userSchema = new mongoose.Schema({ + username: { + type: String, + unique: true, + required: true, + minlength: 2, + }, + email: { + type: String, + unique: true, + }, + password: { + type: String, + required: true, + }, + accessToken: { + type: String, + default: () => crypto.randomBytes(128).toString("hex"), + } +}) + +export const User = mongoose.model("User", userSchema) \ No newline at end of file diff --git a/package.json b/package.json index a25852d..2339c52 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,8 @@ "@babel/core": "^7.27.3", "@babel/node": "^7.27.1", "@babel/preset-env": "^7.27.2", + "bcrypt-nodejs": "^0.0.3", + "bcryptjs": "^3.0.2", "cors": "^2.8.5", "dotenv": "^16.5.0", "express": "^4.21.2", diff --git a/server.js b/server.js index 93f59ff..9f0159f 100644 --- a/server.js +++ b/server.js @@ -3,7 +3,9 @@ import express from "express" import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" import dotenv from "dotenv" - +import bcrypt from "bcryptjs" +import { User } from "./models/User" +import { Thought } from "./models/Thought" import thoughtsList from "./data/thoughtsList.json" // CONNECTION SETTINGS @@ -11,30 +13,84 @@ const port = process.env.PORT || 8000 const app = express() dotenv.config() -const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/thoughts" -mongoose.connect(mongoUrl) +const mongoUrl = process.env.MONGO_URL || "mongodb://localhost:27017/thoughts" +console.log("🔌 Connecting to MongoDB at:", mongoUrl) + +mongoose.connect(mongoUrl, { + autoIndex: true +}) +.then(() => { + console.log("🌱 Connected to DB:", mongoose.connection.db.databaseName); +}) +.catch((err) => { + console.error("❌ MongoDB connection error:", err) +}) app.use(cors()) app.use(express.json()) -// MONGOOSE METHODS -const thoughtSchema = new mongoose.Schema({ - message: { - required: true, - type: String, - minlength: 5, - maxlength: 140}, - hearts: { - type: Number, - default: 0}, - createdAt: { - type: Date, - default: Date.now +// MIDDLEWARE TO AUTH +const authenticateUser = async (req, res, next) => { + const user = await User.findOne({accessToken: req.header("Authorization")}) + if(user) { + req.user = user + next() + } else { + res.status(401).json({loggedOut: true}) } +} + +// REGISTRATION ENDPOINT - ASSIGN ENCRYPTED TOKEN (CREATE) +app.post("/users", async (req, res) => { + try { + const { username, email, password } = req.body + if (!username || !password) { + return res.status(400).json({ error: "username and password are required"}) + } + + const salt = bcrypt.genSaltSync() + const user = new User({ username, email, password: bcrypt.hashSync(password, salt) }) + await user.save() + + res.status(200).json({ + message: "Signup success", + success: true, + id: user._id, + accessToken: user.accessToken}) + } catch(err) { + console.error(err) + res.status(400).json({ + message: "Could not create user", + errors: err.errors}) + } }) -const Thought = mongoose.model("Thought", thoughtSchema) +// LOGIN ENDPOINT (FINDS USER) +app.post("/login", async (req, res) => { + try { + const { username, password } = req.body + const user = await User.findOne({ username: req.body.username }) + if (!user) { + return res.status(404).json({ + success: false, + message: "User does not exist"}) + } + + if (user && bcrypt.compareSync(req.body.password, user.password)) { + res.status(201).json({ + success: true, + message: "User logged in", + userId: user.id, + accessToken: user.accessToken}) + }} catch(err) { + res.status(400).json({ + success: false, + notFound: true}) + } +}) + +// SEED DATABASE if (process.env.RESET_DB) { const seedDatabase = async () => { await Thought.deleteMany({}) @@ -56,9 +112,9 @@ app.get("/", (req, res) => { // GET ALL THOUGHTS app.get("/thoughts", async (req, res) => { + + try { const thoughts = await Thought.find() - -try { if (thoughtsList.length === 0) { return res.status(404).json({ success: false, @@ -81,27 +137,6 @@ try { } }) -// GET ONE THOUGHT -app.get("/thoughts/:id", async (req, res) => { - - try { - const aThought = await Thought.findById(req.params.id) - - if (!aThought) { - return res.status(404).json({ error: "thought not found" }) - } - - res.status(200).json(aThought) - - } catch (error) { - res.status(500).json({ - success: false, - response: error, - message: "Failed to find this thought." - }) - } -}) - // POST THOUGHT app.post("/thoughts", async (req, res) => { const { message, hearts, createdAt } = req.body @@ -124,7 +159,7 @@ app.post("/thoughts", async (req, res) => { }) // DELETE ONE THOUGHT -app.delete("/thoughts/:id", async (req, res) => { +app.delete("/thoughts/:id", authenticateUser, async (req, res) => { try { const delThought = await Thought.findByIdAndDelete(req.params.id) @@ -146,8 +181,8 @@ app.delete("/thoughts/:id", async (req, res) => { } }) -// UPDATE THOUGHT -app.patch("/thoughts/:id", async (req, res) => { +// UPDATE/EDIT THOUGHT +app.patch("/thoughts/:id", authenticateUser, async (req, res) => { const { id } = req.params const { editThought } = req.body @@ -197,6 +232,7 @@ app.post("/thoughts/:id/like", async (req, res) => { } }) + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) From c476392c0de7e876fe2e6c52985141214ccccdfe Mon Sep 17 00:00:00 2001 From: Bianka R Date: Mon, 16 Jun 2025 15:15:08 +0200 Subject: [PATCH 19/31] add authRouter for user and login --- models/User.js | 3 ++ routes/authRouter.js | 90 ++++++++++++++++++++++++++++++++++++++++ routes/thoughtsRouter.js | 0 server.js | 65 ++--------------------------- 4 files changed, 96 insertions(+), 62 deletions(-) create mode 100644 routes/authRouter.js create mode 100644 routes/thoughtsRouter.js diff --git a/models/User.js b/models/User.js index 6142c87..c361cae 100644 --- a/models/User.js +++ b/models/User.js @@ -7,10 +7,13 @@ const userSchema = new mongoose.Schema({ unique: true, required: true, minlength: 2, + trim: true, }, email: { type: String, unique: true, + sparse: true, + trim: true, }, password: { type: String, diff --git a/routes/authRouter.js b/routes/authRouter.js new file mode 100644 index 0000000..4ae2c0b --- /dev/null +++ b/routes/authRouter.js @@ -0,0 +1,90 @@ +import bcrypt from "bcryptjs" +import { User } from "../models/User" +import { Router } from "express" + +const authRouter = Router() + +// REGISTRATION ENDPOINT - ASSIGN ENCRYPTED TOKEN (CREATE) +authRouter.post("/", async (req, res) => { + try { + const { username, email, password } = req.body + if (!username || !password) { + return res.status(400).json({ error: "username and password are required"}) + } + + const salt = bcrypt.genSaltSync() + const user = new User({ + username, + email: email || null , + password: bcrypt.hashSync(password, salt) }) + + await user.save() + + res.status(200).json({ + message: "Signup success", + success: true, + id: user._id, + accessToken: user.accessToken}) + + } catch(err) { + if (err.code === 11000) { + const field = Object.keys(err.keyPattern)[0] + res.status(409).json({ + success: false, + message: `A user with that ${field} already exists.`, + }) + } else { + console.error(err) + res.status(400).json({ + success: false, + message: "Could not create user", + errors: err.errors + }) + } + } +}) + +// LOGIN ENDPOINT (FINDS USER) +authRouter.post("/login", async (req, res) => { + try { + const { username, password } = req.body + + const user = await User.findOne({ username: req.body.username }) + if (!user) { + return res.status(404).json({ + success: false, + message: "User does not exist"}) + } + + if (user && bcrypt.compareSync(req.body.password, user.password)) { + res.status(201).json({ + success: true, + message: "User successfully logged in", + userId: user.id, + accessToken: user.accessToken + }) + } else { + res.status(401).json({ + success: false, + message: "Invalid password" + }) + + }} catch(err) { + res.status(400).json({ + success: false, + notFound: true}) + } +}) + +// MIDDLEWARE TO AUTH +export const authenticateUser = async (req, res, next) => { + const user = await User.findOne({accessToken: req.header("Authorization")}) + if(user) { + req.user = user + next() + } else { + res.status(401).json({loggedOut: true}) + } +} + +export default authRouter \ No newline at end of file diff --git a/routes/thoughtsRouter.js b/routes/thoughtsRouter.js new file mode 100644 index 0000000..e69de29 diff --git a/server.js b/server.js index 9f0159f..49116ec 100644 --- a/server.js +++ b/server.js @@ -3,10 +3,9 @@ import express from "express" import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" import dotenv from "dotenv" -import bcrypt from "bcryptjs" -import { User } from "./models/User" import { Thought } from "./models/Thought" import thoughtsList from "./data/thoughtsList.json" +import authRouter, { authenticateUser } from "./routes/authRouter" // CONNECTION SETTINGS const port = process.env.PORT || 8000 @@ -29,66 +28,8 @@ mongoose.connect(mongoUrl, { app.use(cors()) app.use(express.json()) -// MIDDLEWARE TO AUTH -const authenticateUser = async (req, res, next) => { - const user = await User.findOne({accessToken: req.header("Authorization")}) - if(user) { - req.user = user - next() - } else { - res.status(401).json({loggedOut: true}) - } -} - -// REGISTRATION ENDPOINT - ASSIGN ENCRYPTED TOKEN (CREATE) -app.post("/users", async (req, res) => { - try { - const { username, email, password } = req.body - if (!username || !password) { - return res.status(400).json({ error: "username and password are required"}) - } - - const salt = bcrypt.genSaltSync() - const user = new User({ username, email, password: bcrypt.hashSync(password, salt) }) - await user.save() - - res.status(200).json({ - message: "Signup success", - success: true, - id: user._id, - accessToken: user.accessToken}) - } catch(err) { - console.error(err) - res.status(400).json({ - message: "Could not create user", - errors: err.errors}) - } -}) - -// LOGIN ENDPOINT (FINDS USER) -app.post("/login", async (req, res) => { - try { - const { username, password } = req.body - - const user = await User.findOne({ username: req.body.username }) - if (!user) { - return res.status(404).json({ - success: false, - message: "User does not exist"}) - } - - if (user && bcrypt.compareSync(req.body.password, user.password)) { - res.status(201).json({ - success: true, - message: "User logged in", - userId: user.id, - accessToken: user.accessToken}) - }} catch(err) { - res.status(400).json({ - success: false, - notFound: true}) - } -}) +// MOUNT AUTH ROUTER +app.use("/users", authRouter) // SEED DATABASE if (process.env.RESET_DB) { From 78e1229bd497ea9aa7b4188691b7933e55315ea9 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Tue, 17 Jun 2025 09:42:21 +0200 Subject: [PATCH 20/31] new routes, trying to fix .env, add render link --- .gitignore | 2 + models/Thought.js | 5 +++ pull_request_template.md | 4 +- routers/authRouter.js | 90 +++++++++++++++++++++++++++++++++++++++ routers/thoughtsRouter.js | 55 ++++++++++++++++++++++++ server.js | 55 ++---------------------- 6 files changed, 159 insertions(+), 52 deletions(-) create mode 100644 routers/authRouter.js create mode 100644 routers/thoughtsRouter.js diff --git a/.gitignore b/.gitignore index 7bfe6e0..f727795 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ node_modules .DS_Store .env +.env.dev +.env.prod .env.local .env.development.local .env.test.local diff --git a/models/Thought.js b/models/Thought.js index 28418e0..75a6a58 100644 --- a/models/Thought.js +++ b/models/Thought.js @@ -12,6 +12,11 @@ const thoughtSchema = new mongoose.Schema({ createdAt: { type: Date, default: Date.now + }, + createdBy: { + type: mongoose.Schema.Types.ObjectId, + ref: "User", + default: null, } }) diff --git a/pull_request_template.md b/pull_request_template.md index fb9fdc3..e3a7b29 100644 --- a/pull_request_template.md +++ b/pull_request_template.md @@ -1 +1,3 @@ -Please include your Render link here. \ No newline at end of file +Please include your Render link here: + +https://js-project-api-b8sd.onrender.com diff --git a/routers/authRouter.js b/routers/authRouter.js new file mode 100644 index 0000000..4ae2c0b --- /dev/null +++ b/routers/authRouter.js @@ -0,0 +1,90 @@ +import bcrypt from "bcryptjs" +import { User } from "../models/User" +import { Router } from "express" + +const authRouter = Router() + +// REGISTRATION ENDPOINT - ASSIGN ENCRYPTED TOKEN (CREATE) +authRouter.post("/", async (req, res) => { + try { + const { username, email, password } = req.body + if (!username || !password) { + return res.status(400).json({ error: "username and password are required"}) + } + + const salt = bcrypt.genSaltSync() + const user = new User({ + username, + email: email || null , + password: bcrypt.hashSync(password, salt) }) + + await user.save() + + res.status(200).json({ + message: "Signup success", + success: true, + id: user._id, + accessToken: user.accessToken}) + + } catch(err) { + if (err.code === 11000) { + const field = Object.keys(err.keyPattern)[0] + res.status(409).json({ + success: false, + message: `A user with that ${field} already exists.`, + }) + } else { + console.error(err) + res.status(400).json({ + success: false, + message: "Could not create user", + errors: err.errors + }) + } + } +}) + +// LOGIN ENDPOINT (FINDS USER) +authRouter.post("/login", async (req, res) => { + try { + const { username, password } = req.body + + const user = await User.findOne({ username: req.body.username }) + if (!user) { + return res.status(404).json({ + success: false, + message: "User does not exist"}) + } + + if (user && bcrypt.compareSync(req.body.password, user.password)) { + res.status(201).json({ + success: true, + message: "User successfully logged in", + userId: user.id, + accessToken: user.accessToken + }) + } else { + res.status(401).json({ + success: false, + message: "Invalid password" + }) + + }} catch(err) { + res.status(400).json({ + success: false, + notFound: true}) + } +}) + +// MIDDLEWARE TO AUTH +export const authenticateUser = async (req, res, next) => { + const user = await User.findOne({accessToken: req.header("Authorization")}) + if(user) { + req.user = user + next() + } else { + res.status(401).json({loggedOut: true}) + } +} + +export default authRouter \ No newline at end of file diff --git a/routers/thoughtsRouter.js b/routers/thoughtsRouter.js new file mode 100644 index 0000000..3cc6c06 --- /dev/null +++ b/routers/thoughtsRouter.js @@ -0,0 +1,55 @@ +import { Router } from "express" +import { Thought } from "../models/Thought" +import { authenticateUser } from "./authRouter" + +const thoughtsRouter = Router() + +// GET ALL THOUGHTS +thoughtsRouter.get("/thoughts", async (req, res) => { + + try { + const thoughts = await Thought.find() + if (Thought.length === 0) { + return res.status(404).json({ + success: false, + response: [], + message: "No thoughts available." + }) + } + res.status(200).json({ + success: true, + response: thoughts, + message: "thoughts available." + }) + + } catch (error) { + res.status(500).json({ + success: false, + response: error, + message: "Failed to fetch thoughts." + }) + } +}) + +// POST THOUGHT +thoughtsRouter.post("/thoughts", authenticateUser, async (req, res) => { + const { message, hearts, createdAt } = req.body + + try { + const newThought = await new Thought({ message, hearts, createdAt, createdBy: req.user._id }).save() + + res.status(201).json({ + success: true, + response: newThought, + message: "Thought posted successfully." + }) + } catch (error){ + res.status(500).json({ + success: false, + response: error, + message: "Could not post thought" + }) + } +}) + +export default thoughtsRouter \ No newline at end of file diff --git a/server.js b/server.js index 49116ec..8d2e3f5 100644 --- a/server.js +++ b/server.js @@ -1,11 +1,12 @@ import cors from "cors" +import dotenv from "dotenv" import express from "express" import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" -import dotenv from "dotenv" -import { Thought } from "./models/Thought" + import thoughtsList from "./data/thoughtsList.json" -import authRouter, { authenticateUser } from "./routes/authRouter" +import { Thought } from "./models/Thought" +import authRouter, { authenticateUser } from "./routers/authRouter" // CONNECTION SETTINGS const port = process.env.PORT || 8000 @@ -51,54 +52,6 @@ app.get("/", (req, res) => { }) }) -// GET ALL THOUGHTS -app.get("/thoughts", async (req, res) => { - - try { - const thoughts = await Thought.find() - if (thoughtsList.length === 0) { - return res.status(404).json({ - success: false, - response: [], - message: "No thoughts available." - }) - } - res.status(200).json({ - success: true, - response: thoughts, - message: "thoughts available." - }) - - } catch (error) { - res.status(500).json({ - success: false, - response: error, - message: "Failed to fetch thoughts." - }) - } -}) - -// POST THOUGHT -app.post("/thoughts", async (req, res) => { - const { message, hearts, createdAt } = req.body - - try { - const newThought = await new Thought({ message, hearts, createdAt }).save() - - res.status(201).json({ - success: true, - response: newThought, - message: "Thought posted successfully." - }) - } catch (error){ - res.status(500).json({ - success: false, - response: error, - message: "Could not post thought" - }) - } -}) - // DELETE ONE THOUGHT app.delete("/thoughts/:id", authenticateUser, async (req, res) => { From 97a6ed85ecd2aec7bce082bf86a0802697f7dab2 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Tue, 17 Jun 2025 10:25:51 +0200 Subject: [PATCH 21/31] Remove .env* from version control --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f727795..533f873 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ node_modules .DS_Store -.env +.env* .env.dev .env.prod .env.local From dc500ed42cbc4a12605f269f66e9d8516bc4f99d Mon Sep 17 00:00:00 2001 From: Bianka R Date: Tue, 17 Jun 2025 13:28:40 +0200 Subject: [PATCH 22/31] fix double routes folder? --- routers/authRouter.js | 90 --------------------------------------- routers/thoughtsRouter.js | 55 ------------------------ routes/thoughtsRouter.js | 56 ++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 145 deletions(-) delete mode 100644 routers/authRouter.js delete mode 100644 routers/thoughtsRouter.js diff --git a/routers/authRouter.js b/routers/authRouter.js deleted file mode 100644 index 4ae2c0b..0000000 --- a/routers/authRouter.js +++ /dev/null @@ -1,90 +0,0 @@ -import bcrypt from "bcryptjs" -import { User } from "../models/User" -import { Router } from "express" - -const authRouter = Router() - -// REGISTRATION ENDPOINT - ASSIGN ENCRYPTED TOKEN (CREATE) -authRouter.post("/", async (req, res) => { - try { - const { username, email, password } = req.body - if (!username || !password) { - return res.status(400).json({ error: "username and password are required"}) - } - - const salt = bcrypt.genSaltSync() - const user = new User({ - username, - email: email || null , - password: bcrypt.hashSync(password, salt) }) - - await user.save() - - res.status(200).json({ - message: "Signup success", - success: true, - id: user._id, - accessToken: user.accessToken}) - - } catch(err) { - if (err.code === 11000) { - const field = Object.keys(err.keyPattern)[0] - res.status(409).json({ - success: false, - message: `A user with that ${field} already exists.`, - }) - } else { - console.error(err) - res.status(400).json({ - success: false, - message: "Could not create user", - errors: err.errors - }) - } - } -}) - -// LOGIN ENDPOINT (FINDS USER) -authRouter.post("/login", async (req, res) => { - try { - const { username, password } = req.body - - const user = await User.findOne({ username: req.body.username }) - if (!user) { - return res.status(404).json({ - success: false, - message: "User does not exist"}) - } - - if (user && bcrypt.compareSync(req.body.password, user.password)) { - res.status(201).json({ - success: true, - message: "User successfully logged in", - userId: user.id, - accessToken: user.accessToken - }) - } else { - res.status(401).json({ - success: false, - message: "Invalid password" - }) - - }} catch(err) { - res.status(400).json({ - success: false, - notFound: true}) - } -}) - -// MIDDLEWARE TO AUTH -export const authenticateUser = async (req, res, next) => { - const user = await User.findOne({accessToken: req.header("Authorization")}) - if(user) { - req.user = user - next() - } else { - res.status(401).json({loggedOut: true}) - } -} - -export default authRouter \ No newline at end of file diff --git a/routers/thoughtsRouter.js b/routers/thoughtsRouter.js deleted file mode 100644 index 3cc6c06..0000000 --- a/routers/thoughtsRouter.js +++ /dev/null @@ -1,55 +0,0 @@ -import { Router } from "express" -import { Thought } from "../models/Thought" -import { authenticateUser } from "./authRouter" - -const thoughtsRouter = Router() - -// GET ALL THOUGHTS -thoughtsRouter.get("/thoughts", async (req, res) => { - - try { - const thoughts = await Thought.find() - if (Thought.length === 0) { - return res.status(404).json({ - success: false, - response: [], - message: "No thoughts available." - }) - } - res.status(200).json({ - success: true, - response: thoughts, - message: "thoughts available." - }) - - } catch (error) { - res.status(500).json({ - success: false, - response: error, - message: "Failed to fetch thoughts." - }) - } -}) - -// POST THOUGHT -thoughtsRouter.post("/thoughts", authenticateUser, async (req, res) => { - const { message, hearts, createdAt } = req.body - - try { - const newThought = await new Thought({ message, hearts, createdAt, createdBy: req.user._id }).save() - - res.status(201).json({ - success: true, - response: newThought, - message: "Thought posted successfully." - }) - } catch (error){ - res.status(500).json({ - success: false, - response: error, - message: "Could not post thought" - }) - } -}) - -export default thoughtsRouter \ No newline at end of file diff --git a/routes/thoughtsRouter.js b/routes/thoughtsRouter.js index e69de29..07916a9 100644 --- a/routes/thoughtsRouter.js +++ b/routes/thoughtsRouter.js @@ -0,0 +1,56 @@ +import { Router } from "express" + +import { Thought } from "../models/Thought" +import { authenticateUser } from "./authRouter" + +const thoughtsRouter = Router() + +// GET ALL THOUGHTS +thoughtsRouter.get("/thoughts", async (req, res) => { + + try { + const thoughts = await Thought.find() + if (Thought.length === 0) { + return res.status(404).json({ + success: false, + response: [], + message: "No thoughts available." + }) + } + res.status(200).json({ + success: true, + response: thoughts, + message: "thoughts available." + }) + + } catch (error) { + res.status(500).json({ + success: false, + response: error, + message: "Failed to fetch thoughts." + }) + } +}) + +// POST THOUGHT +thoughtsRouter.post("/thoughts", authenticateUser, async (req, res) => { + const { message, hearts, createdAt } = req.body + + try { + const newThought = await new Thought({ message, hearts, createdAt, createdBy: req.user._id }).save() + + res.status(201).json({ + success: true, + response: newThought, + message: "Thought posted successfully." + }) + } catch (error){ + res.status(500).json({ + success: false, + response: error, + message: "Could not post thought" + }) + } +}) + +export default thoughtsRouter From e76e51106b19a089652e0386c8bf694520cdc158 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Tue, 17 Jun 2025 13:58:24 +0200 Subject: [PATCH 23/31] update error handling for authentication --- routes/authRouter.js | 35 ++++++++++++++++++++++++++++------- server.js | 6 +++++- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/routes/authRouter.js b/routes/authRouter.js index 4ae2c0b..ee92d81 100644 --- a/routes/authRouter.js +++ b/routes/authRouter.js @@ -1,7 +1,8 @@ import bcrypt from "bcryptjs" -import { User } from "../models/User" import { Router } from "express" +import { User } from "../models/User" + const authRouter = Router() // REGISTRATION ENDPOINT - ASSIGN ENCRYPTED TOKEN (CREATE) @@ -78,12 +79,32 @@ authRouter.post("/login", async (req, res) => { // MIDDLEWARE TO AUTH export const authenticateUser = async (req, res, next) => { - const user = await User.findOne({accessToken: req.header("Authorization")}) - if(user) { - req.user = user - next() - } else { - res.status(401).json({loggedOut: true}) + try { + + const token = req.header("Authorization") + if (!token) { + return res.status(401).json({ + success: false, + message: "Access token missing. Please login to continue." + }) + } + + const user = await User.findOne({ accessToken: token }) + if(!user) { + return res.status(401).json({ + success: false, + message: "Invalid token. Please login in again.", + loggedOut: true + }) + } + req.user = user + next() + } catch (err) { + console.error("Authentication error", err) + res.status(500).json({ + success: false, + message: "Server error during authentication." + }) } } diff --git a/server.js b/server.js index 8d2e3f5..8059961 100644 --- a/server.js +++ b/server.js @@ -6,7 +6,8 @@ import mongoose from "mongoose" import thoughtsList from "./data/thoughtsList.json" import { Thought } from "./models/Thought" -import authRouter, { authenticateUser } from "./routers/authRouter" +import authRouter, { authenticateUser } from "./routes/authRouter" +import thoughtsRouter from "./routes/thoughtsRouter" // CONNECTION SETTINGS const port = process.env.PORT || 8000 @@ -32,6 +33,9 @@ app.use(express.json()) // MOUNT AUTH ROUTER app.use("/users", authRouter) +// MOUNT THOUGHTS ROUTER +app.use("/", thoughtsRouter) + // SEED DATABASE if (process.env.RESET_DB) { const seedDatabase = async () => { From 32071343b266204a8b1c592df8fcd23edf1683dd Mon Sep 17 00:00:00 2001 From: Bianka R Date: Tue, 17 Jun 2025 14:37:11 +0200 Subject: [PATCH 24/31] create users, auth, thoughts routes --- routes/authRouter.js | 2 +- routes/thoughtsRouter.js | 81 +++++++++++++++++++++++++++++++++++++++ routes/usersRouter.js | 31 +++++++++++++++ server.js | 83 ++-------------------------------------- 4 files changed, 117 insertions(+), 80 deletions(-) create mode 100644 routes/usersRouter.js diff --git a/routes/authRouter.js b/routes/authRouter.js index ee92d81..a024907 100644 --- a/routes/authRouter.js +++ b/routes/authRouter.js @@ -6,7 +6,7 @@ import { User } from "../models/User" const authRouter = Router() // REGISTRATION ENDPOINT - ASSIGN ENCRYPTED TOKEN (CREATE) -authRouter.post("/", async (req, res) => { +authRouter.post("/register", async (req, res) => { try { const { username, email, password } = req.body if (!username || !password) { diff --git a/routes/thoughtsRouter.js b/routes/thoughtsRouter.js index 07916a9..6fe5326 100644 --- a/routes/thoughtsRouter.js +++ b/routes/thoughtsRouter.js @@ -53,4 +53,85 @@ thoughtsRouter.post("/thoughts", authenticateUser, async (req, res) => { } }) + +// DELETE THOUGHT +thoughtsRouter.delete("/:id", authenticateUser, async (req, res) => { + + try { + const delThought = await Thought.findByIdAndDelete({ _id: req.params.id, createdBy: req.user._id }) + + if (!delThought) { + return res.status(404).json({ + success: false, + message: "Not found or authorized" + }) + } + res.status(200).json({ + success: true, + response: delThought, + message: "Thought deleted successfully." + }) + } catch (error){ + res.status(500).json({ + success: false, + response: error, + message: "Could not delete thought" + }) + } +}) + +// UPDATE/EDIT THOUGHT +thoughtsRouter.patch("/:id", authenticateUser, async (req, res) => { + const { editThought } = req.body + + try { + const thought = await Thought.findByIdAndUpdate({ _id: req.params.id, createdBy: req.user._id }, + { message: editThought }, + { new: true, runValidators: true }) + + if (!thought) { + return res.status(404).json({ + success: false, + message: "Not found, no update possible." + }) + } + res.status(200).json({ + success: true, + response: thought, + message: "Thought updated successfully." + }) + } catch (error){ + res.status(500).json({ + success: false, + response: error, + message: "Could not update thought" + }) + } +}) + +// POST A LIKE +thoughtsRouter.post("/:id/like", async (req, res) => { + + const { id } = req.params + + try { + const thought = await Thought.findByIdAndUpdate( id, { $inc: { hearts: 1 } }, { new: true, runValidators: true }) + + if (!thought) { + return res.status(404).json({ error: "This thought not found, no update possible." }) + } + res.status(201).json({ + success: true, + response: thought, + message: "New like added." + }) + } catch (error){ + res.status(500).json({ + success: false, + response: error, + message: "Could not update likes." + }) + } +}) + export default thoughtsRouter diff --git a/routes/usersRouter.js b/routes/usersRouter.js new file mode 100644 index 0000000..a809078 --- /dev/null +++ b/routes/usersRouter.js @@ -0,0 +1,31 @@ +import { Router } from "express" + +import { Thought } from "../models/Thought" +import { authenticateUser } from "./authRouter" + +const usersRouter = Router() + +// GET USER DETAILS +usersRouter.get("/me", authenticateUser, async (req, res) => { + const user = req.user + res.json({ + success: true, + user: { + username: user.username, + email: user.email, + id: user.id + } + }) +}) + +// GET USER THOUGHTS +usersRouter.get("/my-thoughts", authenticateUser, async (req, res) => { + const userId = req.user._id + const thoughts = await Thought.find({ createdBy: userId }) + res.json({ + success: true, + response: thoughts + }) +}) + +export default usersRouter \ No newline at end of file diff --git a/server.js b/server.js index 8059961..2f14afc 100644 --- a/server.js +++ b/server.js @@ -30,11 +30,10 @@ mongoose.connect(mongoUrl, { app.use(cors()) app.use(express.json()) -// MOUNT AUTH ROUTER -app.use("/users", authRouter) - -// MOUNT THOUGHTS ROUTER -app.use("/", thoughtsRouter) +// MOUNT ROUTES +app.use("/auth", authRouter) +app.use("/thoughts", thoughtsRouter) +app.use("/users", usersRouter) // SEED DATABASE if (process.env.RESET_DB) { @@ -56,80 +55,6 @@ app.get("/", (req, res) => { }) }) -// DELETE ONE THOUGHT -app.delete("/thoughts/:id", authenticateUser, async (req, res) => { - - try { - const delThought = await Thought.findByIdAndDelete(req.params.id) - - if (!delThought) { - return res.status(404).json({ error: "This thought not found" }) - } - res.status(201).json({ - success: true, - response: delThought, - message: "Thought deleted successfully." - }) - } catch (error){ - res.status(500).json({ - success: false, - response: error, - message: "Could not delete thought" - }) - } -}) - -// UPDATE/EDIT THOUGHT -app.patch("/thoughts/:id", authenticateUser, async (req, res) => { - - const { id } = req.params - const { editThought } = req.body - - try { - const thought = await Thought.findByIdAndUpdate( id, { message: editThought }, { new: true, runValidators: true }) - - if (!thought) { - return res.status(404).json({ error: "This thought not found, no update possible." }) - } - res.status(201).json({ - success: true, - response: thought, - message: "Thought updated successfully." - }) - } catch (error){ - res.status(500).json({ - success: false, - response: error, - message: "Could not update thought" - }) - } -}) - -// POST A LIKE -app.post("/thoughts/:id/like", async (req, res) => { - - const { id } = req.params - - try { - const thought = await Thought.findByIdAndUpdate( id, { $inc: { hearts: 1 } }, { new: true, runValidators: true }) - - if (!thought) { - return res.status(404).json({ error: "This thought not found, no update possible." }) - } - res.status(201).json({ - success: true, - response: thought, - message: "New like added." - }) - } catch (error){ - res.status(500).json({ - success: false, - response: error, - message: "Could not update likes." - }) - } -}) - // Start the server app.listen(port, () => { From a7d145e520eedd26c6a04178ca0c83f3d1a103d3 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Tue, 17 Jun 2025 14:55:22 +0200 Subject: [PATCH 25/31] path fix for thoughts, users path test works --- routes/thoughtsRouter.js | 2 +- server.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/routes/thoughtsRouter.js b/routes/thoughtsRouter.js index 6fe5326..8eeeb23 100644 --- a/routes/thoughtsRouter.js +++ b/routes/thoughtsRouter.js @@ -33,7 +33,7 @@ thoughtsRouter.get("/thoughts", async (req, res) => { }) // POST THOUGHT -thoughtsRouter.post("/thoughts", authenticateUser, async (req, res) => { +thoughtsRouter.post("/", authenticateUser, async (req, res) => { const { message, hearts, createdAt } = req.body try { diff --git a/server.js b/server.js index 2f14afc..6ebc869 100644 --- a/server.js +++ b/server.js @@ -8,6 +8,7 @@ import thoughtsList from "./data/thoughtsList.json" import { Thought } from "./models/Thought" import authRouter, { authenticateUser } from "./routes/authRouter" import thoughtsRouter from "./routes/thoughtsRouter" +import usersRouter from "./routes/usersRouter" // CONNECTION SETTINGS const port = process.env.PORT || 8000 From a0b97df923e04ac8268f1c6e6f830490c1b65d6e Mon Sep 17 00:00:00 2001 From: Bianka R Date: Tue, 17 Jun 2025 15:14:53 +0200 Subject: [PATCH 26/31] update err handling in register --- models/User.js | 9 ++++++++- routes/authRouter.js | 18 ++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/models/User.js b/models/User.js index c361cae..ae29644 100644 --- a/models/User.js +++ b/models/User.js @@ -1,5 +1,5 @@ -import mongoose from "mongoose" import crypto from "crypto" +import mongoose from "mongoose" const userSchema = new mongoose.Schema({ username: { @@ -13,7 +13,14 @@ const userSchema = new mongoose.Schema({ type: String, unique: true, sparse: true, + lowercase: true, trim: true, + validate: { + validator: (email) => { + return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email) + }, + message: props => `${props.value} is not a valid email address!` + } }, password: { type: String, diff --git a/routes/authRouter.js b/routes/authRouter.js index a024907..e3c9f02 100644 --- a/routes/authRouter.js +++ b/routes/authRouter.js @@ -30,18 +30,24 @@ authRouter.post("/register", async (req, res) => { } catch(err) { if (err.code === 11000) { const field = Object.keys(err.keyPattern)[0] - res.status(409).json({ + return res.status(409).json({ success: false, message: `A user with that ${field} already exists.`, }) - } else { - console.error(err) - res.status(400).json({ + } + if (err.errors) { + const validationErrors = Object.values(err.errors).map(e => e.message) + return res.status(400).json({ success: false, - message: "Could not create user", - errors: err.errors + message: "Invalid input", + errors: validationErrors }) } + console.error(err) + res.status(500).json({ + success: false, + message: "Unexpected server error." + }) } }) From 502c2d9c774724bb9954558f695cb5b3ee283fc7 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Tue, 17 Jun 2025 18:09:14 +0200 Subject: [PATCH 27/31] err handling for thoughts path --- routes/thoughtsRouter.js | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/routes/thoughtsRouter.js b/routes/thoughtsRouter.js index 8eeeb23..abc1148 100644 --- a/routes/thoughtsRouter.js +++ b/routes/thoughtsRouter.js @@ -47,7 +47,7 @@ thoughtsRouter.post("/", authenticateUser, async (req, res) => { } catch (error){ res.status(500).json({ success: false, - response: error, + response: error.message, message: "Could not post thought" }) } @@ -74,7 +74,7 @@ thoughtsRouter.delete("/:id", authenticateUser, async (req, res) => { } catch (error){ res.status(500).json({ success: false, - response: error, + error: error.message, message: "Could not delete thought" }) } @@ -83,6 +83,12 @@ thoughtsRouter.delete("/:id", authenticateUser, async (req, res) => { // UPDATE/EDIT THOUGHT thoughtsRouter.patch("/:id", authenticateUser, async (req, res) => { const { editThought } = req.body + if (!editThought || editThought.trim().length === 0) { + return res.status(400).json({ + success: false, + message: "editThought is required to update the post." + }) + } try { const thought = await Thought.findByIdAndUpdate({ _id: req.params.id, createdBy: req.user._id }, @@ -100,11 +106,18 @@ thoughtsRouter.patch("/:id", authenticateUser, async (req, res) => { response: thought, message: "Thought updated successfully." }) - } catch (error){ + } catch (error) { + if (error.name === "ValidationError") { + return res.status(400).json({ + success: false, + errors: error.errors, + message: "Validation failed", + }) + } res.status(500).json({ success: false, - response: error, - message: "Could not update thought" + error: error.message, + message: "Server error - try again later." }) } }) @@ -125,11 +138,18 @@ thoughtsRouter.post("/:id/like", async (req, res) => { response: thought, message: "New like added." }) - } catch (error){ + } catch (error) { + if (error.name === "ValidationError") { + return res.status(400).json({ + success: false, + errors: error.errors, + message: "Validation failed", + }) + } res.status(500).json({ success: false, - response: error, - message: "Could not update likes." + error: error.message, + message: "Server error - try again later." }) } }) From 58780b69b05a440f5afa1b955fc483506bd4d48f Mon Sep 17 00:00:00 2001 From: Bianka R Date: Tue, 17 Jun 2025 18:24:42 +0200 Subject: [PATCH 28/31] added back get single thought path --- routes/thoughtsRouter.js | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/routes/thoughtsRouter.js b/routes/thoughtsRouter.js index abc1148..0eeffe6 100644 --- a/routes/thoughtsRouter.js +++ b/routes/thoughtsRouter.js @@ -6,7 +6,7 @@ import { authenticateUser } from "./authRouter" const thoughtsRouter = Router() // GET ALL THOUGHTS -thoughtsRouter.get("/thoughts", async (req, res) => { +thoughtsRouter.get("/", async (req, res) => { try { const thoughts = await Thought.find() @@ -32,6 +32,33 @@ thoughtsRouter.get("/thoughts", async (req, res) => { } }) +// GET ONE THOUGHT +thoughtsRouter.get("/:id", async (req, res) => { + const { id } = req.params + + try { + const thought = await Thought.findById(id) + if (!thought) { + return res.status(404).json({ + success: false, + message: "No thought found." + }) + } + res.status(200).json({ + success: true, + response: thought, + message: "Thought found." + }) + + } catch (error) { + res.status(500).json({ + success: false, + response: error.messsage, + message: "Failed to find this thought." + }) + } +}) + // POST THOUGHT thoughtsRouter.post("/", authenticateUser, async (req, res) => { const { message, hearts, createdAt } = req.body From 5629d8b7e5bb3df8b28d85603c3cae5c5e0ec716 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Wed, 18 Jun 2025 09:52:04 +0200 Subject: [PATCH 29/31] show thoughts by most recent top --- routes/authRouter.js | 2 ++ routes/thoughtsRouter.js | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/routes/authRouter.js b/routes/authRouter.js index e3c9f02..3ea5039 100644 --- a/routes/authRouter.js +++ b/routes/authRouter.js @@ -25,6 +25,7 @@ authRouter.post("/register", async (req, res) => { message: "Signup success", success: true, id: user._id, + username: user.username, accessToken: user.accessToken}) } catch(err) { @@ -68,6 +69,7 @@ authRouter.post("/login", async (req, res) => { success: true, message: "User successfully logged in", userId: user.id, + username: user.username, accessToken: user.accessToken }) } else { diff --git a/routes/thoughtsRouter.js b/routes/thoughtsRouter.js index 0eeffe6..9831d25 100644 --- a/routes/thoughtsRouter.js +++ b/routes/thoughtsRouter.js @@ -9,8 +9,8 @@ const thoughtsRouter = Router() thoughtsRouter.get("/", async (req, res) => { try { - const thoughts = await Thought.find() - if (Thought.length === 0) { + const thoughts = await Thought.find().sort({ createdAt: -1 }) + if (thoughts.length === 0) { return res.status(404).json({ success: false, response: [], @@ -53,7 +53,7 @@ thoughtsRouter.get("/:id", async (req, res) => { } catch (error) { res.status(500).json({ success: false, - response: error.messsage, + response: error.message, message: "Failed to find this thought." }) } @@ -92,6 +92,12 @@ thoughtsRouter.delete("/:id", authenticateUser, async (req, res) => { success: false, message: "Not found or authorized" }) + } + if (delThought.createdBy.toString() !== req.user._id.toString()) { + return res.status(403).json({ + success: false, + message: "Unauthorized to delete this thought" + }) } res.status(200).json({ success: true, @@ -127,6 +133,12 @@ thoughtsRouter.patch("/:id", authenticateUser, async (req, res) => { success: false, message: "Not found, no update possible." }) + } + if (thought.createdBy.toString() !== req.user._id.toString()) { + return res.status(403).json({ + success: false, + message: "Unauthorized to edit this thought" + }) } res.status(200).json({ success: true, From 2c907f287b1465f5c6151efe76f2ef0794322857 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Thu, 19 Jun 2025 01:13:55 +0200 Subject: [PATCH 30/31] fix userid naming error --- routes/authRouter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routes/authRouter.js b/routes/authRouter.js index 3ea5039..e3d15fa 100644 --- a/routes/authRouter.js +++ b/routes/authRouter.js @@ -24,7 +24,7 @@ authRouter.post("/register", async (req, res) => { res.status(200).json({ message: "Signup success", success: true, - id: user._id, + userid: user._id, username: user.username, accessToken: user.accessToken}) @@ -68,7 +68,7 @@ authRouter.post("/login", async (req, res) => { res.status(201).json({ success: true, message: "User successfully logged in", - userId: user.id, + userId: user._id, username: user.username, accessToken: user.accessToken }) From 7977400e448c5f101371fcd66d60805846a9e9a5 Mon Sep 17 00:00:00 2001 From: Bianka R Date: Thu, 19 Jun 2025 01:47:06 +0200 Subject: [PATCH 31/31] usage for endpoints --- models/User.js | 1 + server.js | 1 + 2 files changed, 2 insertions(+) diff --git a/models/User.js b/models/User.js index ae29644..19eead2 100644 --- a/models/User.js +++ b/models/User.js @@ -25,6 +25,7 @@ const userSchema = new mongoose.Schema({ password: { type: String, required: true, + minlength: 4, }, accessToken: { type: String, diff --git a/server.js b/server.js index 6ebc869..dde5a83 100644 --- a/server.js +++ b/server.js @@ -52,6 +52,7 @@ app.get("/", (req, res) => { const endpoints = listEndpoints(app) res.json({ message: "Hello Happy Thoughts API", + usage: "Visit /thoughts to get all thoughts, or see the list below for all available endpoints.", endpoints: endpoints }) })