From 0d0657e697a927f959217c58e22ac83741c7e54d Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Tue, 20 Jan 2026 16:04:01 +0100 Subject: [PATCH 01/29] set up endpoints and created three routes: endpoints documentation, all happy thoughts messages and happy thoughts filtered by id --- package.json | 4 +++- server.js | 27 ++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index bf25bb68..6eb2ce2b 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "project-api", "version": "1.0.0", "description": "Project API", + "type": "module", "scripts": { "start": "babel-node server.js", "dev": "nodemon server.js --exec babel-node" @@ -14,6 +15,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" } -} +} \ No newline at end of file diff --git a/server.js b/server.js index f47771bd..d167d8d9 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,7 @@ import cors from "cors" import express from "express" +import listEndpoints from "express-list-endpoints" +import data from "./data.json" with { type: "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: @@ -13,7 +15,30 @@ 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 happy thoughts api", + endpoints: endpoints + }) +}) + +app.get("/happy-thoughts", (req, res) => { + res.json(data) + +}) + +app.get("/happy-thoughts/:id", (req, res) => { + const id = req.params.id + + const happyThought = data.find((happyThought) => happyThought._id === id) + + if (!happyThought) { + return res.status(404).json({ error: `flower with id ${id} does not exist` }) + } + + res.json(happyThought) + }) // Start the server From def493d18d812958bdb0380026ce08bb3e7ca162 Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Thu, 23 Apr 2026 17:41:54 +0200 Subject: [PATCH 02/29] made file structure for models,routes and middleware. added routes for users, made a userSchema. moved the happyThoughts routes into a new file and added auth middleware to some of the routes --- data.json | 7 --- middleware/authMiddleware.js | 23 +++++++++ models/HappyThought.js | 7 +++ models/User.js | 20 ++++++++ package.json | 5 +- routes/happyThoughtsRoutes.js | 87 +++++++++++++++++++++++++++++++++++ routes/userRoutes.js | 77 +++++++++++++++++++++++++++++++ server.js | 54 +++++++++++++++------- 8 files changed, 255 insertions(+), 25 deletions(-) create mode 100644 middleware/authMiddleware.js create mode 100644 models/HappyThought.js create mode 100644 models/User.js create mode 100644 routes/happyThoughtsRoutes.js create mode 100644 routes/userRoutes.js diff --git a/data.json b/data.json index a2c844ff..1124d7f1 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 diff --git a/middleware/authMiddleware.js b/middleware/authMiddleware.js new file mode 100644 index 00000000..6b68a42f --- /dev/null +++ b/middleware/authMiddleware.js @@ -0,0 +1,23 @@ +import { User } from "../models/User" + +export const authenticateUser = async (req, res, next) => { + try { + const user = await User.findOne({ accessToken: req.header("Authorization").replace("Bearer", "")}) + + if (user) { + req.user = user + next() + } else { + res.status(401).json({ + message: "Authentication missing or invalid", + loggedOut: true + }) + } + + } catch (error) { + res.status(500).json({ + message: "internal server error", + error: error.message + }) + } +} \ No newline at end of file diff --git a/models/HappyThought.js b/models/HappyThought.js new file mode 100644 index 00000000..2071debb --- /dev/null +++ b/models/HappyThought.js @@ -0,0 +1,7 @@ +import mongoose from "mongoose" + +const happyThoughtSchema = new mongoose.Schema({ + +}) + +export const HappyThought = mongoose.model("HappyThought", happyThoughtSchema) \ No newline at end of file diff --git a/models/User.js b/models/User.js new file mode 100644 index 00000000..5dc5f6a0 --- /dev/null +++ b/models/User.js @@ -0,0 +1,20 @@ +import crypto from "crypto" +import mongoose from "mongoose" + +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 6eb2ce2b..cce19413 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,12 @@ "@babel/core": "^7.17.9", "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", + "bcrypt": "^6.0.0", "cors": "^2.8.5", + "dotenv": "^17.2.3", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", + "mongoose": "^9.1.5", "nodemon": "^3.0.1" } -} \ No newline at end of file +} diff --git a/routes/happyThoughtsRoutes.js b/routes/happyThoughtsRoutes.js new file mode 100644 index 00000000..e0c98553 --- /dev/null +++ b/routes/happyThoughtsRoutes.js @@ -0,0 +1,87 @@ +import express from "express" +import { authenticateUser } from "../middleware/authMiddleware" + +const router = express.Router() + +router.get("/happy-thoughts", async (req, res) => { + + const { minLikes } = req.query + console.log("min likes", minLikes) + + const query = {} + + if (minLikes) { + query.hearts = {$gte: Number(minLikes)} + } + + try { + const filteredMessages = await Thought.find(query) + + if (filteredMessages.length === 0) { + return res.status(404).json({ + success: false, + response: [], + message: "No thoughts were found for that query" + }) + } + + return res.status(200).json({ + success: true, + response: filteredMessages, + message: "Success" + }) + } catch (error) { + return res.status(500).json({ + success: false, + response: [], + message: error + }) + } +}) + +router.post("/happy-thoughts", authenticateUser, (req, res) => { + const body = req.body + + const newThought = { + _id: data.length + 1, + message: body.message, + hearts: body.hearts, + createdAt: body.createdAt, + __v: body.__v + } + + data.push(newThought) + + res.json(newThought) +}) + + +router.get("/happy-thoughts/:id", (req, res) => { + const id = req.params.id + + const happyThought = data.find((happyThought) => happyThought._id === id) + + if (!happyThought) { + return res.status(404).json({ error: `happy thought with id ${id} does not exist` }) + } + + res.json(happyThought) + +}) + +router.delete("/happy-thoughts/:id", authenticateUser, (req, res) => { + const { id } = req.params + const thought = data.find((thought) => String(thought._id) === String(id)) + + if (!thought) { + return res.status(404).json({error: `thought with id ${id} does not exist`}) + } + + const newThoughts = data.filter((thought) => String(thought._id) !== String(id)) + + data = newThoughts + + res.json(thought) +}) + +export default router \ No newline at end of file diff --git a/routes/userRoutes.js b/routes/userRoutes.js new file mode 100644 index 00000000..8dad3a58 --- /dev/null +++ b/routes/userRoutes.js @@ -0,0 +1,77 @@ +import express from "express" +import bcrypt from "bcrypt" +import { User } from "../models/User" + +const router = express.Router() + +router.post("/signup", async (req, res) => { + try { + const { email, password } = req.body + const existingUser = await User.findOne({ email: email.toLowerCase()}) + + if (existingUser) { + return res.status(409).json({ + success: false, + message: "An error occurred when creating the user" + }) + } + + const salt = bcrypt.genSaltSync() + const hashedPassword = bcrypt.hashSync(password, salt) + + const user = new User({ + email, + password + }) + + const savedUser = await user.save() + + res.status(201).json({ + success: true, + message: "User created successfully", + response: { + savedUser: savedUser + } + }) + + } catch (error) { + res.status(400).json({ + success: false, + message: "failed to create user", + response: error + }) + } +}) + +router.post("/login", async (req, res) => { + try { + const { email, password } = req.body + const user = await User.findOne({email: email.toLowerCase()}) + + if (user && bcrypt.compareSync(password, user.password)) { + res.status(200).json({ + success: true, + message: "Login successful", + respone: { + email: user.email, + id: user._id, + accessToken: user.accessToken + } + }) + } else { + res.status(401).json({ + success: false, + message: "Invalid email or password", + response: null + }) + } + } catch (error) { + res.status(500).json({ + success: false, + message: "Something wnet wrong during login", + response: error + }) + } +}) + +export default router \ No newline at end of file diff --git a/server.js b/server.js index d167d8d9..00faecf0 100644 --- a/server.js +++ b/server.js @@ -1,8 +1,15 @@ import cors from "cors" import express from "express" import listEndpoints from "express-list-endpoints" -import data from "./data.json" with { type: "json" } +import "dotenv/config" +import mongoose from "mongoose" +import happyData from "./data.json" with { type: "json" } +import happyThoughtsRoutes from "./routes/happyThoughtsRoutes.js" +import userRoutes from "./routes/userRoutes.js" +let data = happyData +const mongoUrl = process.env.MONGO_URL +mongoose.connect(mongoUrl) // Defines the port the app will run on. Defaults to 8080, but can be overridden // when starting the server. Example command to overwrite PORT env variable value: // PORT=9000 npm start @@ -13,6 +20,33 @@ const app = express() app.use(cors()) app.use(express.json()) +const thoughtsSchema = new mongoose.Schema ({ +message: { + type: String, + required: true +}, +hearts: { + type: Number +}, +createdAt: { + type: Date, + default: Date.now +} +}) + +const Thought = mongoose.model("Thought", thoughtsSchema) + +if (process.env.RESET_DB === "true") { + const seedDataBase = async () => { + await Thought.deleteMany() + + data.forEach(thought => { + new Thought(thought).save() + }) + } + seedDataBase() +} + // Start defining your routes here app.get("/", (req, res) => { const endpoints = listEndpoints(app) @@ -23,23 +57,9 @@ app.get("/", (req, res) => { }) }) -app.get("/happy-thoughts", (req, res) => { - res.json(data) - -}) - -app.get("/happy-thoughts/:id", (req, res) => { - const id = req.params.id +app.use("/happy-thoughts", happyThoughtsRoutes) +app.use("/users", userRoutes) - const happyThought = data.find((happyThought) => happyThought._id === id) - - if (!happyThought) { - return res.status(404).json({ error: `flower with id ${id} does not exist` }) - } - - res.json(happyThought) - -}) // Start the server app.listen(port, () => { From dc6f1fd941e08b6ec11883e91c4b65db5b3b59ba Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Mon, 27 Apr 2026 14:06:36 +0200 Subject: [PATCH 03/29] added js to authMiddleware for render debugging --- routes/happyThoughtsRoutes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/happyThoughtsRoutes.js b/routes/happyThoughtsRoutes.js index e0c98553..f7cd59db 100644 --- a/routes/happyThoughtsRoutes.js +++ b/routes/happyThoughtsRoutes.js @@ -1,5 +1,5 @@ import express from "express" -import { authenticateUser } from "../middleware/authMiddleware" +import { authenticateUser } from "../middleware/authMiddleware.js" const router = express.Router() From 3689eb94cd49c345976c2182fc505ba1f8a13a18 Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Mon, 27 Apr 2026 14:16:29 +0200 Subject: [PATCH 04/29] more debugging for render --- middleware/authMiddleware.js | 2 +- package.json | 5 +++-- routes/userRoutes.js | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/middleware/authMiddleware.js b/middleware/authMiddleware.js index 6b68a42f..1c690a6c 100644 --- a/middleware/authMiddleware.js +++ b/middleware/authMiddleware.js @@ -1,4 +1,4 @@ -import { User } from "../models/User" +import { User } from "../models/User.js" export const authenticateUser = async (req, res, next) => { try { diff --git a/package.json b/package.json index cce19413..757def92 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,10 @@ "bcrypt": "^6.0.0", "cors": "^2.8.5", "dotenv": "^17.2.3", - "express": "^4.17.3", + "express": "^4.22.1", "express-list-endpoints": "^7.1.1", - "mongoose": "^9.1.5", + "mongodb": "^7.2.0", + "mongoose": "^9.5.0", "nodemon": "^3.0.1" } } diff --git a/routes/userRoutes.js b/routes/userRoutes.js index 8dad3a58..1664d54b 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -1,6 +1,6 @@ import express from "express" import bcrypt from "bcrypt" -import { User } from "../models/User" +import { User } from "../models/User.js" const router = express.Router() From eee75ced8a9fee5e31ace35c0b766086c3a5869c Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Mon, 27 Apr 2026 14:20:26 +0200 Subject: [PATCH 05/29] changed the happy-thoughts route names --- routes/happyThoughtsRoutes.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/routes/happyThoughtsRoutes.js b/routes/happyThoughtsRoutes.js index f7cd59db..149559ac 100644 --- a/routes/happyThoughtsRoutes.js +++ b/routes/happyThoughtsRoutes.js @@ -3,7 +3,7 @@ import { authenticateUser } from "../middleware/authMiddleware.js" const router = express.Router() -router.get("/happy-thoughts", async (req, res) => { +router.get("/", async (req, res) => { const { minLikes } = req.query console.log("min likes", minLikes) @@ -39,7 +39,7 @@ router.get("/happy-thoughts", async (req, res) => { } }) -router.post("/happy-thoughts", authenticateUser, (req, res) => { +router.post("/", authenticateUser, (req, res) => { const body = req.body const newThought = { @@ -56,7 +56,7 @@ router.post("/happy-thoughts", authenticateUser, (req, res) => { }) -router.get("/happy-thoughts/:id", (req, res) => { +router.get("/:id", (req, res) => { const id = req.params.id const happyThought = data.find((happyThought) => happyThought._id === id) @@ -69,7 +69,7 @@ router.get("/happy-thoughts/:id", (req, res) => { }) -router.delete("/happy-thoughts/:id", authenticateUser, (req, res) => { +router.delete("/:id", authenticateUser, (req, res) => { const { id } = req.params const thought = data.find((thought) => String(thought._id) === String(id)) From 0f7144b826e5119693ebc8f3a6ce8a9e3f29c0f4 Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Mon, 27 Apr 2026 15:56:34 +0200 Subject: [PATCH 06/29] added updated some of the happy thoughts routes with the new mongoose model and added try catch blocks --- models/HappyThought.js | 12 ++++- package.json | 2 +- routes/happyThoughtsRoutes.js | 89 ++++++++++++++++++++++++----------- server.js | 29 +----------- 4 files changed, 74 insertions(+), 58 deletions(-) diff --git a/models/HappyThought.js b/models/HappyThought.js index 2071debb..59638791 100644 --- a/models/HappyThought.js +++ b/models/HappyThought.js @@ -1,7 +1,17 @@ import mongoose from "mongoose" const happyThoughtSchema = new mongoose.Schema({ - + message: { + type: String, + required: true + }, + hearts: { + type: Number + }, + createdAt: { + type: Date, + default: Date.now + } }) export const HappyThought = mongoose.model("HappyThought", happyThoughtSchema) \ No newline at end of file diff --git a/package.json b/package.json index 757def92..9e86b428 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", "bcrypt": "^6.0.0", - "cors": "^2.8.5", + "cors": "^2.8.6", "dotenv": "^17.2.3", "express": "^4.22.1", "express-list-endpoints": "^7.1.1", diff --git a/routes/happyThoughtsRoutes.js b/routes/happyThoughtsRoutes.js index 149559ac..56e076aa 100644 --- a/routes/happyThoughtsRoutes.js +++ b/routes/happyThoughtsRoutes.js @@ -1,5 +1,6 @@ import express from "express" import { authenticateUser } from "../middleware/authMiddleware.js" +import { HappyThought } from "../models/HappyThought.js" const router = express.Router() @@ -15,7 +16,7 @@ router.get("/", async (req, res) => { } try { - const filteredMessages = await Thought.find(query) + const filteredMessages = await HappyThought.find(query) if (filteredMessages.length === 0) { return res.status(404).json({ @@ -39,49 +40,81 @@ router.get("/", async (req, res) => { } }) -router.post("/", authenticateUser, (req, res) => { - const body = req.body +router.post("/", authenticateUser, async (req, res) => { + const { message } = req.body - const newThought = { - _id: data.length + 1, - message: body.message, - hearts: body.hearts, - createdAt: body.createdAt, - __v: body.__v - } - - data.push(newThought) + try { + const newHappyThought = await new HappyThought({ message }).save() - res.json(newThought) + res.status(201).json({ + success: true, + response: newHappyThought, + message: "Happy thought created successfully" + }) + } catch (error) { + res.status(500).json({ + success: false, + response: error, + message: "Couldn't create happy thought" + }) + } }) router.get("/:id", (req, res) => { - const id = req.params.id + const { _id } = req.params - const happyThought = data.find((happyThought) => happyThought._id === id) + try { + const happyThought = HappyThought.findById(_id) - if (!happyThought) { - return res.status(404).json({ error: `happy thought with id ${id} does not exist` }) - } + if (!happyThought) { + return res.status(404).json({ + success: false, + response: null, + message: "Happy thought not found" + }) + } - res.json(happyThought) + res.status(200).json({ + success: true, + respone: happyThought + }) + } catch (error) { + res.status(500).json({ + success: false, + response: error, + message: "Happy thought couldn't be found" + }) + } }) router.delete("/:id", authenticateUser, (req, res) => { - const { id } = req.params - const thought = data.find((thought) => String(thought._id) === String(id)) - - if (!thought) { - return res.status(404).json({error: `thought with id ${id} does not exist`}) - } + const { _id } = req.params - const newThoughts = data.filter((thought) => String(thought._id) !== String(id)) + try { + const deletedThought = HappyThought.findByIdAndDelete(_id) - data = newThoughts + if (!deletedThought) { + return res.status(404).json({ + success: false, + response: null, + message: "Happy thought not found" + }) + } - res.json(thought) + res.status(200).json({ + success: true, + response: deletedThought, + message: "Happy thought deleted successfully" + }) + } catch (error) { + res.status(500).json({ + success: false, + response: error, + message: "Error deleting happy thought" + }) + } }) export default router \ No newline at end of file diff --git a/server.js b/server.js index 00faecf0..d868568c 100644 --- a/server.js +++ b/server.js @@ -3,11 +3,10 @@ import express from "express" import listEndpoints from "express-list-endpoints" import "dotenv/config" import mongoose from "mongoose" -import happyData from "./data.json" with { type: "json" } import happyThoughtsRoutes from "./routes/happyThoughtsRoutes.js" import userRoutes from "./routes/userRoutes.js" -let data = happyData + const mongoUrl = process.env.MONGO_URL mongoose.connect(mongoUrl) // Defines the port the app will run on. Defaults to 8080, but can be overridden @@ -20,32 +19,6 @@ const app = express() app.use(cors()) app.use(express.json()) -const thoughtsSchema = new mongoose.Schema ({ -message: { - type: String, - required: true -}, -hearts: { - type: Number -}, -createdAt: { - type: Date, - default: Date.now -} -}) - -const Thought = mongoose.model("Thought", thoughtsSchema) - -if (process.env.RESET_DB === "true") { - const seedDataBase = async () => { - await Thought.deleteMany() - - data.forEach(thought => { - new Thought(thought).save() - }) - } - seedDataBase() -} // Start defining your routes here app.get("/", (req, res) => { From 8ffa85f44943321817c00077f7a6645747e5102e Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Mon, 27 Apr 2026 17:02:00 +0200 Subject: [PATCH 07/29] added seeding database for happy thoughts testing --- routes/happyThoughtsRoutes.js | 3 +++ seedingDatabase/seedingThoughts.js | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 seedingDatabase/seedingThoughts.js diff --git a/routes/happyThoughtsRoutes.js b/routes/happyThoughtsRoutes.js index 56e076aa..0d909b7a 100644 --- a/routes/happyThoughtsRoutes.js +++ b/routes/happyThoughtsRoutes.js @@ -1,9 +1,12 @@ import express from "express" import { authenticateUser } from "../middleware/authMiddleware.js" import { HappyThought } from "../models/HappyThought.js" +import { seedingThoughts } from "../seedingDatabase/seedingThoughts.js" const router = express.Router() +seedingThoughts() + router.get("/", async (req, res) => { const { minLikes } = req.query diff --git a/seedingDatabase/seedingThoughts.js b/seedingDatabase/seedingThoughts.js new file mode 100644 index 00000000..eca5211d --- /dev/null +++ b/seedingDatabase/seedingThoughts.js @@ -0,0 +1,18 @@ +import { HappyThought } from "../models/HappyThought.js" + +export const seedingThoughts = async () => { + + if (process.env.RESET_DB === "true") { + console.log("Resetting seeding database..."); + await HappyThought.deleteMany() + } + + await new HappyThought ({ + message: "Carolina's happy thought" + }).save(); + + await new HappyThought ({ + message: "Mikaela's happy thought" + }).save(); + +} \ No newline at end of file From b095cc20892faad093f149a6898595e7fc3e5648 Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Wed, 20 May 2026 14:38:20 +0200 Subject: [PATCH 08/29] debugged id route: added async await and changed id param --- routes/happyThoughtsRoutes.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/routes/happyThoughtsRoutes.js b/routes/happyThoughtsRoutes.js index 0d909b7a..c61e62b8 100644 --- a/routes/happyThoughtsRoutes.js +++ b/routes/happyThoughtsRoutes.js @@ -64,11 +64,11 @@ router.post("/", authenticateUser, async (req, res) => { }) -router.get("/:id", (req, res) => { - const { _id } = req.params +router.get("/:id", async (req, res) => { + const { id } = req.params try { - const happyThought = HappyThought.findById(_id) + const happyThought = await HappyThought.findById(id) if (!happyThought) { return res.status(404).json({ @@ -92,11 +92,11 @@ router.get("/:id", (req, res) => { }) -router.delete("/:id", authenticateUser, (req, res) => { - const { _id } = req.params +router.delete("/:id", authenticateUser, async (req, res) => { + const { id } = req.params try { - const deletedThought = HappyThought.findByIdAndDelete(_id) + const deletedThought = await HappyThought.findByIdAndDelete(id) if (!deletedThought) { return res.status(404).json({ From 788f053be6a5037c77882f2fb405c9fdc8769afc Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Wed, 20 May 2026 18:22:35 +0200 Subject: [PATCH 09/29] added seeding users to userRoutes --- routes/happyThoughtsRoutes.js | 1 + routes/userRoutes.js | 3 +++ seedingDatabase/seedingUsers.js | 25 +++++++++++++++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 seedingDatabase/seedingUsers.js diff --git a/routes/happyThoughtsRoutes.js b/routes/happyThoughtsRoutes.js index c61e62b8..5dca8a55 100644 --- a/routes/happyThoughtsRoutes.js +++ b/routes/happyThoughtsRoutes.js @@ -96,6 +96,7 @@ router.delete("/:id", authenticateUser, async (req, res) => { const { id } = req.params try { + const deletedThought = await HappyThought.findByIdAndDelete(id) if (!deletedThought) { diff --git a/routes/userRoutes.js b/routes/userRoutes.js index 1664d54b..48389539 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -1,9 +1,12 @@ import express from "express" import bcrypt from "bcrypt" import { User } from "../models/User.js" +import { seedingUsers } from "../seedingDatabase/seedingUsers.js" const router = express.Router() +seedingUsers() + router.post("/signup", async (req, res) => { try { const { email, password } = req.body diff --git a/seedingDatabase/seedingUsers.js b/seedingDatabase/seedingUsers.js new file mode 100644 index 00000000..65560ebf --- /dev/null +++ b/seedingDatabase/seedingUsers.js @@ -0,0 +1,25 @@ +import { User } from "../models/User.js" +import bcrypt from "bcrypt" + +export const seedingUsers = async () => { + const salt = 10 + + if (process.env.RESET_SEED_DB === "true") { + console.log("Resetting seeding database..."); + await User.deleteMany() + } + + await new User ({ + firstName: "Carolina", + lastName: "Oldertz", + email: "carolina.oldertz@gmail.com", + password: bcrypt.hashSync("carolina", salt) + }).save(); + + await new User ({ + firstName: "Mikaela", + lastName: "Sturk", + email: "mikaelasturk@gmail.com", + password: bcrypt.hashSync("mikaela", salt) + }).save() +} \ No newline at end of file From 5f1cf935541c67f47fc9ee71c6e4187294eab354 Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Wed, 20 May 2026 18:25:25 +0200 Subject: [PATCH 10/29] variable change in seeding users --- seedingDatabase/seedingUsers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seedingDatabase/seedingUsers.js b/seedingDatabase/seedingUsers.js index 65560ebf..128300cc 100644 --- a/seedingDatabase/seedingUsers.js +++ b/seedingDatabase/seedingUsers.js @@ -4,7 +4,7 @@ import bcrypt from "bcrypt" export const seedingUsers = async () => { const salt = 10 - if (process.env.RESET_SEED_DB === "true") { + if (process.env.RESET_DB === "true") { console.log("Resetting seeding database..."); await User.deleteMany() } From 5fe76bae536993d45132cf412bf24d10e453f37c Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Fri, 22 May 2026 14:31:17 +0200 Subject: [PATCH 11/29] name debug for frontend --- middleware/authMiddleware.js | 8 +++---- routes/happyThoughtsRoutes.js | 40 +++++++++++++++++------------------ routes/userRoutes.js | 28 ++++++++++++------------ server.js | 4 ++-- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/middleware/authMiddleware.js b/middleware/authMiddleware.js index 1c690a6c..ee339ea0 100644 --- a/middleware/authMiddleware.js +++ b/middleware/authMiddleware.js @@ -1,21 +1,21 @@ import { User } from "../models/User.js" -export const authenticateUser = async (req, res, next) => { +export const authenticateUser = async (reqest, response, next) => { try { const user = await User.findOne({ accessToken: req.header("Authorization").replace("Bearer", "")}) if (user) { - req.user = user + reqest.user = user next() } else { - res.status(401).json({ + response.status(401).json({ message: "Authentication missing or invalid", loggedOut: true }) } } catch (error) { - res.status(500).json({ + response.status(500).json({ message: "internal server error", error: error.message }) diff --git a/routes/happyThoughtsRoutes.js b/routes/happyThoughtsRoutes.js index 5dca8a55..cc4db305 100644 --- a/routes/happyThoughtsRoutes.js +++ b/routes/happyThoughtsRoutes.js @@ -7,9 +7,9 @@ const router = express.Router() seedingThoughts() -router.get("/", async (req, res) => { +router.get("/", async (reqest, response) => { - const { minLikes } = req.query + const { minLikes } = reqest.query console.log("min likes", minLikes) const query = {} @@ -22,20 +22,20 @@ router.get("/", async (req, res) => { const filteredMessages = await HappyThought.find(query) if (filteredMessages.length === 0) { - return res.status(404).json({ + return response.status(404).json({ success: false, response: [], message: "No thoughts were found for that query" }) } - return res.status(200).json({ + return response.status(200).json({ success: true, response: filteredMessages, message: "Success" }) } catch (error) { - return res.status(500).json({ + return response.status(500).json({ success: false, response: [], message: error @@ -43,19 +43,19 @@ router.get("/", async (req, res) => { } }) -router.post("/", authenticateUser, async (req, res) => { - const { message } = req.body +router.post("/", authenticateUser, async (reqest, response) => { + const { message } = reqest.body try { const newHappyThought = await new HappyThought({ message }).save() - res.status(201).json({ + response.status(201).json({ success: true, response: newHappyThought, message: "Happy thought created successfully" }) } catch (error) { - res.status(500).json({ + response.status(500).json({ success: false, response: error, message: "Couldn't create happy thought" @@ -64,26 +64,26 @@ router.post("/", authenticateUser, async (req, res) => { }) -router.get("/:id", async (req, res) => { - const { id } = req.params +router.get("/:id", async (reqest, response) => { + const { id } = reqest.params try { const happyThought = await HappyThought.findById(id) if (!happyThought) { - return res.status(404).json({ + return response.status(404).json({ success: false, response: null, message: "Happy thought not found" }) } - res.status(200).json({ + response.status(200).json({ success: true, - respone: happyThought + response: happyThought }) } catch (error) { - res.status(500).json({ + response.status(500).json({ success: false, response: error, message: "Happy thought couldn't be found" @@ -92,28 +92,28 @@ router.get("/:id", async (req, res) => { }) -router.delete("/:id", authenticateUser, async (req, res) => { - const { id } = req.params +router.delete("/:id", authenticateUser, async (reqest, response) => { + const { id } = reqest.params try { const deletedThought = await HappyThought.findByIdAndDelete(id) if (!deletedThought) { - return res.status(404).json({ + return response.status(404).json({ success: false, response: null, message: "Happy thought not found" }) } - res.status(200).json({ + response.status(200).json({ success: true, response: deletedThought, message: "Happy thought deleted successfully" }) } catch (error) { - res.status(500).json({ + response.status(500).json({ success: false, response: error, message: "Error deleting happy thought" diff --git a/routes/userRoutes.js b/routes/userRoutes.js index 48389539..dfc566ce 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -7,13 +7,13 @@ const router = express.Router() seedingUsers() -router.post("/signup", async (req, res) => { +router.post("/signup", async (reqest, response) => { try { - const { email, password } = req.body + const { email, password } = reqest.body const existingUser = await User.findOne({ email: email.toLowerCase()}) if (existingUser) { - return res.status(409).json({ + return response.status(409).json({ success: false, message: "An error occurred when creating the user" }) @@ -24,12 +24,12 @@ router.post("/signup", async (req, res) => { const user = new User({ email, - password + password: hashedPassword }) const savedUser = await user.save() - res.status(201).json({ + response.status(201).json({ success: true, message: "User created successfully", response: { @@ -38,7 +38,7 @@ router.post("/signup", async (req, res) => { }) } catch (error) { - res.status(400).json({ + response.status(400).json({ success: false, message: "failed to create user", response: error @@ -46,32 +46,32 @@ router.post("/signup", async (req, res) => { } }) -router.post("/login", async (req, res) => { +router.post("/login", async (reqest, response) => { try { - const { email, password } = req.body + const { email, password } = reqest.body const user = await User.findOne({email: email.toLowerCase()}) if (user && bcrypt.compareSync(password, user.password)) { - res.status(200).json({ + response.status(200).json({ success: true, message: "Login successful", - respone: { + response: { email: user.email, id: user._id, accessToken: user.accessToken } }) } else { - res.status(401).json({ + response.status(401).json({ success: false, message: "Invalid email or password", - response: null + response: null }) } } catch (error) { - res.status(500).json({ + response.status(500).json({ success: false, - message: "Something wnet wrong during login", + message: "Something went wrong during login", response: error }) } diff --git a/server.js b/server.js index d868568c..972d25c9 100644 --- a/server.js +++ b/server.js @@ -21,10 +21,10 @@ app.use(express.json()) // Start defining your routes here -app.get("/", (req, res) => { +app.get("/", (reqest, response) => { const endpoints = listEndpoints(app) - res.json({ + response.json({ message: "Welcome to happy thoughts api", endpoints: endpoints }) From 8a840faaa8e5b3d933ad35ba7302e113eb587b06 Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Wed, 27 May 2026 11:49:11 +0200 Subject: [PATCH 12/29] updated user model with first and last name --- models/User.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/models/User.js b/models/User.js index 5dc5f6a0..87781a6e 100644 --- a/models/User.js +++ b/models/User.js @@ -2,6 +2,14 @@ import crypto from "crypto" import mongoose from "mongoose" const userSchema = new mongoose.Schema({ + firstName: { + type: String, + required: true + }, + lastName: { + type: String, + required: true + }, email: { type: String, required: true, From d85eec17ce05ad0173257e01468f63b211603a17 Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Wed, 27 May 2026 13:43:50 +0200 Subject: [PATCH 13/29] added first and lastname to signup route and added a get route for a specific user based on id --- routes/userRoutes.js | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/routes/userRoutes.js b/routes/userRoutes.js index dfc566ce..eecbc5a4 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -7,9 +7,32 @@ const router = express.Router() seedingUsers() +router.get("/:id", async (request, response) => { + try { + const { id } = request.params + const user = await User.findById(id) + + if (user) { + response.status(200).json({ + message: "Hej!!!! Välkommen till din sida, " + user.firstName + "!!!", + user + }) + } else { + response.status(404).json({ + error: "user not found" + }) + } + + } catch (error) { + response.status(400).json({ + error: "invalid request" + }) + } +}) + router.post("/signup", async (reqest, response) => { try { - const { email, password } = reqest.body + const { firstName, lastName, email, password } = reqest.body const existingUser = await User.findOne({ email: email.toLowerCase()}) if (existingUser) { @@ -23,6 +46,8 @@ router.post("/signup", async (reqest, response) => { const hashedPassword = bcrypt.hashSync(password, salt) const user = new User({ + firstName, + lastName, email, password: hashedPassword }) From a41c7e531ffda2167103ecdc89ac5a33dd1056fe Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Wed, 27 May 2026 16:07:05 +0200 Subject: [PATCH 14/29] updated signup route to send accessToken --- routes/userRoutes.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/routes/userRoutes.js b/routes/userRoutes.js index eecbc5a4..513429f4 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -49,7 +49,8 @@ router.post("/signup", async (reqest, response) => { firstName, lastName, email, - password: hashedPassword + password: hashedPassword, + accessToken }) const savedUser = await user.save() From 57f33da781367a07f6a1eb9bc50dbc5f9f27c97e Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Wed, 27 May 2026 16:12:53 +0200 Subject: [PATCH 15/29] debugging signup route --- routes/userRoutes.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/routes/userRoutes.js b/routes/userRoutes.js index 513429f4..211937fd 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -59,7 +59,9 @@ router.post("/signup", async (reqest, response) => { success: true, message: "User created successfully", response: { - savedUser: savedUser + email: savedUser.email, + id: savedUser._id, + accessToken: savedUser.accessToken } }) From 3aed50aa5e4c17fa099a05721cb541b9c8fe8b85 Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Wed, 27 May 2026 16:13:50 +0200 Subject: [PATCH 16/29] more debugging for signup route --- routes/userRoutes.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/routes/userRoutes.js b/routes/userRoutes.js index 211937fd..e815d581 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -49,8 +49,7 @@ router.post("/signup", async (reqest, response) => { firstName, lastName, email, - password: hashedPassword, - accessToken + password: hashedPassword }) const savedUser = await user.save() From d24e3845ddf30cf15ac737aebac5c19a29049112 Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Wed, 27 May 2026 17:16:28 +0200 Subject: [PATCH 17/29] fixed variable name --- middleware/authMiddleware.js | 6 +++--- routes/happyThoughtsRoutes.js | 16 ++++++++-------- routes/userRoutes.js | 8 ++++---- server.js | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/middleware/authMiddleware.js b/middleware/authMiddleware.js index ee339ea0..300409ae 100644 --- a/middleware/authMiddleware.js +++ b/middleware/authMiddleware.js @@ -1,11 +1,11 @@ import { User } from "../models/User.js" -export const authenticateUser = async (reqest, response, next) => { +export const authenticateUser = async (request, response, next) => { try { - const user = await User.findOne({ accessToken: req.header("Authorization").replace("Bearer", "")}) + const user = await User.findOne({ accessToken: request.header("Authorization").replace("Bearer", "")}) if (user) { - reqest.user = user + request.user = user next() } else { response.status(401).json({ diff --git a/routes/happyThoughtsRoutes.js b/routes/happyThoughtsRoutes.js index cc4db305..fc9bdcf0 100644 --- a/routes/happyThoughtsRoutes.js +++ b/routes/happyThoughtsRoutes.js @@ -7,9 +7,9 @@ const router = express.Router() seedingThoughts() -router.get("/", async (reqest, response) => { +router.get("/", async (request, response) => { - const { minLikes } = reqest.query + const { minLikes } = request.query console.log("min likes", minLikes) const query = {} @@ -43,8 +43,8 @@ router.get("/", async (reqest, response) => { } }) -router.post("/", authenticateUser, async (reqest, response) => { - const { message } = reqest.body +router.post("/", authenticateUser, async (request, response) => { + const { message } = request.body try { const newHappyThought = await new HappyThought({ message }).save() @@ -64,8 +64,8 @@ router.post("/", authenticateUser, async (reqest, response) => { }) -router.get("/:id", async (reqest, response) => { - const { id } = reqest.params +router.get("/:id", async (request, response) => { + const { id } = request.params try { const happyThought = await HappyThought.findById(id) @@ -92,8 +92,8 @@ router.get("/:id", async (reqest, response) => { }) -router.delete("/:id", authenticateUser, async (reqest, response) => { - const { id } = reqest.params +router.delete("/:id", authenticateUser, async (request, response) => { + const { id } = request.params try { diff --git a/routes/userRoutes.js b/routes/userRoutes.js index e815d581..ffe53a0f 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -30,9 +30,9 @@ router.get("/:id", async (request, response) => { } }) -router.post("/signup", async (reqest, response) => { +router.post("/signup", async (request, response) => { try { - const { firstName, lastName, email, password } = reqest.body + const { firstName, lastName, email, password } = request.body const existingUser = await User.findOne({ email: email.toLowerCase()}) if (existingUser) { @@ -73,9 +73,9 @@ router.post("/signup", async (reqest, response) => { } }) -router.post("/login", async (reqest, response) => { +router.post("/login", async (request, response) => { try { - const { email, password } = reqest.body + const { email, password } = request.body const user = await User.findOne({email: email.toLowerCase()}) if (user && bcrypt.compareSync(password, user.password)) { diff --git a/server.js b/server.js index 972d25c9..2eacd311 100644 --- a/server.js +++ b/server.js @@ -21,7 +21,7 @@ app.use(express.json()) // Start defining your routes here -app.get("/", (reqest, response) => { +app.get("/", (request, response) => { const endpoints = listEndpoints(app) response.json({ From 1f47018c7f30c6bcd00cd9aac58279bd515bdddd Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Wed, 27 May 2026 18:31:55 +0200 Subject: [PATCH 18/29] debugg in auth middleware --- middleware/authMiddleware.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/middleware/authMiddleware.js b/middleware/authMiddleware.js index 300409ae..7bb5294e 100644 --- a/middleware/authMiddleware.js +++ b/middleware/authMiddleware.js @@ -2,7 +2,7 @@ import { User } from "../models/User.js" export const authenticateUser = async (request, response, next) => { try { - const user = await User.findOne({ accessToken: request.header("Authorization").replace("Bearer", "")}) + const user = await User.findOne({ accessToken: request.header("Authorization").replace("Bearer ", "")}) if (user) { request.user = user From 62fc64e8d167f4cdd79dfa0b603c115af51ddb95 Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Wed, 27 May 2026 18:42:46 +0200 Subject: [PATCH 19/29] happy thoughts route: added sort by desc to get route --- routes/happyThoughtsRoutes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/happyThoughtsRoutes.js b/routes/happyThoughtsRoutes.js index fc9bdcf0..424df2b6 100644 --- a/routes/happyThoughtsRoutes.js +++ b/routes/happyThoughtsRoutes.js @@ -19,7 +19,7 @@ router.get("/", async (request, response) => { } try { - const filteredMessages = await HappyThought.find(query) + const filteredMessages = await HappyThought.find(query).sort({ createdAt: "desc" }) if (filteredMessages.length === 0) { return response.status(404).json({ From 93dfe6451b2858ffb7b9ce2a05b9cc2f50485c15 Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Wed, 27 May 2026 18:54:06 +0200 Subject: [PATCH 20/29] added reset users --- seedingDatabase/seedingUsers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seedingDatabase/seedingUsers.js b/seedingDatabase/seedingUsers.js index 128300cc..18416b66 100644 --- a/seedingDatabase/seedingUsers.js +++ b/seedingDatabase/seedingUsers.js @@ -4,7 +4,7 @@ import bcrypt from "bcrypt" export const seedingUsers = async () => { const salt = 10 - if (process.env.RESET_DB === "true") { + if (process.env.RESET_DB_USERS === "true") { console.log("Resetting seeding database..."); await User.deleteMany() } From b0adbbed3aa18f332bcdb237baf13a60970dba0b Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Fri, 29 May 2026 12:25:22 +0200 Subject: [PATCH 21/29] added email validation to signup and login route and added patch routes for liking and updating a happy thought --- routes/happyThoughtsRoutes.js | 69 +++++++++++++++++++++++++++++++++++ routes/userRoutes.js | 34 +++++++++++++++-- 2 files changed, 99 insertions(+), 4 deletions(-) diff --git a/routes/happyThoughtsRoutes.js b/routes/happyThoughtsRoutes.js index 424df2b6..50e6364a 100644 --- a/routes/happyThoughtsRoutes.js +++ b/routes/happyThoughtsRoutes.js @@ -92,6 +92,7 @@ router.get("/:id", async (request, response) => { }) + router.delete("/:id", authenticateUser, async (request, response) => { const { id } = request.params @@ -119,6 +120,74 @@ router.delete("/:id", authenticateUser, async (request, response) => { message: "Error deleting happy thought" }) } +}), + +router.patch("/:id/like", async (request, response) => { + const { id } = request.params + + try { + const happyThought = await HappyThought.findByIdAndUpdate(id, { $inc: {hearts: 1}}, { new: true }) + + if (!happyThought) { + return response.status(404).json({ + success: false, + response: null, + message: "Happy thought not found" + }) + } + + response.status(200).json({ + success: true, + response: happyThought, + message: "Happy thought liked successfully" + }) + } catch (error) { + response.status(500).json({ + success: false, + response: error, + message: "Error liking happy thought" + }) + } + +}) + +router.patch("/:id", async (request, response) => { + const { id } = request.params + const { message } = request.body + + try { + + if (!message || message.lengyh <5 || message.length > 140) { + return response.status(400).json({ + success: false, + response: null, + message: "Message must be between 5 and 140 characters" + }) + } + + const updatedHappyThought = await HappyThought.findByIdAndUpdate(id, { message }, { new: true}) + + if (!updatedHappyThought) { + return response.status(404).json({ + success: false, + response: null, + message: "Happy Thought not found" + }) + } + + return response.status(200).json({ + success: true, + response: updatedHappyThought, + message: "Happy Thought updated successfully" + }) + + } catch (error) { + response.status(500).json({ + success: false, + response: null, + message: "Could not update thought" + }) + } }) export default router \ No newline at end of file diff --git a/routes/userRoutes.js b/routes/userRoutes.js index ffe53a0f..78f81f81 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -7,6 +7,11 @@ const router = express.Router() seedingUsers() +const validateEmail = (email) => { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ + return emailRegex.test(email) +} + router.get("/:id", async (request, response) => { try { const { id } = request.params @@ -33,7 +38,17 @@ router.get("/:id", async (request, response) => { router.post("/signup", async (request, response) => { try { const { firstName, lastName, email, password } = request.body - const existingUser = await User.findOne({ email: email.toLowerCase()}) + + if(!email || !validateEmail(email)) { + return response.status(400).json({ + success: false, + message: "Invalid email format" + }) + } + + const normalizedEmail = email.toLowerCase() + + const existingUser = await User.findOne({ email: normalizedEmail}) if (existingUser) { return response.status(409).json({ @@ -42,13 +57,14 @@ router.post("/signup", async (request, response) => { }) } + const salt = bcrypt.genSaltSync() const hashedPassword = bcrypt.hashSync(password, salt) const user = new User({ firstName, lastName, - email, + email: normalizedEmail, password: hashedPassword }) @@ -68,7 +84,7 @@ router.post("/signup", async (request, response) => { response.status(400).json({ success: false, message: "failed to create user", - response: error + response: error.message }) } }) @@ -76,7 +92,17 @@ router.post("/signup", async (request, response) => { router.post("/login", async (request, response) => { try { const { email, password } = request.body - const user = await User.findOne({email: email.toLowerCase()}) + + if(!email || !validateEmail(email)) { + return response.status(400).json({ + success: false, + message: "Invalid email format" + }) + } + + const normalizedEmail = email.toLowerCase() + + const user = await User.findOne({email: normalizedEmail}) if (user && bcrypt.compareSync(password, user.password)) { response.status(200).json({ From c7bd4aec73d7ac469b43ae3b5f1d20b08c8d9a01 Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Fri, 29 May 2026 13:22:15 +0200 Subject: [PATCH 22/29] added ping route for cron-job, to wake up api --- server.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/server.js b/server.js index 2eacd311..be86a9f9 100644 --- a/server.js +++ b/server.js @@ -30,6 +30,11 @@ app.get("/", (request, response) => { }) }) +// Wake up API with cron-job, scheduled to end: 1 july 2026 kl: 13:00 +app.get('/ping', (request, response) => { + response.status(200).send('pong'); +}); + app.use("/happy-thoughts", happyThoughtsRoutes) app.use("/users", userRoutes) From 64d89eb38c51ad8eaf273c02d7d2243f76a36c5e Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Fri, 29 May 2026 15:14:19 +0200 Subject: [PATCH 23/29] added auth middleware to id patch route --- routes/happyThoughtsRoutes.js | 61 ++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/routes/happyThoughtsRoutes.js b/routes/happyThoughtsRoutes.js index 50e6364a..3b6f8f99 100644 --- a/routes/happyThoughtsRoutes.js +++ b/routes/happyThoughtsRoutes.js @@ -120,38 +120,9 @@ router.delete("/:id", authenticateUser, async (request, response) => { message: "Error deleting happy thought" }) } -}), - -router.patch("/:id/like", async (request, response) => { - const { id } = request.params - - try { - const happyThought = await HappyThought.findByIdAndUpdate(id, { $inc: {hearts: 1}}, { new: true }) - - if (!happyThought) { - return response.status(404).json({ - success: false, - response: null, - message: "Happy thought not found" - }) - } - - response.status(200).json({ - success: true, - response: happyThought, - message: "Happy thought liked successfully" - }) - } catch (error) { - response.status(500).json({ - success: false, - response: error, - message: "Error liking happy thought" - }) - } - }) -router.patch("/:id", async (request, response) => { +router.patch("/:id", authenticateUser, async (request, response) => { const { id } = request.params const { message } = request.body @@ -190,4 +161,34 @@ router.patch("/:id", async (request, response) => { } }) +router.patch("/:id/like", async (request, response) => { + const { id } = request.params + + try { + const happyThought = await HappyThought.findByIdAndUpdate(id, { $inc: {hearts: 1}}, { new: true }) + + if (!happyThought) { + return response.status(404).json({ + success: false, + response: null, + message: "Happy thought not found" + }) + } + + response.status(200).json({ + success: true, + response: happyThought, + message: "Happy thought liked successfully" + }) + } catch (error) { + response.status(500).json({ + success: false, + response: error, + message: "Error liking happy thought" + }) + } + +}) + + export default router \ No newline at end of file From 9fc67b7858bcd21f14a4e3baff17a55b3718236b Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Fri, 29 May 2026 21:13:36 +0200 Subject: [PATCH 24/29] commented out seeding thoughts --- routes/happyThoughtsRoutes.js | 4 ++-- seedingDatabase/seedingThoughts.js | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/routes/happyThoughtsRoutes.js b/routes/happyThoughtsRoutes.js index 3b6f8f99..8b136e49 100644 --- a/routes/happyThoughtsRoutes.js +++ b/routes/happyThoughtsRoutes.js @@ -1,11 +1,11 @@ import express from "express" import { authenticateUser } from "../middleware/authMiddleware.js" import { HappyThought } from "../models/HappyThought.js" -import { seedingThoughts } from "../seedingDatabase/seedingThoughts.js" +// import { seedingThoughts } from "../seedingDatabase/seedingThoughts.js" const router = express.Router() -seedingThoughts() +// seedingThoughts() router.get("/", async (request, response) => { diff --git a/seedingDatabase/seedingThoughts.js b/seedingDatabase/seedingThoughts.js index eca5211d..8a97fa9b 100644 --- a/seedingDatabase/seedingThoughts.js +++ b/seedingDatabase/seedingThoughts.js @@ -1,18 +1,18 @@ -import { HappyThought } from "../models/HappyThought.js" +// import { HappyThought } from "../models/HappyThought.js" -export const seedingThoughts = async () => { +// export const seedingThoughts = async () => { - if (process.env.RESET_DB === "true") { - console.log("Resetting seeding database..."); - await HappyThought.deleteMany() - } +// if (process.env.RESET_DB === "true") { +// console.log("Resetting seeding database..."); +// await HappyThought.deleteMany() +// } - await new HappyThought ({ - message: "Carolina's happy thought" - }).save(); +// await new HappyThought ({ +// message: "Carolina's happy thought" +// }).save(); - await new HappyThought ({ - message: "Mikaela's happy thought" - }).save(); +// await new HappyThought ({ +// message: "Mikaela's happy thought" +// }).save(); -} \ No newline at end of file +// } \ No newline at end of file From 8e5cbd025d83af352f440bfb0c9f10bba4272612 Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Fri, 29 May 2026 21:22:39 +0200 Subject: [PATCH 25/29] deleted seeding datbased --- routes/happyThoughtsRoutes.js | 3 --- routes/userRoutes.js | 3 --- seedingDatabase/seedingThoughts.js | 18 ------------------ seedingDatabase/seedingUsers.js | 25 ------------------------- 4 files changed, 49 deletions(-) delete mode 100644 seedingDatabase/seedingThoughts.js delete mode 100644 seedingDatabase/seedingUsers.js diff --git a/routes/happyThoughtsRoutes.js b/routes/happyThoughtsRoutes.js index 8b136e49..9de94f86 100644 --- a/routes/happyThoughtsRoutes.js +++ b/routes/happyThoughtsRoutes.js @@ -1,12 +1,9 @@ import express from "express" import { authenticateUser } from "../middleware/authMiddleware.js" import { HappyThought } from "../models/HappyThought.js" -// import { seedingThoughts } from "../seedingDatabase/seedingThoughts.js" const router = express.Router() -// seedingThoughts() - router.get("/", async (request, response) => { const { minLikes } = request.query diff --git a/routes/userRoutes.js b/routes/userRoutes.js index 78f81f81..9d388f67 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -1,12 +1,9 @@ import express from "express" import bcrypt from "bcrypt" import { User } from "../models/User.js" -import { seedingUsers } from "../seedingDatabase/seedingUsers.js" const router = express.Router() -seedingUsers() - const validateEmail = (email) => { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ return emailRegex.test(email) diff --git a/seedingDatabase/seedingThoughts.js b/seedingDatabase/seedingThoughts.js deleted file mode 100644 index 8a97fa9b..00000000 --- a/seedingDatabase/seedingThoughts.js +++ /dev/null @@ -1,18 +0,0 @@ -// import { HappyThought } from "../models/HappyThought.js" - -// export const seedingThoughts = async () => { - -// if (process.env.RESET_DB === "true") { -// console.log("Resetting seeding database..."); -// await HappyThought.deleteMany() -// } - -// await new HappyThought ({ -// message: "Carolina's happy thought" -// }).save(); - -// await new HappyThought ({ -// message: "Mikaela's happy thought" -// }).save(); - -// } \ No newline at end of file diff --git a/seedingDatabase/seedingUsers.js b/seedingDatabase/seedingUsers.js deleted file mode 100644 index 18416b66..00000000 --- a/seedingDatabase/seedingUsers.js +++ /dev/null @@ -1,25 +0,0 @@ -import { User } from "../models/User.js" -import bcrypt from "bcrypt" - -export const seedingUsers = async () => { - const salt = 10 - - if (process.env.RESET_DB_USERS === "true") { - console.log("Resetting seeding database..."); - await User.deleteMany() - } - - await new User ({ - firstName: "Carolina", - lastName: "Oldertz", - email: "carolina.oldertz@gmail.com", - password: bcrypt.hashSync("carolina", salt) - }).save(); - - await new User ({ - firstName: "Mikaela", - lastName: "Sturk", - email: "mikaelasturk@gmail.com", - password: bcrypt.hashSync("mikaela", salt) - }).save() -} \ No newline at end of file From b3e90c406539bf96aef76308d0fa758c5d559c46 Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Fri, 29 May 2026 21:35:31 +0200 Subject: [PATCH 26/29] added render link in readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0f9f073d..5cb62b77 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Project API +render: https://happy-thoughts-api-o47r.onrender.com + 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 From 204861838ee16a5f6f00cfaa30ae2cabbe6fbd3e Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Wed, 24 Jun 2026 17:07:14 +0200 Subject: [PATCH 27/29] refactor: enhance authentication and author validation in HappyThought routes --- middleware/authMiddleware.js | 12 ++++++- models/HappyThought.js | 5 +++ routes/happyThoughtsRoutes.js | 59 ++++++++++++++++++++++++++++++++--- 3 files changed, 71 insertions(+), 5 deletions(-) diff --git a/middleware/authMiddleware.js b/middleware/authMiddleware.js index 7bb5294e..8b19f608 100644 --- a/middleware/authMiddleware.js +++ b/middleware/authMiddleware.js @@ -2,7 +2,17 @@ import { User } from "../models/User.js" export const authenticateUser = async (request, response, next) => { try { - const user = await User.findOne({ accessToken: request.header("Authorization").replace("Bearer ", "")}) + + const authHeader = request.header("Authorization") || request.get("Authorization") + + if(!authHeader) { + return response.status(401).json({ + message: "Authentication missing or invalid", + loggedOut: true + }) + } + + const user = await User.findOne({ accessToken: authHeader.replace("Bearer ", "")}) if (user) { request.user = user diff --git a/models/HappyThought.js b/models/HappyThought.js index 59638791..a59c6805 100644 --- a/models/HappyThought.js +++ b/models/HappyThought.js @@ -11,6 +11,11 @@ const happyThoughtSchema = new mongoose.Schema({ createdAt: { type: Date, default: Date.now + }, + author: { + type: mongoose.Schema.Types.ObjectId, + ref: "User", + required: true } }) diff --git a/routes/happyThoughtsRoutes.js b/routes/happyThoughtsRoutes.js index 9de94f86..4555069e 100644 --- a/routes/happyThoughtsRoutes.js +++ b/routes/happyThoughtsRoutes.js @@ -7,7 +7,6 @@ const router = express.Router() router.get("/", async (request, response) => { const { minLikes } = request.query - console.log("min likes", minLikes) const query = {} @@ -44,7 +43,7 @@ router.post("/", authenticateUser, async (request, response) => { const { message } = request.body try { - const newHappyThought = await new HappyThought({ message }).save() + const newHappyThought = await new HappyThought({ message, author: request.user._id }).save() response.status(201).json({ success: true, @@ -93,8 +92,42 @@ router.get("/:id", async (request, response) => { router.delete("/:id", authenticateUser, async (request, response) => { const { id } = request.params + if (!id || !mongoose.isValidObjectId(id)) { + return response.status(400).json({ + success: false, + response: null, + message: "Invalid ID" + }) + } + + if (!request.user || !request.user._id) { + return response.status(401).json({ + success: false, + response: null, + message: "User not authenticated" + }) + } + try { - + + const thought = await HappyThought.findById(id) + + if (!thought) { + return response.status(404).json({ + success: false, + response: null, + message: "Happy thought not found" + }) + } + + if (!thought.author || !thought.author.equals(request.user._id)) { + return response.status(403).json({ + success: false, + response: null, + message: "You are not authorized to delete this thought" + }) + } + const deletedThought = await HappyThought.findByIdAndDelete(id) if (!deletedThought) { @@ -125,7 +158,7 @@ router.patch("/:id", authenticateUser, async (request, response) => { try { - if (!message || message.lengyh <5 || message.length > 140) { + if (!message || message.length <5 || message.length > 140) { return response.status(400).json({ success: false, response: null, @@ -133,6 +166,24 @@ router.patch("/:id", authenticateUser, async (request, response) => { }) } + const thought = await HappyThought.findById(id) + + if (!thought) { + return response.status(404).json({ + success: false, + response: null, + message: "Happy Thought not found" + }) + } + + if (!thought.author.equals(request.user._id)) { + return response.status(403).json({ + success: false, + response: null, + message: "You are not authorized to update this thought" + }) + } + const updatedHappyThought = await HappyThought.findByIdAndUpdate(id, { message }, { new: true}) if (!updatedHappyThought) { From 323cea93716050c1e184e7d0939bcee0ea95dd94 Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Wed, 24 Jun 2026 17:32:20 +0200 Subject: [PATCH 28/29] refactor: improve author population in HappyThought routes --- routes/happyThoughtsRoutes.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/routes/happyThoughtsRoutes.js b/routes/happyThoughtsRoutes.js index 4555069e..8bff7a81 100644 --- a/routes/happyThoughtsRoutes.js +++ b/routes/happyThoughtsRoutes.js @@ -15,7 +15,10 @@ router.get("/", async (request, response) => { } try { - const filteredMessages = await HappyThought.find(query).sort({ createdAt: "desc" }) + + const filteredMessages = await HappyThought.find(query) + .sort({ createdAt: "desc" }) + .populate("author", "firstName lastName") if (filteredMessages.length === 0) { return response.status(404).json({ @@ -44,7 +47,7 @@ router.post("/", authenticateUser, async (request, response) => { try { const newHappyThought = await new HappyThought({ message, author: request.user._id }).save() - + await newHappyThought.populate("author", "firstName lastName") response.status(201).json({ success: true, response: newHappyThought, @@ -64,14 +67,13 @@ router.get("/:id", async (request, response) => { const { id } = request.params try { - const happyThought = await HappyThought.findById(id) - + const happyThought = await HappyThought.findById(id).populate("author", "firstName lastName") if (!happyThought) { return response.status(404).json({ success: false, response: null, message: "Happy thought not found" - }) + }) } response.status(200).json({ From a39640d7f7c76735eed7389435acc5d8bb0b959e Mon Sep 17 00:00:00 2001 From: Carolina Oldertz Date: Wed, 24 Jun 2026 17:58:51 +0200 Subject: [PATCH 29/29] refactor: enhance author validation in delete route for HappyThoughts --- routes/happyThoughtsRoutes.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/routes/happyThoughtsRoutes.js b/routes/happyThoughtsRoutes.js index 8bff7a81..7a997362 100644 --- a/routes/happyThoughtsRoutes.js +++ b/routes/happyThoughtsRoutes.js @@ -1,4 +1,5 @@ import express from "express" +import mongoose from "mongoose" import { authenticateUser } from "../middleware/authMiddleware.js" import { HappyThought } from "../models/HappyThought.js" @@ -122,7 +123,9 @@ router.delete("/:id", authenticateUser, async (request, response) => { }) } - if (!thought.author || !thought.author.equals(request.user._id)) { + // säker ägarcheck: fungerar om author är ObjectId eller populated object + const authorId = thought.author?._id ? thought.author._id.toString() : thought.author?.toString() + if (!authorId || authorId !== request.user._id.toString()) { return response.status(403).json({ success: false, response: null,