From bc32ffd5c19f5d3b9012de95dfd0d7fc66cd5be3 Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Thu, 29 May 2025 16:20:41 +0200 Subject: [PATCH 01/29] add express-list-endpoints to dependencies --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index bf25bb6..00addae 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@babel/preset-env": "^7.16.11", "cors": "^2.8.5", "express": "^4.17.3", + "express-list-endpoints": "^7.1.1", "nodemon": "^3.0.1" } } From 6fa29ff8f7c97f327a9d182726b47882e160609b Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Thu, 29 May 2025 16:37:38 +0200 Subject: [PATCH 02/29] add dotenv to dependencies --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 00addae..70ca4d2 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", "cors": "^2.8.5", + "dotenv": "^16.5.0", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", "nodemon": "^3.0.1" From 9f7f23f018e8b075785e4c139c85598afc24f87f Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Thu, 29 May 2025 23:08:20 +0200 Subject: [PATCH 03/29] define endpoints and modify json file to use property id instead of _id --- data.json | 166 +++++++++++++++++++++++++++--------------------------- server.js | 12 ++++ 2 files changed, 95 insertions(+), 83 deletions(-) diff --git a/data.json b/data.json index a2c844f..3b4d7d7 100644 --- a/data.json +++ b/data.json @@ -1,121 +1,121 @@ [ - { - "_id": "682bab8c12155b00101732ce", - "message": "Berlin baby", - "hearts": 37, - "createdAt": "2025-05-19T22:07:08.999Z", - "__v": 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": "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": "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", + "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": "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": "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": "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", + "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": "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": "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", + "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": "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": "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": "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": "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": "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 + "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 f47771b..f1b0525 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,6 @@ import cors from "cors" import express from "express" +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: @@ -16,6 +17,17 @@ app.get("/", (req, res) => { res.send("Hello Technigo!") }) +// Endpoint for getting all posts +app.get("/posts", (req, res) => { + res.json(data) +}) + +// Endpoint for getting a specific post +app.get("/posts/:id", (req, res) => { + const post = data.find((post) => post.id === req.params.id); + res.json(post); +}) + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) From 2cefed7fc339cc656e5894eaa2361862a6afbd3f Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Thu, 29 May 2025 23:24:59 +0200 Subject: [PATCH 04/29] add filtering with query parameters on posts endpoint --- server.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index f1b0525..2a0d1f2 100644 --- a/server.js +++ b/server.js @@ -19,7 +19,16 @@ app.get("/", (req, res) => { // Endpoint for getting all posts app.get("/posts", (req, res) => { - res.json(data) + + const { hearts } = req.query; + + let filteredData = data; + + if (hearts) { + filteredData = filteredData.filter(post => post.hearts === +hearts); + } + + res.json(filteredData) }) // Endpoint for getting a specific post From 90156f1e6c0528b0acb305ce4915573218531a1d Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Thu, 29 May 2025 23:25:56 +0200 Subject: [PATCH 05/29] delete repeated post in data json file --- data.json | 7 ------- 1 file changed, 7 deletions(-) diff --git a/data.json b/data.json index 3b4d7d7..37ab0a7 100644 --- a/data.json +++ b/data.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 From 31f71d61c5d996d64a335c75cd130df72fa14c54 Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Thu, 29 May 2025 23:42:05 +0200 Subject: [PATCH 06/29] add listEndpoints to document API --- server.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index 2a0d1f2..21df7ea 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,7 @@ import cors from "cors" import express from "express" import data from "./data.json" +import listEndpoints from "express-list-endpoints" // 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: @@ -14,7 +15,11 @@ app.use(express.json()) // Start defining your routes here app.get("/", (req, res) => { - res.send("Hello Technigo!") + const endpoints = listEndpoints(app) + res.json({ + message: "Welcome to the Happy Thoughts API", + endpoints: endpoints + }) }) // Endpoint for getting all posts From 41b1ffcf374008dc0ee567c3b727b68012843d1c Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Sat, 31 May 2025 19:05:50 +0200 Subject: [PATCH 07/29] add mongoose to dependencies and mongoose boilerplate to serverjs --- package.json | 1 + server.js | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/package.json b/package.json index 70ca4d2..d320bcb 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.0.1" } } diff --git a/server.js b/server.js index 21df7ea..368aafc 100644 --- a/server.js +++ b/server.js @@ -2,6 +2,7 @@ import cors from "cors" import express from "express" import data from "./data.json" import listEndpoints from "express-list-endpoints" +import mongoose from "mongoose" // 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: @@ -13,6 +14,12 @@ const app = express() app.use(cors()) app.use(express.json()) +const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/posts" +mongoose.connect(mongoUrl, { useNewUrlParser: true, useUnifiedTopology: true }) +mongoose.Promise = Promise + +const Post = + // Start defining your routes here app.get("/", (req, res) => { const endpoints = listEndpoints(app) From e596d9db56af34b7d05a2e440bc8a2bdfaa1cc26 Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Tue, 10 Jun 2025 07:32:10 +0200 Subject: [PATCH 08/29] define post schema and function to seed database --- server.js | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/server.js b/server.js index 368aafc..199a26e 100644 --- a/server.js +++ b/server.js @@ -4,9 +4,11 @@ import data from "./data.json" import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" -// 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 +// Set up mongoose +const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/happy-thoughts-api" +mongoose.connect(mongoUrl) + +// Set up express const port = process.env.PORT || 8080 const app = express() @@ -14,12 +16,6 @@ const app = express() app.use(cors()) app.use(express.json()) -const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/posts" -mongoose.connect(mongoUrl, { useNewUrlParser: true, useUnifiedTopology: true }) -mongoose.Promise = Promise - -const Post = - // Start defining your routes here app.get("/", (req, res) => { const endpoints = listEndpoints(app) @@ -29,6 +25,28 @@ app.get("/", (req, res) => { }) }) +// Define post schema +const postSchema = new mongoose.Schema({ + id: Number, + message: String, + hearts: Number, + createdAt: String, + __v: Number +}) + +const Post = mongoose.model("Post", postSchema) + +// Seed database +if (process.env.RESET_DB) { + const seedDatabase = async () => { + await Post.deleteMany({}) + data.forEach(post => { + new Post(post).save() + }) + } + seedDatabase() +} + // Endpoint for getting all posts app.get("/posts", (req, res) => { From 72ebcefdd58efef57df84cde79d2cc66584a2543 Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Tue, 10 Jun 2025 08:19:36 +0200 Subject: [PATCH 09/29] add endpoint for getting all posts --- server.js | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/server.js b/server.js index 199a26e..b48f59b 100644 --- a/server.js +++ b/server.js @@ -48,17 +48,39 @@ if (process.env.RESET_DB) { } // Endpoint for getting all posts -app.get("/posts", (req, res) => { - +app.get("/posts", async (req, res) => { const { hearts } = req.query; - - let filteredData = data; + + const query = {} if (hearts) { - filteredData = filteredData.filter(post => post.hearts === +hearts); + query.hearts = hearts + } + + try { + const filteredPosts = await Post.find(query) + + if (filteredPosts.length === 0) { + return res.status(404).json({ + success: false, + response: [], + message: "No posts found for given query. Please try again with a different query" + }) + } + res.status(200).json({ + success: true, + response: filteredPosts, + message: "Success" + }) + + } catch (error) { + res.status(500).json({ + success: false, + response: error, + message: "Failed to fetch posts" + }) } - res.json(filteredData) }) // Endpoint for getting a specific post From 62b520a611d860b5468051c35204b983f389bb6a Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Tue, 10 Jun 2025 09:48:16 +0200 Subject: [PATCH 10/29] create endpoint for posting new post --- server.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/server.js b/server.js index b48f59b..1d4b6b8 100644 --- a/server.js +++ b/server.js @@ -89,6 +89,17 @@ app.get("/posts/:id", (req, res) => { res.json(post); }) +// Endpoint for posting +app.post("/posts", async (req, res) => { + const { message } = req.body + + try { + const newPost = await new Post({ message }).save() + } catch (error) { + + } +}) + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) From 6d430ba659db256c1a1b9807a2ebe809399e7409 Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Tue, 10 Jun 2025 09:48:49 +0200 Subject: [PATCH 11/29] finish creating endpoint for posting new post --- server.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index 1d4b6b8..03a54b4 100644 --- a/server.js +++ b/server.js @@ -95,8 +95,17 @@ app.post("/posts", async (req, res) => { try { const newPost = await new Post({ message }).save() + res.status(201).json({ + success: true, + response: newPost, + message: "Post created successfully" + }) } catch (error) { - + res.status(500).json({ + success: false, + response: error, + message: "Could not create post" + }) } }) From 1ad0b7dc581ce08d8b3b835efe1d922c91c372ec Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Wed, 11 Jun 2025 08:32:58 +0200 Subject: [PATCH 12/29] correct schema format --- server.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/server.js b/server.js index 03a54b4..15675c3 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,6 @@ import cors from "cors" import express from "express" +import dotenv from "dotenv" import data from "./data.json" import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" @@ -8,6 +9,9 @@ import mongoose from "mongoose" const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/happy-thoughts-api" mongoose.connect(mongoUrl) +// Set up dotenv +dotenv.config() + // Set up express const port = process.env.PORT || 8080 const app = express() @@ -28,10 +32,8 @@ app.get("/", (req, res) => { // Define post schema const postSchema = new mongoose.Schema({ id: Number, - message: String, - hearts: Number, - createdAt: String, - __v: Number + message: { type: String, required: true }, + hearts: { type: Number, default: 0 }, }) const Post = mongoose.model("Post", postSchema) From 01288d41d77fc652d038d252cb2b1062688f5762 Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Wed, 11 Jun 2025 08:37:01 +0200 Subject: [PATCH 13/29] correct schema model --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index 15675c3..fb2d123 100644 --- a/server.js +++ b/server.js @@ -31,9 +31,9 @@ app.get("/", (req, res) => { // Define post schema const postSchema = new mongoose.Schema({ - id: Number, message: { type: String, required: true }, hearts: { type: Number, default: 0 }, + timestamps: { createdAt: true, updatedAt: false } }) const Post = mongoose.model("Post", postSchema) From 398e89c50c3fcd17884dfe4a21f10fd457d5ef34 Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Wed, 11 Jun 2025 08:42:30 +0200 Subject: [PATCH 14/29] correct seed db --- server.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index fb2d123..4d665f0 100644 --- a/server.js +++ b/server.js @@ -33,6 +33,8 @@ app.get("/", (req, res) => { const postSchema = new mongoose.Schema({ message: { type: String, required: true }, hearts: { type: Number, default: 0 }, +}, +{ timestamps: { createdAt: true, updatedAt: false } }) @@ -42,8 +44,8 @@ const Post = mongoose.model("Post", postSchema) if (process.env.RESET_DB) { const seedDatabase = async () => { await Post.deleteMany({}) - data.forEach(post => { - new Post(post).save() + data.forEach(({ message, hearts}) => { + new Post({ message, hearts }).save() }) } seedDatabase() From 3f28eab282235e0e34729032c733766b52800da1 Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Wed, 11 Jun 2025 21:43:27 +0200 Subject: [PATCH 15/29] update nomenclature posts to thoughts throughout the code --- models/user.js | 0 server.js | 54 +++++++++++++++++++++++++------------------------- 2 files changed, 27 insertions(+), 27 deletions(-) create mode 100644 models/user.js diff --git a/models/user.js b/models/user.js new file mode 100644 index 0000000..e69de29 diff --git a/server.js b/server.js index 4d665f0..4b832a9 100644 --- a/server.js +++ b/server.js @@ -1,17 +1,17 @@ import cors from "cors" import express from "express" -import dotenv from "dotenv" -import data from "./data.json" import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" +import dotenv from "dotenv" +import data from "./data.json" + +// Set up dotenv +dotenv.config() // Set up mongoose const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/happy-thoughts-api" mongoose.connect(mongoUrl) -// Set up dotenv -dotenv.config() - // Set up express const port = process.env.PORT || 8080 const app = express() @@ -29,8 +29,8 @@ app.get("/", (req, res) => { }) }) -// Define post schema -const postSchema = new mongoose.Schema({ +// Define thought schema +const thoughtSchema = new mongoose.Schema({ message: { type: String, required: true }, hearts: { type: Number, default: 0 }, }, @@ -38,21 +38,21 @@ const postSchema = new mongoose.Schema({ timestamps: { createdAt: true, updatedAt: false } }) -const Post = mongoose.model("Post", postSchema) +const Thought = mongoose.model("Thought", thoughtSchema) // Seed database if (process.env.RESET_DB) { const seedDatabase = async () => { - await Post.deleteMany({}) - data.forEach(({ message, hearts}) => { - new Post({ message, hearts }).save() + await Thought.deleteMany({}) + data.forEach(({ message, hearts }) => { + new Thought({ message, hearts }).save() }) } seedDatabase() } -// Endpoint for getting all posts -app.get("/posts", async (req, res) => { +// Endpoint for getting all thoughts +app.get("/thoughts", async (req, res) => { const { hearts } = req.query; const query = {} @@ -62,18 +62,18 @@ app.get("/posts", async (req, res) => { } try { - const filteredPosts = await Post.find(query) + const filteredThoughts = await Thought.find(query) - if (filteredPosts.length === 0) { + if (filteredThoughts.length === 0) { return res.status(404).json({ success: false, response: [], - message: "No posts found for given query. Please try again with a different query" + message: "No thoughts found for given query. Please try again with a different query" }) } res.status(200).json({ success: true, - response: filteredPosts, + response: filteredThoughts, message: "Success" }) @@ -81,34 +81,34 @@ app.get("/posts", async (req, res) => { res.status(500).json({ success: false, response: error, - message: "Failed to fetch posts" + message: "Failed to fetch thoughts" }) } }) -// Endpoint for getting a specific post -app.get("/posts/:id", (req, res) => { - const post = data.find((post) => post.id === req.params.id); - res.json(post); +// Endpoint for getting a specific thought +app.get("/thoughts/:id", (req, res) => { + const thought = data.find((thought) => thought.id === req.params.id); + res.json(thought); }) // Endpoint for posting -app.post("/posts", async (req, res) => { +app.post("/thoughts", async (req, res) => { const { message } = req.body try { - const newPost = await new Post({ message }).save() + const newThought = await new Thought({ message }).save() res.status(201).json({ success: true, - response: newPost, - message: "Post created successfully" + response: newThought, + message: "Thought created successfully" }) } catch (error) { res.status(500).json({ success: false, response: error, - message: "Could not create post" + message: "Could not create thought" }) } }) From b7ca6117eff2a0d9e3416c4d2b50e7b5096da075 Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Wed, 11 Jun 2025 21:51:53 +0200 Subject: [PATCH 16/29] created models folder with thought and user schemas --- models/thought.js | 11 +++++++++++ server.js | 1 + 2 files changed, 12 insertions(+) create mode 100644 models/thought.js diff --git a/models/thought.js b/models/thought.js new file mode 100644 index 0000000..bbe17b2 --- /dev/null +++ b/models/thought.js @@ -0,0 +1,11 @@ +import mongoose from "mongoose" + +const thoughtSchema = new mongoose.Schema({ + message: { type: String, required: true }, + hearts: { type: Number, default: 0 }, +}, +{ + timestamps: { createdAt: true, updatedAt: false } +}) + +export const Thought = mongoose.model("Thought", thoughtSchema) \ No newline at end of file diff --git a/server.js b/server.js index 4b832a9..af5978f 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 data from "./data.json" +import { Thought } from "./models/thought.js" // Set up dotenv dotenv.config() From 9fffc982b97ee6027a3185e8124b580d9407d861 Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Wed, 11 Jun 2025 21:54:21 +0200 Subject: [PATCH 17/29] deleted thought schema from server js --- server.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/server.js b/server.js index af5978f..3b3fe88 100644 --- a/server.js +++ b/server.js @@ -30,17 +30,6 @@ app.get("/", (req, res) => { }) }) -// Define thought schema -const thoughtSchema = new mongoose.Schema({ - message: { type: String, required: true }, - hearts: { type: Number, default: 0 }, -}, -{ - timestamps: { createdAt: true, updatedAt: false } -}) - -const Thought = mongoose.model("Thought", thoughtSchema) - // Seed database if (process.env.RESET_DB) { const seedDatabase = async () => { From fbd47b548dc8b9fddb05458a2657fca541c71c23 Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Wed, 11 Jun 2025 22:02:07 +0200 Subject: [PATCH 18/29] modify thought schema --- models/thought.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/models/thought.js b/models/thought.js index bbe17b2..bab4c25 100644 --- a/models/thought.js +++ b/models/thought.js @@ -1,11 +1,21 @@ import mongoose from "mongoose" const thoughtSchema = new mongoose.Schema({ - message: { type: String, required: true }, - hearts: { type: Number, default: 0 }, -}, -{ - timestamps: { createdAt: true, updatedAt: false } + 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) \ No newline at end of file From 9ed516dfe676103016ef3a0b60e234c8560c645c Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Wed, 11 Jun 2025 22:31:01 +0200 Subject: [PATCH 19/29] added user schema to models --- models/user.js | 20 ++++++++++++++++++++ package.json | 2 ++ 2 files changed, 22 insertions(+) diff --git a/models/user.js b/models/user.js index e69de29..277cc7a 100644 --- a/models/user.js +++ b/models/user.js @@ -0,0 +1,20 @@ +import mongoose from "mongoose" +import crypto from "crypto" + +const userSchema = new mongoose.Schema({ + email: { + type: String, + required: true, + 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 d320bcb..4b5790b 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,9 @@ "@babel/core": "^7.17.9", "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", + "bcrypt": "^6.0.0", "cors": "^2.8.5", + "crypto": "^1.0.1", "dotenv": "^16.5.0", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", From b3dc9c54ccb1002e3f3a76774a4a659ca4f85e3c Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Fri, 13 Jun 2025 09:40:39 +0200 Subject: [PATCH 20/29] update thought schema to include userid --- server.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/server.js b/server.js index 3b3fe88..76d9306 100644 --- a/server.js +++ b/server.js @@ -5,6 +5,7 @@ import mongoose from "mongoose" import dotenv from "dotenv" import data from "./data.json" import { Thought } from "./models/thought.js" +import { User } from "./models/user.js" // Set up dotenv dotenv.config() @@ -21,15 +22,6 @@ const app = express() app.use(cors()) app.use(express.json()) -// Start defining your routes here -app.get("/", (req, res) => { - const endpoints = listEndpoints(app) - res.json({ - message: "Welcome to the Happy Thoughts API", - endpoints: endpoints - }) -}) - // Seed database if (process.env.RESET_DB) { const seedDatabase = async () => { @@ -41,6 +33,15 @@ if (process.env.RESET_DB) { seedDatabase() } +// Start defining your routes here +app.get("/", (req, res) => { + const endpoints = listEndpoints(app) + res.json({ + message: "Welcome to the Happy Thoughts API", + endpoints: endpoints + }) +}) + // Endpoint for getting all thoughts app.get("/thoughts", async (req, res) => { const { hearts } = req.query; @@ -77,13 +78,13 @@ app.get("/thoughts", async (req, res) => { }) -// Endpoint for getting a specific thought +// Endpoint for getting a specific thought by id app.get("/thoughts/:id", (req, res) => { const thought = data.find((thought) => thought.id === req.params.id); res.json(thought); }) -// Endpoint for posting +// Endpoint for posting thoughts app.post("/thoughts", async (req, res) => { const { message } = req.body From a6adfd283175669dd5691e751dae6b50b0a5383b Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Sun, 15 Jun 2025 15:51:15 +0200 Subject: [PATCH 21/29] finish creating endpoints, separate out controller functions, create middleware for user authentication, migrate to jwt --- .gitignore | 3 +- controllers/deleteThought.js | 44 +++++++++++ controllers/getThought.js | 31 ++++++++ controllers/getThoughts.js | 34 +++++++++ controllers/getUserData.js | 31 ++++++++ controllers/loginUser.js | 44 +++++++++++ controllers/patchThought.js | 45 ++++++++++++ controllers/patchThoughtLikes.js | 46 ++++++++++++ controllers/postThought.js | 33 +++++++++ controllers/postUser.js | 26 +++++++ middleware/authenticateUser.js | 42 +++++++++++ models/thought.js | 14 +++- models/user.js | 8 +- package.json | 1 + server.js | 122 ++++++++++++------------------- 15 files changed, 440 insertions(+), 84 deletions(-) create mode 100644 controllers/deleteThought.js create mode 100644 controllers/getThought.js create mode 100644 controllers/getThoughts.js create mode 100644 controllers/getUserData.js create mode 100644 controllers/loginUser.js create mode 100644 controllers/patchThought.js create mode 100644 controllers/patchThoughtLikes.js create mode 100644 controllers/postThought.js create mode 100644 controllers/postUser.js create mode 100644 middleware/authenticateUser.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/controllers/deleteThought.js b/controllers/deleteThought.js new file mode 100644 index 0000000..12aed4a --- /dev/null +++ b/controllers/deleteThought.js @@ -0,0 +1,44 @@ +import { Thought } from "../models/thought.js" + +export const deleteThought = async (req, res) => { + const { id } = req.params + const userId = req.user._id + + try { + + const thought = await Thought.findById(id) + + if (!thought) { + return res.status(404).json({ + success: false, + response: [], + message: "Failed to delete thought: no thought found for the given id." + }) + } + + if (thought.userId.toString() !== userId) { + return res.status(403).json({ + success: false, + response: [], + message: "Failed to delete thought: you are not authorized to delete this thought." + }) + } + + await Thought.findByIdAndDelete(id) + + res.status(200).json({ + success: true, + response: [], + message: "Thought deleted successfully." + }) + + } catch (error) { + + res.status(500).json({ + success: false, + response: error, + message: "Internal server error: failed to delete thought. Please try again later." + }) + + } +} \ No newline at end of file diff --git a/controllers/getThought.js b/controllers/getThought.js new file mode 100644 index 0000000..310e60b --- /dev/null +++ b/controllers/getThought.js @@ -0,0 +1,31 @@ +import { Thought } from "../models/thought.js" + +export const getThought = async (req, res) => { + const { id } = req.params + + try { + const thought = await Thought.findById(id) + + if (!thought) { + return res.status(404).json({ + success: false, + response: [], + message: "No thought found for the given id. Please try again with a different id." + }) + } + + res.status(200).json({ + success: true, + response: thought, + message: "Success." + }) + } + + catch (error) { + res.status(500).json({ + success: false, + response: error, + message: "Internal server error: failed to fetch thought. Please try again later." + }) + } +} \ No newline at end of file diff --git a/controllers/getThoughts.js b/controllers/getThoughts.js new file mode 100644 index 0000000..0ec334e --- /dev/null +++ b/controllers/getThoughts.js @@ -0,0 +1,34 @@ +import { Thought } from "../models/thought.js" + +export const getThoughts = async (req, res) => { + const { hearts } = req.query; + const query = {} + + if (hearts) { + query.hearts = hearts + } + + try { + const filteredThoughts = await Thought.find(query) + + if (filteredThoughts.length === 0) { + return res.status(404).json({ + success: false, + response: [], + message: "No thoughts found for given query. Please try again with a different query" + }) + } + res.status(200).json({ + success: true, + response: filteredThoughts, + message: "Success" + }) + + } catch (error) { + res.status(500).json({ + success: false, + response: error, + message: "Failed to fetch thoughts" + }) + } +} \ No newline at end of file diff --git a/controllers/getUserData.js b/controllers/getUserData.js new file mode 100644 index 0000000..ff41124 --- /dev/null +++ b/controllers/getUserData.js @@ -0,0 +1,31 @@ +import { User } from "../models/user.js" + +export const getUserData = async (req, res) => { + try { + + const user = req.user + + if (!user) { + return res.status(404).json({ + success: false, + response: [], + message: "Failed to get user data: no user found for the given id." + }) + } + + res.status(200).json({ + success: true, + response: { name: user.name }, + message: "Success" + }) + + } catch (error) { + + res.status(500).json({ + success: false, + response: error, + message: "Internal server error: failed to get user data. Please try again later." + }) + + } +} \ No newline at end of file diff --git a/controllers/loginUser.js b/controllers/loginUser.js new file mode 100644 index 0000000..9ab5a00 --- /dev/null +++ b/controllers/loginUser.js @@ -0,0 +1,44 @@ +import bcrypt from "bcrypt" +import jwt from "jsonwebtoken" +import { User } from "../models/user.js" + +export const loginUser = async (req, res) => { + const { email, password } = req.body + + try { + const user = await User.findOne({ email }) + + if (!user || !bcrypt.compareSync(password, user.password)) { + return res.status(401).json({ + success: false, + response: [], + message: "Failed to log in: invalid email or password." + }) + } + + const accessToken = jwt.sign( + { userId: user._id }, + process.env.JWT_SECRET, + { expiresIn: process.env.JWT_EXPIRES_IN} + ) + + res.status(200).json({ + success: true, + response: { + accessToken, + name: user.name, + userId: user._id + }, + message: "Log in successful." + }) + +} catch (error) { + + res.status(500).json({ + success: false, + response: error, + message: "Internal server error: failed to log in. Please try again later." + }) + + } +} \ No newline at end of file diff --git a/controllers/patchThought.js b/controllers/patchThought.js new file mode 100644 index 0000000..af6573c --- /dev/null +++ b/controllers/patchThought.js @@ -0,0 +1,45 @@ +import { Thought } from "../models/thought.js" + +export const patchThought = async (req, res) => { + const { id } = req.params + const { updatedMessage } = req.body + const userId = req.user._id + + try { + const thought = await Thought.findById(id) + + if (!thought) { + return res.status(404).json({ + success: false, + response: [], + message: "Failed to update thought: no thought found for given id." + }) + } + + if (thought.userId.toString() !== userId) { + return res.status(403).json({ + success: false, + response: [], + message: "Failed to update thought: you are not authorized to update this thought." + }) + } + + thought.message = updatedMessage + await thought.save() + + res.status(200).json({ + success: true, + response: thought, + message: "Thought updated successfully." + }) + + } catch (error) { + + res.status(500).json({ + success: false, + response: error, + message: "Internal server error: failed to update thought. Please try again later." + }) + + } +} \ No newline at end of file diff --git a/controllers/patchThoughtLikes.js b/controllers/patchThoughtLikes.js new file mode 100644 index 0000000..537bb9a --- /dev/null +++ b/controllers/patchThoughtLikes.js @@ -0,0 +1,46 @@ +import { Thought } from "../models/thought.js" + +export const patchThoughtLikes = async (req, res) => { + const { id } = req.params + const { userId } = req.body + + try { + + const thought = await Thought.findById(id) + + if (!thought) { + return res.status(404).json({ + success: false, + response: [], + message: "No thought found for the given id. Please try again with a different id." + }) + } + + const hasLiked = thought.likes.includes(userId) + + if (hasLiked) { + // remove like + thought.likes = thought.likes.filter(like => like.toString() !== userId) + } else { + // add like + thought.likes.push(userId) + } + + await thought.save() + + res.status(200).json({ + success: true, + response: thought, + message: "Likes updated successfully." + }) + + } catch (error) { + + res.status(500).json({ + success: false, + response: error, + message: "Internal server error: failed to update likes. Please try again later." + }) + + } +} \ No newline at end of file diff --git a/controllers/postThought.js b/controllers/postThought.js new file mode 100644 index 0000000..0169587 --- /dev/null +++ b/controllers/postThought.js @@ -0,0 +1,33 @@ +import { Thought } from "../models/thought.js" + +export const postThought = async (req, res) => { + const { message } = req.body + const user = req.user + + try { + const newThought = await new Thought({ message, userId: user._id }).save() + + if (!newThought) { + return res.status(400).json({ + success: false, + response: [], + message: "Failed to post thought." + }) + } + + res.status(201).json({ + success: true, + response: newThought, + message: "Thought posted successfully." + }) + + } catch (error) { + + res.status(500).json({ + success: false, + response: error, + message: "Internal server error: failed to post thought. Please try again later." + }) + + } +} \ No newline at end of file diff --git a/controllers/postUser.js b/controllers/postUser.js new file mode 100644 index 0000000..17a4118 --- /dev/null +++ b/controllers/postUser.js @@ -0,0 +1,26 @@ +import { User } from "../models/user.js" +import bcrypt from "bcrypt" + +export const postUser = async (req, res) => { + try { + + const { name, email, password } = req.body + const salt = bcrypt.genSaltSync() + const user = await new User({ name, email, password: bcrypt.hashSync(password, salt) }).save() + + res.status(201).json({ + success: true, + response: { userId: user._id, accessToken: user.accessToken }, + message: "User registered successfully." + }) + + } catch (error) { + + res.status(500).json({ + success: false, + response: error, + message: "Internal server error: failed to register user. Please try again later." + }) + + } +} \ No newline at end of file diff --git a/middleware/authenticateUser.js b/middleware/authenticateUser.js new file mode 100644 index 0000000..bd155bc --- /dev/null +++ b/middleware/authenticateUser.js @@ -0,0 +1,42 @@ +import jwt from "jsonwebtoken" +import { User } from "../models/user.js" + +export const authenticateUser = async (req, res, next) => { + const authHeader = req.headers.authorization + + if (!authHeader || !authHeader.startsWith("Bearer ")) { + return res.status(401).json({ + success: false, + response: [], + message: "Authorization header missing or invalid." + }) + } + + const token = authHeader.replace("Bearer ", "") + + try { + + const decoded = jwt.verify(token, process.env.JWT_SECRET) + const user = await User.findById(decoded.userId) + + if (!user) { + return res.status(401).json({ + success: false, + response: [], + message: "User not found." + }) + } + + req.user = user + next() + + } catch (error) { + + res.status(401).json({ + success: false, + response: [], + message: "Invalid token." + }) + + } +} \ No newline at end of file diff --git a/models/thought.js b/models/thought.js index bab4c25..7c6bd16 100644 --- a/models/thought.js +++ b/models/thought.js @@ -7,10 +7,16 @@ const thoughtSchema = new mongoose.Schema({ minLength: 5, maxLength: 140 }, - hearts: { - type: Number, - default: 0, - min: 0 + likes: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: "User" + } + ], + userId: { + type: mongoose.Schema.Types.ObjectId, + ref: "User", + required: true }, createdAt: { type: Date, diff --git a/models/user.js b/models/user.js index 277cc7a..0d34f2f 100644 --- a/models/user.js +++ b/models/user.js @@ -2,6 +2,10 @@ import mongoose from "mongoose" import crypto from "crypto" const userSchema = new mongoose.Schema({ + name: { + type: String, + required: true + }, email: { type: String, required: true, @@ -10,10 +14,6 @@ const userSchema = new mongoose.Schema({ password: { type: String, required: true - }, - accessToken: { - type: String, - default: () => crypto.randomBytes(128).toString("hex") } }) diff --git a/package.json b/package.json index 4b5790b..c4c2233 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "dotenv": "^16.5.0", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", + "jsonwebtoken": "^9.0.2", "mongoose": "^8.15.1", "nodemon": "^3.0.1" } diff --git a/server.js b/server.js index 76d9306..a287369 100644 --- a/server.js +++ b/server.js @@ -3,37 +3,42 @@ import express from "express" import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" import dotenv from "dotenv" -import data from "./data.json" -import { Thought } from "./models/thought.js" -import { User } from "./models/user.js" -// Set up dotenv +import { getThoughts } from "./controllers/getThoughts.js" +import { getThought } from "./controllers/getThought.js" +import { postThought } from "./controllers/postThought.js" +import { patchThought } from "./controllers/patchThought.js" +import { patchThoughtLikes } from "./controllers/patchThoughtLikes.js" +import { deleteThought } from "./controllers/deleteThought.js" +import { postUser } from "./controllers/postUser.js" +import { loginUser } from "./controllers/loginUser.js" +import { getUserData } from "./controllers/getUserData.js" +import { authenticateUser } from "./middleware/authenticateUser.js" + dotenv.config() -// Set up mongoose const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/happy-thoughts-api" mongoose.connect(mongoUrl) -// Set up 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()) // Seed database -if (process.env.RESET_DB) { - const seedDatabase = async () => { - await Thought.deleteMany({}) - data.forEach(({ message, hearts }) => { - new Thought({ message, hearts }).save() - }) - } - seedDatabase() -} - -// Start defining your routes here +// if (process.env.RESET_DB) { +// const seedDatabase = async () => { +// await Thought.deleteMany({}) +// data.forEach(({ message, hearts }) => { +// new Thought({ message, hearts }).save() +// }) +// } +// seedDatabase() +// } + +// List all API endpoints for documentation + app.get("/", (req, res) => { const endpoints = listEndpoints(app) res.json({ @@ -42,67 +47,34 @@ app.get("/", (req, res) => { }) }) -// Endpoint for getting all thoughts -app.get("/thoughts", async (req, res) => { - const { hearts } = req.query; - - const query = {} - - if (hearts) { - query.hearts = hearts - } - - try { - const filteredThoughts = await Thought.find(query) - - if (filteredThoughts.length === 0) { - return res.status(404).json({ - success: false, - response: [], - message: "No thoughts found for given query. Please try again with a different query" - }) - } - res.status(200).json({ - success: true, - response: filteredThoughts, - message: "Success" - }) - - } catch (error) { - res.status(500).json({ - success: false, - response: error, - message: "Failed to fetch thoughts" - }) - } +// Set up endpoints -}) +// Endpoint for getting all thoughts +app.get("/thoughts", authenticateUser, getThoughts) // Endpoint for getting a specific thought by id -app.get("/thoughts/:id", (req, res) => { - const thought = data.find((thought) => thought.id === req.params.id); - res.json(thought); -}) +app.get("/thoughts/:id", authenticateUser, getThought) -// Endpoint for posting thoughts -app.post("/thoughts", async (req, res) => { - const { message } = req.body - - try { - const newThought = await new Thought({ message }).save() - res.status(201).json({ - success: true, - response: newThought, - message: "Thought created successfully" - }) - } catch (error) { - res.status(500).json({ - success: false, - response: error, - message: "Could not create thought" - }) - } -}) +// Endpoint for posting a thought +app.post("/thoughts", authenticateUser, postThought) + +// Endpoint for updating a thought +app.patch("/thoughts/:id", authenticateUser, patchThought) + +// Endpoint for toggling likes +app.patch("/thoughts/:id/likes", authenticateUser, patchThoughtLikes) + +// Endpoint for deleting a thought +app.delete("/thoughts/:id", authenticateUser, deleteThought) + +// Endpoint for registering a user +app.post("/users/register", postUser) + +// Endpoint for logging in a user +app.post("/users/login", loginUser) + +// Endpoint for retrieving the data of an authenticated user +app.get("/users/me", authenticateUser, getUserData) // Start the server app.listen(port, () => { From 05863507829420a68906055ff9c11fc7f3939ae6 Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Sun, 15 Jun 2025 16:09:46 +0200 Subject: [PATCH 22/29] update postUser controller to issue jwt access token --- controllers/postUser.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/controllers/postUser.js b/controllers/postUser.js index 17a4118..47b2c19 100644 --- a/controllers/postUser.js +++ b/controllers/postUser.js @@ -1,16 +1,30 @@ -import { User } from "../models/user.js" import bcrypt from "bcrypt" +import jwt from "jsonwebtoken" +import { User } from "../models/user.js" export const postUser = async (req, res) => { try { const { name, email, password } = req.body + const salt = bcrypt.genSaltSync() - const user = await new User({ name, email, password: bcrypt.hashSync(password, salt) }).save() + const hashedPassword = bcrypt.hashSync(password, salt) + + const newUser = await new User({ name, email, password: hashedPassword }).save() + + const accessToken = jwt.sign( + { userId: newUser._id }, + process.env.JWT_SECRET, + { expiresIn: process.env.JWT_EXPIRES_IN } + ) res.status(201).json({ success: true, - response: { userId: user._id, accessToken: user.accessToken }, + response: { + userId: newUser._id, + name: newUser.name, + accessToken + }, message: "User registered successfully." }) From 928cd3af8e2262f97d1544101fb8e5268a918b0d Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Sun, 15 Jun 2025 16:48:21 +0200 Subject: [PATCH 23/29] test minor bug fix in patchThought controller --- controllers/patchThought.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/patchThought.js b/controllers/patchThought.js index af6573c..84e91f3 100644 --- a/controllers/patchThought.js +++ b/controllers/patchThought.js @@ -16,7 +16,7 @@ export const patchThought = async (req, res) => { }) } - if (thought.userId.toString() !== userId) { + if (thought.userId.toString() !== userId.toString()) { return res.status(403).json({ success: false, response: [], From ee9d4d5dcea22b5b4602c1f9fa8a29f6f4c74a08 Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Sun, 15 Jun 2025 22:28:30 +0200 Subject: [PATCH 24/29] correct const userId in patchThoughtLikes controller code --- controllers/patchThoughtLikes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/patchThoughtLikes.js b/controllers/patchThoughtLikes.js index 537bb9a..02fa008 100644 --- a/controllers/patchThoughtLikes.js +++ b/controllers/patchThoughtLikes.js @@ -2,7 +2,7 @@ import { Thought } from "../models/thought.js" export const patchThoughtLikes = async (req, res) => { const { id } = req.params - const { userId } = req.body + const userId = req.user._id try { From d2571229484490c21b3a4116530dea71b158e18e Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Sun, 15 Jun 2025 22:43:47 +0200 Subject: [PATCH 25/29] fix minor bug in patchThoughtLikes controller --- controllers/patchThoughtLikes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/patchThoughtLikes.js b/controllers/patchThoughtLikes.js index 02fa008..05a0f40 100644 --- a/controllers/patchThoughtLikes.js +++ b/controllers/patchThoughtLikes.js @@ -20,7 +20,7 @@ export const patchThoughtLikes = async (req, res) => { if (hasLiked) { // remove like - thought.likes = thought.likes.filter(like => like.toString() !== userId) + thought.likes = thought.likes.filter(like => like.toString() !== userId.toString()) } else { // add like thought.likes.push(userId) From 5505e979e12e533d9351051631d47c3e8043ef5c Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Sun, 15 Jun 2025 22:51:36 +0200 Subject: [PATCH 26/29] fix minor bug in deleteThought controller code --- controllers/deleteThought.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/deleteThought.js b/controllers/deleteThought.js index 12aed4a..c2bd780 100644 --- a/controllers/deleteThought.js +++ b/controllers/deleteThought.js @@ -16,7 +16,7 @@ export const deleteThought = async (req, res) => { }) } - if (thought.userId.toString() !== userId) { + if (thought.userId.toString() !== userId.toString()) { return res.status(403).json({ success: false, response: [], From 8c87c24bd4b44b4fdc6000f3754ec071271e7d1e Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Mon, 16 Jun 2025 22:30:25 +0200 Subject: [PATCH 27/29] delete data.json and function for seeding database --- data.json | 114 ------------------------------------------------------ server.js | 11 ------ 2 files changed, 125 deletions(-) delete mode 100644 data.json diff --git a/data.json b/data.json deleted file mode 100644 index 37ab0a7..0000000 --- a/data.json +++ /dev/null @@ -1,114 +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 - } -] \ No newline at end of file diff --git a/server.js b/server.js index a287369..effa935 100644 --- a/server.js +++ b/server.js @@ -26,17 +26,6 @@ const app = express() app.use(cors()) app.use(express.json()) -// Seed database -// if (process.env.RESET_DB) { -// const seedDatabase = async () => { -// await Thought.deleteMany({}) -// data.forEach(({ message, hearts }) => { -// new Thought({ message, hearts }).save() -// }) -// } -// seedDatabase() -// } - // List all API endpoints for documentation app.get("/", (req, res) => { From 629480eb809fa064570f5283bb02e81e76ae9470 Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Wed, 25 Jun 2025 19:47:58 +0200 Subject: [PATCH 28/29] separate runtime dependencies from dev dependencies in package json --- package.json | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index c4c2233..09bb299 100644 --- a/package.json +++ b/package.json @@ -9,17 +9,18 @@ "author": "", "license": "ISC", "dependencies": { - "@babel/core": "^7.17.9", - "@babel/node": "^7.16.8", - "@babel/preset-env": "^7.16.11", "bcrypt": "^6.0.0", "cors": "^2.8.5", - "crypto": "^1.0.1", "dotenv": "^16.5.0", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", "jsonwebtoken": "^9.0.2", - "mongoose": "^8.15.1", - "nodemon": "^3.0.1" + "mongoose": "^8.15.1" + }, + "devDependencies": { + "@babel/core": "^7.27.4", + "@babel/node": "^7.27.1", + "@babel/preset-env": "^7.27.2", + "nodemon": "^3.1.10" } } From 519ba1602b5dd840bc979bd24c1b6d97ae39b551 Mon Sep 17 00:00:00 2001 From: Juan Salvador Zorrilla Date: Sat, 28 Jun 2025 12:15:47 +0200 Subject: [PATCH 29/29] remove unused crypto import in user js --- models/user.js | 1 - 1 file changed, 1 deletion(-) diff --git a/models/user.js b/models/user.js index 0d34f2f..c315fdc 100644 --- a/models/user.js +++ b/models/user.js @@ -1,5 +1,4 @@ import mongoose from "mongoose" -import crypto from "crypto" const userSchema = new mongoose.Schema({ name: {