From b58c5c60a98bacdd9c2514756c4d3cd1b45c6380 Mon Sep 17 00:00:00 2001 From: simfrisk Date: Tue, 27 May 2025 20:24:23 +0200 Subject: [PATCH 01/24] Got the project started --- data.json | 10 +++++----- package.json | 6 +++--- server.js | 19 ++++++++++++++++++- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/data.json b/data.json index a2c844f..62b0fd7 100644 --- a/data.json +++ b/data.json @@ -1,5 +1,5 @@ [ - { + { "_id": "682bab8c12155b00101732ce", "message": "Berlin baby", "hearts": 37, @@ -7,7 +7,7 @@ "__v": 0 }, { - "_id": "682e53cc4fddf50010bbe739", + "_id": "682e53cc4fddf50010bbe739", "message": "My family!", "hearts": 0, "createdAt": "2025-05-22T22:29:32.232Z", @@ -25,7 +25,7 @@ "message": "Newly washed bedlinen, kids that sleeps through the night.. FINGERS CROSSED 🤞🏼\n", "hearts": 6, "createdAt": "2025-05-21T21:42:23.862Z", - "__v": 0 + "__v": 0 }, { "_id": "682e45804fddf50010bbe736", @@ -53,7 +53,7 @@ "message": "A god joke: \nWhy did the scarecrow win an award?\nBecause he was outstanding in his field!", "hearts": 12, "createdAt": "2025-05-20T20:54:51.082Z", - "__v": 0 + "__v": 0 }, { "_id": "682cebbe17487d0010a298b5", @@ -74,7 +74,7 @@ "message": "Summer is coming...", "hearts": 2, "createdAt": "2025-05-20T15:03:22.379Z", - "__v": 0 + "__v": 0 }, { "_id": "682c706c951f7a0017130024", diff --git a/package.json b/package.json index bf25bb6..187c3ab 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", "cors": "^2.8.5", - "express": "^4.17.3", - "nodemon": "^3.0.1" + "express": "^4.21.2", + "nodemon": "^3.1.10" } -} +} \ No newline at end of file diff --git a/server.js b/server.js index f47771b..5f38107 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,6 @@ import cors from "cors" import express from "express" +import thoughtData 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: @@ -13,7 +14,23 @@ app.use(express.json()) // Start defining your routes here app.get("/", (req, res) => { - res.send("Hello Technigo!") + res.send("Hello Simon!") +}) + +app.get("/thoughts", (req, res) => { + res.json(thoughtData) +}) + +app.get("/thoughts/:id", (req, res) => { + const thought = thoughtData.find(thought => thought._id === req.params.id) + + console.log(thought) + + if (!thought) { + return res.send("error: Thought not found") + } + + res.json(thought) }) // Start the server From 403c8450d80ca2fd1b7fb02fc21364fba4111b5d Mon Sep 17 00:00:00 2001 From: simfrisk Date: Wed, 28 May 2025 13:51:38 +0200 Subject: [PATCH 02/24] added sort by hearts --- package.json | 3 ++- server.js | 41 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 187c3ab..e01ae4d 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@babel/preset-env": "^7.16.11", "cors": "^2.8.5", "express": "^4.21.2", + "express-list-endpoints": "^7.1.1", "nodemon": "^3.1.10" } -} \ No newline at end of file +} diff --git a/server.js b/server.js index 5f38107..e9b5986 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,7 @@ import cors from "cors" import express from "express" import thoughtData 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,11 +15,25 @@ app.use(express.json()) // Start defining your routes here app.get("/", (req, res) => { - res.send("Hello Simon!") -}) + const endpoints = listEndpoints(app) + res.json({ + message: "Welcome to the Happy Thoughts API", + endpoints: endpoints + }) + +}); app.get("/thoughts", (req, res) => { - res.json(thoughtData) + + const { hearts } = req.query + + let sortedThoughts = thoughtData + + if (hearts) { + sortedThoughts = sortedThoughts.sort((a, b) => a.hearts - b.hearts) + } + + res.json(sortedThoughts) }) app.get("/thoughts/:id", (req, res) => { @@ -33,6 +48,26 @@ app.get("/thoughts/:id", (req, res) => { res.json(thought) }) +// app.get("/flowers", (req, res) => { + +// const { color, symbol } = req.query + +// let filteredFlowers = flowerData + +// if (color) { +// filteredFlowers = filteredFlowers.filter(flower => flower.color.toLowerCase() === color.toLowerCase()) +// } + +// if (symbol) { +// filteredFlowers = filteredFlowers.filter(flower => +// flower.symbolism.some(word => word.toLowerCase() === symbol.toLowerCase()) +// ) +// } + +// res.json(filteredFlowers) +// }) + + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) From 1f3bf9a21951f21424fe203eff5424cf880bdcd0 Mon Sep 17 00:00:00 2001 From: simfrisk Date: Wed, 28 May 2025 14:43:30 +0200 Subject: [PATCH 03/24] cleaned up the project --- data.json | 4 +-- endpoints/getHome.js | 9 +++++ endpoints/getThoughtById.js | 13 +++++++ server.js | 68 +++++++++++-------------------------- utils/getFiltredThoughts.js | 12 +++++++ utils/getSortedThoughts.js | 10 ++++++ 6 files changed, 66 insertions(+), 50 deletions(-) create mode 100644 endpoints/getHome.js create mode 100644 endpoints/getThoughtById.js create mode 100644 utils/getFiltredThoughts.js create mode 100644 utils/getSortedThoughts.js diff --git a/data.json b/data.json index 62b0fd7..ee86380 100644 --- a/data.json +++ b/data.json @@ -2,7 +2,7 @@ { "_id": "682bab8c12155b00101732ce", "message": "Berlin baby", - "hearts": 37, + "hearts": 2, "createdAt": "2025-05-19T22:07:08.999Z", "__v": 0 }, @@ -23,7 +23,7 @@ { "_id": "682e48bf4fddf50010bbe737", "message": "Newly washed bedlinen, kids that sleeps through the night.. FINGERS CROSSED 🤞🏼\n", - "hearts": 6, + "hearts": 62, "createdAt": "2025-05-21T21:42:23.862Z", "__v": 0 }, diff --git a/endpoints/getHome.js b/endpoints/getHome.js new file mode 100644 index 0000000..874820d --- /dev/null +++ b/endpoints/getHome.js @@ -0,0 +1,9 @@ +import listEndpoints from "express-list-endpoints"; + +export const getHome = (app) => (req, res) => { + const endpoints = listEndpoints(app); + res.json({ + message: "Welcome to the Happy Thoughts API", + endpoints, + }); +}; \ No newline at end of file diff --git a/endpoints/getThoughtById.js b/endpoints/getThoughtById.js new file mode 100644 index 0000000..3bf0156 --- /dev/null +++ b/endpoints/getThoughtById.js @@ -0,0 +1,13 @@ +import thoughtData from "../data.json"; + +export const getThoughtById = (req, res) => { + const thought = thoughtData.find(thought => thought._id === req.params.id); + + console.log(thought); + + if (!thought) { + return res.status(404).send({ error: "Thought not found" }); + } + + res.json(thought); +}; \ No newline at end of file diff --git a/server.js b/server.js index e9b5986..2dc0cf9 100644 --- a/server.js +++ b/server.js @@ -1,71 +1,43 @@ import cors from "cors" import express from "express" import thoughtData from "./data.json" -import listEndpoints from 'express-list-endpoints' +import { getSortedThoughts } from "./utils/getSortedThoughts" +import { getFilteredThoughts } from "./utils/getFiltredThoughts" +import { getThoughtById } from "./endpoints/getThoughtById" +import { getHome } from "./endpoints/getHome" -// 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 +// The setup of the port const port = process.env.PORT || 8080 const app = express() -// Add middlewares to enable cors and json body parsing +// The middleware 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 - }) - -}); +// The home with the api documentation +app.get("/", getHome(app)) +// The main thoughts and querys app.get("/thoughts", (req, res) => { + const { minHearts, sort } = req.query - const { hearts } = req.query - - let sortedThoughts = thoughtData + let result = thoughtData - if (hearts) { - sortedThoughts = sortedThoughts.sort((a, b) => a.hearts - b.hearts) + // Filters the hearts by the number and above + if (minHearts) { + result = getFilteredThoughts(result, minHearts) } - res.json(sortedThoughts) -}) - -app.get("/thoughts/:id", (req, res) => { - const thought = thoughtData.find(thought => thought._id === req.params.id) - - console.log(thought) - - if (!thought) { - return res.send("error: Thought not found") + // Sorts the heart in an accending order + if (sort === "hearts") { + result = getSortedThoughts(result, true) } - res.json(thought) + res.json(result) }) -// app.get("/flowers", (req, res) => { - -// const { color, symbol } = req.query - -// let filteredFlowers = flowerData - -// if (color) { -// filteredFlowers = filteredFlowers.filter(flower => flower.color.toLowerCase() === color.toLowerCase()) -// } - -// if (symbol) { -// filteredFlowers = filteredFlowers.filter(flower => -// flower.symbolism.some(word => word.toLowerCase() === symbol.toLowerCase()) -// ) -// } - -// res.json(filteredFlowers) -// }) +//Get an endpoint for a specific thought by ID +app.get("/thoughts/:id", getThoughtById) // Start the server diff --git a/utils/getFiltredThoughts.js b/utils/getFiltredThoughts.js new file mode 100644 index 0000000..726f21a --- /dev/null +++ b/utils/getFiltredThoughts.js @@ -0,0 +1,12 @@ + +export const getFilteredThoughts = (thoughts, heartsQuery) => { + let filteredThoughts = thoughts + + if (heartsQuery) { + filteredThoughts = filteredThoughts.filter( + (thought) => Number(thought.hearts) >= Number(heartsQuery) + ) + } + + return filteredThoughts +}; \ No newline at end of file diff --git a/utils/getSortedThoughts.js b/utils/getSortedThoughts.js new file mode 100644 index 0000000..9205af9 --- /dev/null +++ b/utils/getSortedThoughts.js @@ -0,0 +1,10 @@ + +export const getSortedThoughts = (thoughts, heartsQuery) => { + let sortedThoughts = thoughts + + if (heartsQuery) { + sortedThoughts = [...thoughts].sort((a, b) => b.hearts - a.hearts) + } + + return sortedThoughts +} \ No newline at end of file From ffbbc58ef7393cdaa3ffb9bc3e53703518704d23 Mon Sep 17 00:00:00 2001 From: simfrisk Date: Wed, 28 May 2025 18:33:07 +0200 Subject: [PATCH 04/24] Added pages and documentation --- endpoints/getHome.js | 6 ++++++ server.js | 24 +++++++++++++++++++++--- utils/getPages.js | 6 ++++++ 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 utils/getPages.js diff --git a/endpoints/getHome.js b/endpoints/getHome.js index 874820d..57bc954 100644 --- a/endpoints/getHome.js +++ b/endpoints/getHome.js @@ -5,5 +5,11 @@ export const getHome = (app) => (req, res) => { res.json({ message: "Welcome to the Happy Thoughts API", endpoints, + thoughtQueries: { + minimumHearts: "http://localhost:8080/thoughts?minHearts=10", + sortByHearts: "http://localhost:8080/thoughts?sort=hearts", + pages: "http://localhost:8080/thoughts?page=1", + combined: "http://localhost:8080/thoughts?minHearts=5&sort=hearts&page=1" + } }); }; \ No newline at end of file diff --git a/server.js b/server.js index 2dc0cf9..afd6502 100644 --- a/server.js +++ b/server.js @@ -1,3 +1,4 @@ +//#region ---- Imports ---- import cors from "cors" import express from "express" import thoughtData from "./data.json" @@ -5,7 +6,10 @@ import { getSortedThoughts } from "./utils/getSortedThoughts" import { getFilteredThoughts } from "./utils/getFiltredThoughts" import { getThoughtById } from "./endpoints/getThoughtById" import { getHome } from "./endpoints/getHome" +import { getPages } from "./utils/getPages" +//#endregion +//#region ---- Set up ---- // The setup of the port const port = process.env.PORT || 8080 const app = express() @@ -14,33 +18,47 @@ const app = express() app.use(cors()) app.use(express.json()) +//#endregion + +//#region ---- endpoint ---- // The home with the api documentation app.get("/", getHome(app)) // The main thoughts and querys app.get("/thoughts", (req, res) => { - const { minHearts, sort } = req.query + const { minHearts, sort, page } = req.query let result = thoughtData // Filters the hearts by the number and above + // URL example: http://localhost:8080/thoughts?minHearts=10 if (minHearts) { result = getFilteredThoughts(result, minHearts) } // Sorts the heart in an accending order + //URL exapmle: http://localhost:8080/thoughts?sort=hearts if (sort === "hearts") { result = getSortedThoughts(result, true) } - res.json(result) + // Page function + // URL example: http://localhost:8080/thoughts?page=1 + const pagedResults = getPages(result, page) + + //Renders the Thoughts + res.json(pagedResults) }) //Get an endpoint for a specific thought by ID +// URL example: http://localhost:8080/thoughts/682e48bf4fddf50010bbe737 app.get("/thoughts/:id", getThoughtById) +//#endregion -// Start the server +//#region ---- Starts the server ---- app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) }) + +//#endregion \ No newline at end of file diff --git a/utils/getPages.js b/utils/getPages.js new file mode 100644 index 0000000..daf8092 --- /dev/null +++ b/utils/getPages.js @@ -0,0 +1,6 @@ +export const getPages = (result, page = 1, pageLenght = 5) => { + const pageNumber = Number(page) + const start = (pageNumber - 1) * pageLenght + const end = start + pageLenght + return result.slice(start, end) +} \ No newline at end of file From 805891d6878d2a078ca7998d3504266d9c4deb39 Mon Sep 17 00:00:00 2001 From: simfrisk Date: Tue, 3 Jun 2025 20:13:29 +0200 Subject: [PATCH 05/24] Added mongoose --- models/thought.js | 0 package.json | 1 + server.js | 67 +++++++++++++++++++++++++++++++++-------------- 3 files changed, 49 insertions(+), 19 deletions(-) create mode 100644 models/thought.js diff --git a/models/thought.js b/models/thought.js new file mode 100644 index 0000000..e69de29 diff --git a/package.json b/package.json index e01ae4d..2879578 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "cors": "^2.8.5", "express": "^4.21.2", "express-list-endpoints": "^7.1.1", + "mongoose": "^8.15.1", "nodemon": "^3.1.10" } } diff --git a/server.js b/server.js index afd6502..a67b2e8 100644 --- a/server.js +++ b/server.js @@ -7,8 +7,12 @@ import { getFilteredThoughts } from "./utils/getFiltredThoughts" import { getThoughtById } from "./endpoints/getThoughtById" import { getHome } from "./endpoints/getHome" import { getPages } from "./utils/getPages" +import { mongoose } from "mongoose" //#endregion +const mongoUrl = process.env.MONGO_URL || 'mongodb://localhost/testing'; +mongoose.connect(mongoUrl) + //#region ---- Set up ---- // The setup of the port const port = process.env.PORT || 8080 @@ -18,6 +22,29 @@ const app = express() app.use(cors()) app.use(express.json()) +const ThoughtSchema = new mongoose.Schema({ + _id: String, + message: String, + hearts: Number, + createdAt: { + type: Date, + default: Date.now + }, + __v: Number +}) + +const Thought = mongoose.model("Thought", ThoughtSchema) + +if (process.env.RESET_DB) { + const seedDatabase = async () => { + await Thought.deleteMany({}); + thoughtData.forEach(thought => { + new Thought(thought).save(); + }); + }; + seedDatabase(); +} + //#endregion //#region ---- endpoint ---- @@ -25,29 +52,31 @@ app.use(express.json()) app.get("/", getHome(app)) // The main thoughts and querys -app.get("/thoughts", (req, res) => { +app.get("/thoughts", async (req, res) => { + try { + const { minHearts, sort, page } = req.query + let result = await Thought.find() - const { minHearts, sort, page } = req.query - let result = thoughtData + // Filters the hearts by the number and above + // URL example: http://localhost:8080/thoughts?minHearts=10 + if (minHearts) { + result = getFilteredThoughts(result, minHearts) + } - // Filters the hearts by the number and above - // URL example: http://localhost:8080/thoughts?minHearts=10 - if (minHearts) { - result = getFilteredThoughts(result, minHearts) - } + // Sorts the heart in an accending order + //URL exapmle: http://localhost:8080/thoughts?sort=hearts + if (sort === "hearts") { + result = getSortedThoughts(result, true) + } - // Sorts the heart in an accending order - //URL exapmle: http://localhost:8080/thoughts?sort=hearts - if (sort === "hearts") { - result = getSortedThoughts(result, true) + // Page function + // URL example: http://localhost:8080/thoughts?page=1 + const pagedResults = getPages(result, page) + res.json(pagedResults) + } catch (error) { + console.error("Error fetching thoughts:", error) + res.status(500).json({ error: "Failed to fetch thoughts." }) } - - // Page function - // URL example: http://localhost:8080/thoughts?page=1 - const pagedResults = getPages(result, page) - - //Renders the Thoughts - res.json(pagedResults) }) //Get an endpoint for a specific thought by ID From 98697630a40683803edd878e14d6b71d12d22f4f Mon Sep 17 00:00:00 2001 From: simfrisk Date: Wed, 4 Jun 2025 21:53:05 +0200 Subject: [PATCH 06/24] Added alot --- endpoints/deleteThought.js | 30 +++++++++++++++++ endpoints/getThoughtById.js | 44 ++++++++++++++++++++----- endpoints/getThoughts.js | 30 +++++++++++++++++ endpoints/patchThought.js | 29 +++++++++++++++++ endpoints/postThought.js | 30 +++++++++++++++++ models/thought.js | 15 +++++++++ server.js | 65 ++++++++----------------------------- 7 files changed, 184 insertions(+), 59 deletions(-) create mode 100644 endpoints/deleteThought.js create mode 100644 endpoints/getThoughts.js create mode 100644 endpoints/patchThought.js create mode 100644 endpoints/postThought.js diff --git a/endpoints/deleteThought.js b/endpoints/deleteThought.js new file mode 100644 index 0000000..0d03483 --- /dev/null +++ b/endpoints/deleteThought.js @@ -0,0 +1,30 @@ +import { Thought } from "../models/thought" + +export const deleteThought = async (req, res) => { + const { id } = req.params + + try { + const thought = await Thought.findByIdAndDelete(id) + + if (!thought) { + return res.status(404).json({ + success: false, + response: null, + message: 'Thought could not be deleted' + }) + } + res.status(200).json({ + success: true, + response: thought, + message: 'The thought was deleted' + }) + + } catch (error) { + res.status(500).json({ + success: false, + response: error, + message: 'Could not delete thought' + } + ) + } +} \ No newline at end of file diff --git a/endpoints/getThoughtById.js b/endpoints/getThoughtById.js index 3bf0156..79b53b5 100644 --- a/endpoints/getThoughtById.js +++ b/endpoints/getThoughtById.js @@ -1,13 +1,41 @@ +import { response } from "express"; import thoughtData from "../data.json"; +import { Thought } from "../models/thought"; -export const getThoughtById = (req, res) => { - const thought = thoughtData.find(thought => thought._id === req.params.id); +export const getThoughtById = async (req, res) => { + const { id } = req.params - console.log(thought); - - if (!thought) { - return res.status(404).send({ error: "Thought not found" }); + try { + const thought = await Thought.findById(id) + if (!thought) { + return res.status(400).json({ + success: false, + response: null, + message: 'Thought not found' + }) + } + res.status(200).json({ + success: true, + response: thought, + message: 'The flower was found' + }) + } catch (error) { + res.status(500).json({ + success: false, + response: error, + message: 'Thought could not be found' + }) } - res.json(thought); -}; \ No newline at end of file +} + +// const thought = thoughtData.find(thought => thought._id === req.params.id); + +// console.log(thought); + +// if (!thought) { +// return res.status(404).send({ error: "Thought not found" }); +// } + +// res.json(thought); +// }; \ No newline at end of file diff --git a/endpoints/getThoughts.js b/endpoints/getThoughts.js new file mode 100644 index 0000000..44e36f4 --- /dev/null +++ b/endpoints/getThoughts.js @@ -0,0 +1,30 @@ +import { Thought } from "../models/thought"; +import { getPages } from "../utils/getPages"; +import { getSortedThoughts } from "../utils/getSortedThoughts"; + +export const getThoughts = async (req, res) => { + try { + const { minHearts, sort, page } = req.query + let result = await Thought.find() + + // Filters the hearts by the number and above + // URL example: http://localhost:8080/thoughts?minHearts=10 + if (minHearts) { + result = getFilteredThoughts(result, minHearts) + } + + // Sorts the heart in an accending order + //URL exapmle: http://localhost:8080/thoughts?sort=hearts + if (sort === "hearts") { + result = getSortedThoughts(result, true) + } + + // Page function + // URL example: http://localhost:8080/thoughts?page=1 + const pagedResults = getPages(result, page) + res.json(pagedResults) + } catch (error) { + console.error("Error fetching thoughts:", error) + res.status(500).json({ error: "Failed to fetch thoughts." }) + } +} \ No newline at end of file diff --git a/endpoints/patchThought.js b/endpoints/patchThought.js new file mode 100644 index 0000000..1410062 --- /dev/null +++ b/endpoints/patchThought.js @@ -0,0 +1,29 @@ +import { Thought } from "../models/thought" + +export const patchThought = async (req, res) => { + const { id } = req.params + const { newMessage } = req.body + + try { + const thought = await Thought.findByIdAndUpdate(id, { message: newMessage }, { new: true, runValidators: true }) + if (!thought) { + return res.status(400).json({ + success: false, + response: null, + message: 'Thought could not be changed' + }); + } + + res.status(201).json({ + success: true, + response: thought, + message: 'Thought successfully changed' + }); + } catch (error) { + res.status(400).json({ + success: false, + response: error, + message: 'Could not change thought in the database' + }); + } +} \ No newline at end of file diff --git a/endpoints/postThought.js b/endpoints/postThought.js new file mode 100644 index 0000000..55483b9 --- /dev/null +++ b/endpoints/postThought.js @@ -0,0 +1,30 @@ +import { Thought } from "../models/thought"; + +export const postThought = async (req, res) => { + const { message } = req.body; + const newThought = new Thought({ message }) + + try { + const savedNewThought = await newThought.save() + + if (!savedNewThought) { + return res.status(400).json({ + success: false, + response: null, + message: 'Thought could not be saved' + }); + } + + res.status(201).json({ + success: true, + response: savedNewThought, + message: 'Thought successfully saved' + }); + } catch (error) { + res.status(400).json({ + success: false, + response: error, + message: 'Could not save thought to the database' + }); + } +} \ No newline at end of file diff --git a/models/thought.js b/models/thought.js index e69de29..a7a5b71 100644 --- a/models/thought.js +++ b/models/thought.js @@ -0,0 +1,15 @@ +import mongoose from "mongoose"; + +const ThoughtSchema = new mongoose.Schema({ + message: String, + hearts: { + type: Number, + default: 0 + }, + createdAt: { + type: Date, + default: Date.now + } +}); + +export const Thought = mongoose.model("Thought", ThoughtSchema); \ No newline at end of file diff --git a/server.js b/server.js index a67b2e8..193b9cc 100644 --- a/server.js +++ b/server.js @@ -1,19 +1,22 @@ //#region ---- Imports ---- import cors from "cors" -import express from "express" +import express, { response } from "express" import thoughtData from "./data.json" -import { getSortedThoughts } from "./utils/getSortedThoughts" -import { getFilteredThoughts } from "./utils/getFiltredThoughts" import { getThoughtById } from "./endpoints/getThoughtById" +import { getThoughts } from "./endpoints/getThoughts" +import { postThought } from "./endpoints/postThought" +import { patchThought } from "./endpoints/patchThought" +import { deleteThought } from "./endpoints/deleteThought" import { getHome } from "./endpoints/getHome" -import { getPages } from "./utils/getPages" -import { mongoose } from "mongoose" +import { Thought } from "./models/thought" +import mongoose from "mongoose" //#endregion +//#region ---- Set up ---- + const mongoUrl = process.env.MONGO_URL || 'mongodb://localhost/testing'; mongoose.connect(mongoUrl) -//#region ---- Set up ---- // The setup of the port const port = process.env.PORT || 8080 const app = express() @@ -22,19 +25,6 @@ const app = express() app.use(cors()) app.use(express.json()) -const ThoughtSchema = new mongoose.Schema({ - _id: String, - message: String, - hearts: Number, - createdAt: { - type: Date, - default: Date.now - }, - __v: Number -}) - -const Thought = mongoose.model("Thought", ThoughtSchema) - if (process.env.RESET_DB) { const seedDatabase = async () => { await Thought.deleteMany({}); @@ -48,40 +38,13 @@ if (process.env.RESET_DB) { //#endregion //#region ---- endpoint ---- -// The home with the api documentation -app.get("/", getHome(app)) -// The main thoughts and querys -app.get("/thoughts", async (req, res) => { - try { - const { minHearts, sort, page } = req.query - let result = await Thought.find() - - // Filters the hearts by the number and above - // URL example: http://localhost:8080/thoughts?minHearts=10 - if (minHearts) { - result = getFilteredThoughts(result, minHearts) - } - - // Sorts the heart in an accending order - //URL exapmle: http://localhost:8080/thoughts?sort=hearts - if (sort === "hearts") { - result = getSortedThoughts(result, true) - } - - // Page function - // URL example: http://localhost:8080/thoughts?page=1 - const pagedResults = getPages(result, page) - res.json(pagedResults) - } catch (error) { - console.error("Error fetching thoughts:", error) - res.status(500).json({ error: "Failed to fetch thoughts." }) - } -}) - -//Get an endpoint for a specific thought by ID -// URL example: http://localhost:8080/thoughts/682e48bf4fddf50010bbe737 +app.get("/", getHome(app)) +app.get("/thoughts", getThoughts) app.get("/thoughts/:id", getThoughtById) +app.post("/thoughts", postThought) +app.patch("/thoughts/:id", patchThought) +app.delete('/thoughts/:id', deleteThought) //#endregion From 506c16a805d17d2cc7f3b6cb3689fd40d662636a Mon Sep 17 00:00:00 2001 From: simfrisk Date: Thu, 5 Jun 2025 04:59:53 +0200 Subject: [PATCH 07/24] Done some stuff --- data.json | 17 ----------------- endpoints/getThoughts.js | 6 ++++++ package.json | 1 + server.js | 5 +++++ utils/getFiltredThoughts.js | 1 - utils/getPages.js | 2 +- utils/getSortedThoughts.js | 1 - 7 files changed, 13 insertions(+), 20 deletions(-) diff --git a/data.json b/data.json index ee86380..6b603d6 100644 --- a/data.json +++ b/data.json @@ -1,118 +1,101 @@ [ { - "_id": "682bab8c12155b00101732ce", "message": "Berlin baby", "hearts": 2, "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": 62, "createdAt": "2025-05-21T21:42:23.862Z", "__v": 0 }, { - "_id": "682e45804fddf50010bbe736", "message": "I am happy that I feel healthy and have energy again", "hearts": 13, "createdAt": "2025-05-21T21:28:32.196Z", "__v": 0 }, { - "_id": "682e23fecf615800105107aa", "message": "cold beer", "hearts": 2, "createdAt": "2025-05-21T19:05:34.113Z", "__v": 0 }, { - "_id": "682e22aecf615800105107a9", "message": "My friend is visiting this weekend! <3", "hearts": 6, "createdAt": "2025-05-21T18:59:58.121Z", "__v": 0 }, { - "_id": "682cec1b17487d0010a298b6", "message": "A god joke: \nWhy did the scarecrow win an award?\nBecause he was outstanding in his field!", "hearts": 12, "createdAt": "2025-05-20T20:54:51.082Z", "__v": 0 }, { - "_id": "682cebbe17487d0010a298b5", "message": "Tacos and tequila🌮🍹", "hearts": 2, "createdAt": "2025-05-19T20:53:18.899Z", "__v": 0 }, { - "_id": "682ceb5617487d0010a298b4", "message": "Netflix and late night ice-cream🍦", "hearts": 1, "createdAt": "2025-05-18T20:51:34.494Z", "__v": 0 }, { - "_id": "682c99ba3bff2d0010f5d44e", "message": "Summer is coming...", "hearts": 2, "createdAt": "2025-05-20T15:03:22.379Z", "__v": 0 }, { - "_id": "682c706c951f7a0017130024", "message": "Exercise? I thought you said extra fries! 🍟😂", "hearts": 14, "createdAt": "2025-05-20T12:07:08.185Z", "__v": 0 }, { - "_id": "682c6fe1951f7a0017130023", "message": "I’m on a seafood diet. I see food, and I eat it.", "hearts": 4, "createdAt": "2025-05-20T12:04:49.978Z", "__v": 0 }, { - "_id": "682c6f0e951f7a0017130022", "message": "Cute monkeys🐒", "hearts": 2, "createdAt": "2025-05-20T12:01:18.308Z", "__v": 0 }, { - "_id": "682c6e65951f7a0017130021", "message": "The weather is nice!", "hearts": 0, "createdAt": "2025-05-20T11:58:29.662Z", "__v": 0 }, { - "_id": "682bfdb4270ca300105af221", "message": "good vibes and good things", "hearts": 3, "createdAt": "2025-05-20T03:57:40.322Z", "__v": 0 }, { - "_id": "682bab8c12155b00101732ce", "message": "Berlin baby", "hearts": 37, "createdAt": "2025-05-19T22:07:08.999Z", diff --git a/endpoints/getThoughts.js b/endpoints/getThoughts.js index 44e36f4..01b7532 100644 --- a/endpoints/getThoughts.js +++ b/endpoints/getThoughts.js @@ -1,6 +1,7 @@ import { Thought } from "../models/thought"; import { getPages } from "../utils/getPages"; import { getSortedThoughts } from "../utils/getSortedThoughts"; +import { getFilteredThoughts } from "../utils/getFiltredThoughts" export const getThoughts = async (req, res) => { try { @@ -19,6 +20,11 @@ export const getThoughts = async (req, res) => { result = getSortedThoughts(result, true) } + // Default sort by creation date descending + if (!sort) { + result = result.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)); + } + // Page function // URL example: http://localhost:8080/thoughts?page=1 const pagedResults = getPages(result, page) diff --git a/package.json b/package.json index 2879578..77dd7dd 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.21.2", "express-list-endpoints": "^7.1.1", "mongoose": "^8.15.1", diff --git a/server.js b/server.js index 193b9cc..462b2ea 100644 --- a/server.js +++ b/server.js @@ -10,9 +10,12 @@ import { deleteThought } from "./endpoints/deleteThought" import { getHome } from "./endpoints/getHome" import { Thought } from "./models/thought" import mongoose from "mongoose" +import dotenv from "dotenv"; + //#endregion //#region ---- Set up ---- +dotenv.config(); const mongoUrl = process.env.MONGO_URL || 'mongodb://localhost/testing'; mongoose.connect(mongoUrl) @@ -27,10 +30,12 @@ app.use(express.json()) if (process.env.RESET_DB) { const seedDatabase = async () => { + console.log("🌱 Resetting and seeding database..."); await Thought.deleteMany({}); thoughtData.forEach(thought => { new Thought(thought).save(); }); + console.log("✅ Seeding complete."); }; seedDatabase(); } diff --git a/utils/getFiltredThoughts.js b/utils/getFiltredThoughts.js index 726f21a..ad211ef 100644 --- a/utils/getFiltredThoughts.js +++ b/utils/getFiltredThoughts.js @@ -1,4 +1,3 @@ - export const getFilteredThoughts = (thoughts, heartsQuery) => { let filteredThoughts = thoughts diff --git a/utils/getPages.js b/utils/getPages.js index daf8092..3229102 100644 --- a/utils/getPages.js +++ b/utils/getPages.js @@ -1,4 +1,4 @@ -export const getPages = (result, page = 1, pageLenght = 5) => { +export const getPages = (result, page = 1, pageLenght = 10) => { const pageNumber = Number(page) const start = (pageNumber - 1) * pageLenght const end = start + pageLenght diff --git a/utils/getSortedThoughts.js b/utils/getSortedThoughts.js index 9205af9..08c6238 100644 --- a/utils/getSortedThoughts.js +++ b/utils/getSortedThoughts.js @@ -1,4 +1,3 @@ - export const getSortedThoughts = (thoughts, heartsQuery) => { let sortedThoughts = thoughts From 8983e05482d330f7fe6008bc199a969eef8c51b9 Mon Sep 17 00:00:00 2001 From: simfrisk Date: Thu, 5 Jun 2025 12:10:00 +0200 Subject: [PATCH 08/24] Added some stuff --- endpoints/getThoughts.js | 6 ++---- endpoints/postLike.js | 33 +++++++++++++++++++++++++++++++++ models/thought.js | 10 ++++++++-- server.js | 2 ++ todo | 1 + 5 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 endpoints/postLike.js create mode 100644 todo diff --git a/endpoints/getThoughts.js b/endpoints/getThoughts.js index 01b7532..02a86a8 100644 --- a/endpoints/getThoughts.js +++ b/endpoints/getThoughts.js @@ -18,10 +18,8 @@ export const getThoughts = async (req, res) => { //URL exapmle: http://localhost:8080/thoughts?sort=hearts if (sort === "hearts") { result = getSortedThoughts(result, true) - } - - // Default sort by creation date descending - if (!sort) { + } else { + // Always sort by createdAt descending if not sorting by hearts result = result.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)); } diff --git a/endpoints/postLike.js b/endpoints/postLike.js new file mode 100644 index 0000000..4ecb499 --- /dev/null +++ b/endpoints/postLike.js @@ -0,0 +1,33 @@ +import { Thought } from "../models/thought"; + +export const postLike = async (req, res) => { + const { id } = req.params; + + try { + const updatedThought = await Thought.findByIdAndUpdate( + id, + { $inc: { hearts: 1 } }, + { new: true } + ); + + if (!updatedThought) { + return res.status(400).json({ + success: false, + response: null, + message: 'Thought could not be liked' + }); + } + + res.status(201).json({ + success: true, + response: updatedThought, + message: 'Thought successfully liked' + }); + } catch (error) { + res.status(400).json({ + success: false, + response: error, + message: 'Could not like thought to the database' + }); + } +}; \ No newline at end of file diff --git a/models/thought.js b/models/thought.js index a7a5b71..e086d5d 100644 --- a/models/thought.js +++ b/models/thought.js @@ -1,10 +1,16 @@ import mongoose from "mongoose"; const ThoughtSchema = new mongoose.Schema({ - message: String, + message: { + type: String, + required: true, + trim: true, + minlength: 5, + maxlength: 140 + }, hearts: { type: Number, - default: 0 + default: 0, }, createdAt: { type: Date, diff --git a/server.js b/server.js index 462b2ea..aa95b00 100644 --- a/server.js +++ b/server.js @@ -5,6 +5,7 @@ import thoughtData from "./data.json" import { getThoughtById } from "./endpoints/getThoughtById" import { getThoughts } from "./endpoints/getThoughts" import { postThought } from "./endpoints/postThought" +import { postLike } from "./endpoints/postLike" import { patchThought } from "./endpoints/patchThought" import { deleteThought } from "./endpoints/deleteThought" import { getHome } from "./endpoints/getHome" @@ -48,6 +49,7 @@ app.get("/", getHome(app)) app.get("/thoughts", getThoughts) app.get("/thoughts/:id", getThoughtById) app.post("/thoughts", postThought) +app.post("/thoughts/:id/like", postLike) app.patch("/thoughts/:id", patchThought) app.delete('/thoughts/:id', deleteThought) diff --git a/todo b/todo new file mode 100644 index 0000000..472eff1 --- /dev/null +++ b/todo @@ -0,0 +1 @@ +[X] Fix seeding on npm run dev \ No newline at end of file From d5b37df398dc099eb45b36c0f0b0b759a3139bc9 Mon Sep 17 00:00:00 2001 From: simfrisk Date: Tue, 10 Jun 2025 14:13:22 +0200 Subject: [PATCH 09/24] Testing --- endpoints/getThoughts.js | 9 ++++++++- endpoints/postUser.js | 22 ++++++++++++++++++++++ models/user.js | 22 ++++++++++++++++++++++ server.js | 19 +++++++++++++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 endpoints/postUser.js create mode 100644 models/user.js diff --git a/endpoints/getThoughts.js b/endpoints/getThoughts.js index 02a86a8..b30d7d9 100644 --- a/endpoints/getThoughts.js +++ b/endpoints/getThoughts.js @@ -26,9 +26,16 @@ export const getThoughts = async (req, res) => { // Page function // URL example: http://localhost:8080/thoughts?page=1 const pagedResults = getPages(result, page) + // const totalPages = Math.ceil(result.length / 10) + + // res.json({ + // pagedResults, + // totalPages + // }) res.json(pagedResults) } catch (error) { console.error("Error fetching thoughts:", error) res.status(500).json({ error: "Failed to fetch thoughts." }) } -} \ No newline at end of file +} + diff --git a/endpoints/postUser.js b/endpoints/postUser.js new file mode 100644 index 0000000..9d19add --- /dev/null +++ b/endpoints/postUser.js @@ -0,0 +1,22 @@ +import { User } from "../models/user"; + +export const postUser = async (req, res) => { + try { + const { name, email, password } = req.body + const salt = bcrypt.genSaltSync() + const user = new User({ name, email, password: bcrypt.hashSync(password, salt) }) + user.save() + res.status(201).json({ + success: true, + message: "User created", + id: user._id, + accessToken: user.accessToken, + }) + } catch (error) { + res.status(400).json({ + success: false, + message: "Could not create user", + errors: error + }) + } +} \ No newline at end of file diff --git a/models/user.js b/models/user.js new file mode 100644 index 0000000..e6d661c --- /dev/null +++ b/models/user.js @@ -0,0 +1,22 @@ +import { mongoose } from "mongoose" + +const UserSchema = new mongoose.Schema({ + name: { + type: String, + unique: true + }, + email: { + type: String, + unique: true + }, + password: { + type: String, + required: true + }, + accessToken: { + type: String, + default: () => crypto.randomBytes(128).toString("hex") + } +}) + +export const User = mongoose.model("User", UserSchema); \ No newline at end of file diff --git a/server.js b/server.js index aa95b00..4390bf9 100644 --- a/server.js +++ b/server.js @@ -6,10 +6,12 @@ import { getThoughtById } from "./endpoints/getThoughtById" import { getThoughts } from "./endpoints/getThoughts" import { postThought } from "./endpoints/postThought" import { postLike } from "./endpoints/postLike" +import { postUser } from "./endpoints/postUser" import { patchThought } from "./endpoints/patchThought" import { deleteThought } from "./endpoints/deleteThought" import { getHome } from "./endpoints/getHome" import { Thought } from "./models/thought" +import { User } from "./models/user" import mongoose from "mongoose" import dotenv from "dotenv"; @@ -41,6 +43,22 @@ if (process.env.RESET_DB) { seedDatabase(); } +//User stuff +const authenticateUser = async (req, res, next) => { + const user = await User.findOne({ + accessToken: req.header("Authorization") + }) + + if (user) { + req.user = user + next() + } else { + res.status(401).json({ + loggedOut: true + }) + } +} + //#endregion //#region ---- endpoint ---- @@ -50,6 +68,7 @@ app.get("/thoughts", getThoughts) app.get("/thoughts/:id", getThoughtById) app.post("/thoughts", postThought) app.post("/thoughts/:id/like", postLike) +app.post("/users", postUser) app.patch("/thoughts/:id", patchThought) app.delete('/thoughts/:id', deleteThought) From c71f5c28f8fa46f8bc762eca37a3e0a41aaa972b Mon Sep 17 00:00:00 2001 From: simfrisk Date: Tue, 10 Jun 2025 14:19:00 +0200 Subject: [PATCH 10/24] Fixes --- models/user.js | 2 +- package.json | 2 ++ server.js | 21 +++++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/models/user.js b/models/user.js index e6d661c..9f78f28 100644 --- a/models/user.js +++ b/models/user.js @@ -1,4 +1,4 @@ -import { mongoose } from "mongoose" +import mongoose from "mongoose" const UserSchema = new mongoose.Schema({ name: { diff --git a/package.json b/package.json index 77dd7dd..1036fd3 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.21.2", "express-list-endpoints": "^7.1.1", diff --git a/server.js b/server.js index 4390bf9..d763d80 100644 --- a/server.js +++ b/server.js @@ -14,6 +14,8 @@ import { Thought } from "./models/thought" import { User } from "./models/user" import mongoose from "mongoose" import dotenv from "dotenv"; +import crypto from "crypto" +import bcrypt from "bcrypt" //#endregion @@ -72,6 +74,25 @@ app.post("/users", postUser) app.patch("/thoughts/:id", patchThought) app.delete('/thoughts/:id', deleteThought) +app.get("/secrets", authenticateUser) +app.get("/secrets", (req, res) => { + res.json({ + secret: "This is secret" + }) +}) + +app.post("/sessions", async (req, res) => { + const user = await User.findOne({ + email: req.body.email + }) + + if (user && bcrypt.compareSync(req.body.password, user.password)) { + res.json({ userId: user._id }) + } else { + res.json({ notFound: true }) + } +}) + //#endregion //#region ---- Starts the server ---- From 17adca07b24a23a088e56ac4c73ed506faf26434 Mon Sep 17 00:00:00 2001 From: simfrisk Date: Tue, 10 Jun 2025 14:22:27 +0200 Subject: [PATCH 11/24] Fixes --- endpoints/postUser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/endpoints/postUser.js b/endpoints/postUser.js index 9d19add..1318a14 100644 --- a/endpoints/postUser.js +++ b/endpoints/postUser.js @@ -5,7 +5,7 @@ export const postUser = async (req, res) => { const { name, email, password } = req.body const salt = bcrypt.genSaltSync() const user = new User({ name, email, password: bcrypt.hashSync(password, salt) }) - user.save() + await user.save() res.status(201).json({ success: true, message: "User created", From 4a950f392805b304e251a3b9f9029b1f086afc93 Mon Sep 17 00:00:00 2001 From: simfrisk Date: Tue, 10 Jun 2025 15:14:24 +0200 Subject: [PATCH 12/24] Added users. Might not work --- endpoints/getSecrets.js | 10 +++++++++ endpoints/postSession.js | 14 ++++++++++++ endpoints/postUser.js | 5 ++++- middleware/authenticateUser.js | 14 ++++++++++++ models/user.js | 21 ++++++++++++++++- package.json | 1 + server.js | 41 +++++----------------------------- 7 files changed, 69 insertions(+), 37 deletions(-) create mode 100644 endpoints/getSecrets.js create mode 100644 endpoints/postSession.js create mode 100644 middleware/authenticateUser.js diff --git a/endpoints/getSecrets.js b/endpoints/getSecrets.js new file mode 100644 index 0000000..7f8d447 --- /dev/null +++ b/endpoints/getSecrets.js @@ -0,0 +1,10 @@ +export const getSecrets = (req, res) => { + res.json({ secret: "This is secret" }); +}; + +// app.get("/secrets", authenticateUser) +// app.get("/secrets", (req, res) => { +// res.json({ +// secret: "This is secret" +// }) +// }) \ No newline at end of file diff --git a/endpoints/postSession.js b/endpoints/postSession.js new file mode 100644 index 0000000..7140af2 --- /dev/null +++ b/endpoints/postSession.js @@ -0,0 +1,14 @@ +import { User } from "../models/user"; +import bcrypt from "bcrypt" + +export const postSession = async (req, res) => { + const user = await User.findOne({ + email: req.body.email + }) + + if (user && bcrypt.compareSync(req.body.password, user.password)) { + res.json({ userId: user._id }) + } else { + res.json({ notFound: true }) + } +}) \ No newline at end of file diff --git a/endpoints/postUser.js b/endpoints/postUser.js index 1318a14..7af71a2 100644 --- a/endpoints/postUser.js +++ b/endpoints/postUser.js @@ -1,4 +1,5 @@ import { User } from "../models/user"; +import bcrypt from "bcrypt" export const postUser = async (req, res) => { try { @@ -13,10 +14,12 @@ export const postUser = async (req, res) => { accessToken: user.accessToken, }) } catch (error) { + console.error("❌ Error creating user:", error); + res.status(400).json({ success: false, message: "Could not create user", errors: error - }) + }); } } \ No newline at end of file diff --git a/middleware/authenticateUser.js b/middleware/authenticateUser.js new file mode 100644 index 0000000..b7d69b0 --- /dev/null +++ b/middleware/authenticateUser.js @@ -0,0 +1,14 @@ +import { User } from "../models/user.js" + +export const authenticateUser = async (req, res, next) => { + const user = await User.findOne({ + accessToken: req.header("Authorization") + }) + + if (user) { + req.user = user + next() + } else { + res.status(401).json({ loggedOut: true }) + } +} \ No newline at end of file diff --git a/models/user.js b/models/user.js index 9f78f28..1ee199d 100644 --- a/models/user.js +++ b/models/user.js @@ -1,12 +1,15 @@ import mongoose from "mongoose" +import crypto from "crypto" const UserSchema = new mongoose.Schema({ name: { type: String, + required: true, unique: true }, email: { type: String, + required: true, unique: true }, password: { @@ -19,4 +22,20 @@ const UserSchema = new mongoose.Schema({ } }) -export const User = mongoose.model("User", UserSchema); \ No newline at end of file +export const User = mongoose.model("User", UserSchema); + + +// export const authenticateUser = async (req, res, next) => { +// const user = await User.findOne({ +// accessToken: req.header("Authorization") +// }) + +// if (user) { +// req.user = user +// next() +// } else { +// res.status(401).json({ +// loggedOut: true +// }) +// } +// } \ No newline at end of file diff --git a/package.json b/package.json index 1036fd3..5e4fa7d 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", "bcrypt": "^6.0.0", + "bcrypt-nodejs": "^0.0.3", "cors": "^2.8.5", "crypto": "^1.0.1", "dotenv": "^16.5.0", diff --git a/server.js b/server.js index d763d80..e15777a 100644 --- a/server.js +++ b/server.js @@ -2,20 +2,20 @@ import cors from "cors" import express, { response } from "express" import thoughtData from "./data.json" +import { authenticateUser } from "./middleware/authenticateUser.js" import { getThoughtById } from "./endpoints/getThoughtById" import { getThoughts } from "./endpoints/getThoughts" +import { getSecrets } from "./endpoints/getSecrets" import { postThought } from "./endpoints/postThought" import { postLike } from "./endpoints/postLike" import { postUser } from "./endpoints/postUser" +import { postSession } from "./endpoints/postSession" import { patchThought } from "./endpoints/patchThought" import { deleteThought } from "./endpoints/deleteThought" import { getHome } from "./endpoints/getHome" import { Thought } from "./models/thought" -import { User } from "./models/user" import mongoose from "mongoose" import dotenv from "dotenv"; -import crypto from "crypto" -import bcrypt from "bcrypt" //#endregion @@ -23,6 +23,7 @@ import bcrypt from "bcrypt" dotenv.config(); const mongoUrl = process.env.MONGO_URL || 'mongodb://localhost/testing'; +// const mongoUrl = 'mongodb://localhost/testing'; mongoose.connect(mongoUrl) // The setup of the port @@ -45,22 +46,6 @@ if (process.env.RESET_DB) { seedDatabase(); } -//User stuff -const authenticateUser = async (req, res, next) => { - const user = await User.findOne({ - accessToken: req.header("Authorization") - }) - - if (user) { - req.user = user - next() - } else { - res.status(401).json({ - loggedOut: true - }) - } -} - //#endregion //#region ---- endpoint ---- @@ -71,27 +56,13 @@ app.get("/thoughts/:id", getThoughtById) app.post("/thoughts", postThought) app.post("/thoughts/:id/like", postLike) app.post("/users", postUser) +app.post("/sessions", postSession) app.patch("/thoughts/:id", patchThought) app.delete('/thoughts/:id', deleteThought) +app.get("/secrets", authenticateUser, getSecrets) -app.get("/secrets", authenticateUser) -app.get("/secrets", (req, res) => { - res.json({ - secret: "This is secret" - }) -}) -app.post("/sessions", async (req, res) => { - const user = await User.findOne({ - email: req.body.email - }) - if (user && bcrypt.compareSync(req.body.password, user.password)) { - res.json({ userId: user._id }) - } else { - res.json({ notFound: true }) - } -}) //#endregion From dd275110683f989d2cb8027b324aa62dbdc22630 Mon Sep 17 00:00:00 2001 From: simfrisk Date: Wed, 11 Jun 2025 08:32:55 +0200 Subject: [PATCH 13/24] fix --- endpoints/postSession.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/endpoints/postSession.js b/endpoints/postSession.js index 7140af2..bb6d1f4 100644 --- a/endpoints/postSession.js +++ b/endpoints/postSession.js @@ -11,4 +11,4 @@ export const postSession = async (req, res) => { } else { res.json({ notFound: true }) } -}) \ No newline at end of file +} \ No newline at end of file From 79016495b113f74e857ed3e5e5dc390a3b763e8f Mon Sep 17 00:00:00 2001 From: simfrisk Date: Wed, 11 Jun 2025 13:03:15 +0200 Subject: [PATCH 14/24] fix --- server.js | 38 +++++++++++++++----------------------- setup/resetDatabase.js | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 23 deletions(-) create mode 100644 setup/resetDatabase.js diff --git a/server.js b/server.js index e15777a..fffb7b7 100644 --- a/server.js +++ b/server.js @@ -1,25 +1,29 @@ //#region ---- Imports ---- + +import dotenv from "dotenv" import cors from "cors" import express, { response } from "express" -import thoughtData from "./data.json" +import mongoose from "mongoose" + import { authenticateUser } from "./middleware/authenticateUser.js" +import { resetDatabase } from "./setup/resetDatabase.js" + +import { getHome } from "./endpoints/getHome" +import { getSecrets } from "./endpoints/getSecrets" import { getThoughtById } from "./endpoints/getThoughtById" import { getThoughts } from "./endpoints/getThoughts" -import { getSecrets } from "./endpoints/getSecrets" -import { postThought } from "./endpoints/postThought" import { postLike } from "./endpoints/postLike" -import { postUser } from "./endpoints/postUser" import { postSession } from "./endpoints/postSession" +import { postThought } from "./endpoints/postThought" +import { postUser } from "./endpoints/postUser" import { patchThought } from "./endpoints/patchThought" import { deleteThought } from "./endpoints/deleteThought" -import { getHome } from "./endpoints/getHome" -import { Thought } from "./models/thought" -import mongoose from "mongoose" -import dotenv from "dotenv"; //#endregion //#region ---- Set up ---- + +// Runs the env file dotenv.config(); const mongoUrl = process.env.MONGO_URL || 'mongodb://localhost/testing'; @@ -34,17 +38,8 @@ const app = express() app.use(cors()) app.use(express.json()) -if (process.env.RESET_DB) { - const seedDatabase = async () => { - console.log("🌱 Resetting and seeding database..."); - await Thought.deleteMany({}); - thoughtData.forEach(thought => { - new Thought(thought).save(); - }); - console.log("✅ Seeding complete."); - }; - seedDatabase(); -} +// Reset the database with: RESET_DB=true npm start +resetDatabase() //#endregion @@ -53,16 +48,13 @@ if (process.env.RESET_DB) { app.get("/", getHome(app)) app.get("/thoughts", getThoughts) app.get("/thoughts/:id", getThoughtById) +app.get("/secrets", authenticateUser, getSecrets) app.post("/thoughts", postThought) app.post("/thoughts/:id/like", postLike) app.post("/users", postUser) app.post("/sessions", postSession) app.patch("/thoughts/:id", patchThought) app.delete('/thoughts/:id', deleteThought) -app.get("/secrets", authenticateUser, getSecrets) - - - //#endregion diff --git a/setup/resetDatabase.js b/setup/resetDatabase.js new file mode 100644 index 0000000..7dba691 --- /dev/null +++ b/setup/resetDatabase.js @@ -0,0 +1,16 @@ +import { Thought } from "../models/thought"; +import thoughtData from "../data.json" + +export const resetDatabase = () => { + if (process.env.RESET_DB) { + const seedDatabase = async () => { + console.log("🌱 Resetting and seeding database..."); + await Thought.deleteMany({}); + thoughtData.forEach(thought => { + new Thought(thought).save(); + }); + console.log("✅ Seeding complete."); + }; + seedDatabase(); + } +} \ No newline at end of file From 3c86067b7bd084d74a76f1a504908f9b61e94cb4 Mon Sep 17 00:00:00 2001 From: simfrisk Date: Wed, 11 Jun 2025 13:12:44 +0200 Subject: [PATCH 15/24] added --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index fffb7b7..fc9ec9f 100644 --- a/server.js +++ b/server.js @@ -49,7 +49,7 @@ app.get("/", getHome(app)) app.get("/thoughts", getThoughts) app.get("/thoughts/:id", getThoughtById) app.get("/secrets", authenticateUser, getSecrets) -app.post("/thoughts", postThought) +app.post("/thoughts", authenticateUser, postThought) app.post("/thoughts/:id/like", postLike) app.post("/users", postUser) app.post("/sessions", postSession) From a9908fac80792477c0de7066155a281cdfb84f4b Mon Sep 17 00:00:00 2001 From: simfrisk Date: Wed, 11 Jun 2025 13:15:20 +0200 Subject: [PATCH 16/24] added authentication --- server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index fc9ec9f..da09ddc 100644 --- a/server.js +++ b/server.js @@ -46,10 +46,10 @@ resetDatabase() //#region ---- endpoint ---- app.get("/", getHome(app)) -app.get("/thoughts", getThoughts) +app.get("/thoughts", authenticateUser, getThoughts) app.get("/thoughts/:id", getThoughtById) app.get("/secrets", authenticateUser, getSecrets) -app.post("/thoughts", authenticateUser, postThought) +app.post("/thoughts", postThought) app.post("/thoughts/:id/like", postLike) app.post("/users", postUser) app.post("/sessions", postSession) From a15cbf012a9d62ab02310be304f9a4ccadf3c9f6 Mon Sep 17 00:00:00 2001 From: simfrisk Date: Wed, 11 Jun 2025 13:17:18 +0200 Subject: [PATCH 17/24] Added protection --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index da09ddc..ea8ab59 100644 --- a/server.js +++ b/server.js @@ -47,7 +47,7 @@ resetDatabase() app.get("/", getHome(app)) app.get("/thoughts", authenticateUser, getThoughts) -app.get("/thoughts/:id", getThoughtById) +app.get("/thoughts/:id", authenticateUser, getThoughtById) app.get("/secrets", authenticateUser, getSecrets) app.post("/thoughts", postThought) app.post("/thoughts/:id/like", postLike) From 1a1cd09d38d61ebe6469c3527dd0c5bd3a511491 Mon Sep 17 00:00:00 2001 From: simfrisk Date: Wed, 11 Jun 2025 14:20:14 +0200 Subject: [PATCH 18/24] Added token --- endpoints/postSession.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/endpoints/postSession.js b/endpoints/postSession.js index bb6d1f4..7460e5e 100644 --- a/endpoints/postSession.js +++ b/endpoints/postSession.js @@ -7,7 +7,10 @@ export const postSession = async (req, res) => { }) if (user && bcrypt.compareSync(req.body.password, user.password)) { - res.json({ userId: user._id }) + res.json({ + userId: user._id, + accessToken: user.accessToken + }) } else { res.json({ notFound: true }) } From 66aed3904ef73c86c466c6587cc025f5843a9d99 Mon Sep 17 00:00:00 2001 From: simfrisk Date: Fri, 13 Jun 2025 07:46:51 +0200 Subject: [PATCH 19/24] Thought prodection --- endpoints/deleteThought.js | 16 ++++++++++++++-- endpoints/patchThought.js | 17 ++++++++++++++++- endpoints/postThought.js | 18 ++++++++++++------ models/thought.js | 5 +++++ server.js | 6 +++--- 5 files changed, 50 insertions(+), 12 deletions(-) diff --git a/endpoints/deleteThought.js b/endpoints/deleteThought.js index 0d03483..7a3afe8 100644 --- a/endpoints/deleteThought.js +++ b/endpoints/deleteThought.js @@ -2,17 +2,29 @@ import { Thought } from "../models/thought" export const deleteThought = async (req, res) => { const { id } = req.params + const userId = req.user._id; try { - const thought = await Thought.findByIdAndDelete(id) + const thought = await Thought.findById(id) if (!thought) { return res.status(404).json({ success: false, response: null, - message: 'Thought could not be deleted' + message: 'Thought could not be found' }) } + + // Check if the current user owns the thought + if (thought.createdBy.toString() !== userId.toString()) { + return res.status(403).json({ + success: false, + message: "You are not allowed to delete this thought" + }); + } + + await thought.deleteOne(); + res.status(200).json({ success: true, response: thought, diff --git a/endpoints/patchThought.js b/endpoints/patchThought.js index 1410062..95c66cc 100644 --- a/endpoints/patchThought.js +++ b/endpoints/patchThought.js @@ -3,9 +3,12 @@ import { Thought } from "../models/thought" export const patchThought = async (req, res) => { const { id } = req.params const { newMessage } = req.body + const userId = req.user._id; try { - const thought = await Thought.findByIdAndUpdate(id, { message: newMessage }, { new: true, runValidators: true }) + const thought = await Thought.findById(id); + // const thought = await Thought.findByIdAndUpdate(id, { message: newMessage }, { new: true, runValidators: true }) + if (!thought) { return res.status(400).json({ success: false, @@ -14,6 +17,18 @@ export const patchThought = async (req, res) => { }); } + // Check if the user owns the thought + if (thought.createdBy.toString() !== userId.toString()) { + return res.status(403).json({ + success: false, + message: "You are not allowed to edit this thought" + }); + } + + thought.message = newMessage; + + const updatedThought = await thought.save(); + res.status(201).json({ success: true, response: thought, diff --git a/endpoints/postThought.js b/endpoints/postThought.js index 55483b9..84fe9e8 100644 --- a/endpoints/postThought.js +++ b/endpoints/postThought.js @@ -2,10 +2,15 @@ import { Thought } from "../models/thought"; export const postThought = async (req, res) => { const { message } = req.body; - const newThought = new Thought({ message }) + const user = req.user; try { - const savedNewThought = await newThought.save() + const newThought = new Thought({ + message, + createdBy: user._id + }); + + const savedNewThought = await newThought.save(); if (!savedNewThought) { return res.status(400).json({ @@ -18,13 +23,14 @@ export const postThought = async (req, res) => { res.status(201).json({ success: true, response: savedNewThought, - message: 'Thought successfully saved' + message: "Thought created" }); + } catch (error) { - res.status(400).json({ + res.status(500).json({ success: false, response: error, - message: 'Could not save thought to the database' + message: "Could not post thought" }); } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/models/thought.js b/models/thought.js index e086d5d..4bf048d 100644 --- a/models/thought.js +++ b/models/thought.js @@ -12,6 +12,11 @@ const ThoughtSchema = new mongoose.Schema({ type: Number, default: 0, }, + createdBy: { + type: mongoose.Schema.Types.ObjectId, + ref: "User", + required: true, + }, createdAt: { type: Date, default: Date.now diff --git a/server.js b/server.js index ea8ab59..50b59ed 100644 --- a/server.js +++ b/server.js @@ -49,12 +49,12 @@ app.get("/", getHome(app)) app.get("/thoughts", authenticateUser, getThoughts) app.get("/thoughts/:id", authenticateUser, getThoughtById) app.get("/secrets", authenticateUser, getSecrets) -app.post("/thoughts", postThought) +app.post("/thoughts", authenticateUser, postThought) app.post("/thoughts/:id/like", postLike) app.post("/users", postUser) app.post("/sessions", postSession) -app.patch("/thoughts/:id", patchThought) -app.delete('/thoughts/:id', deleteThought) +app.patch("/thoughts/:id", authenticateUser, patchThought) +app.delete('/thoughts/:id', authenticateUser, deleteThought) //#endregion From d5a62087089cf9678f047bc478288392c1b74f27 Mon Sep 17 00:00:00 2001 From: simfrisk Date: Fri, 13 Jun 2025 07:58:28 +0200 Subject: [PATCH 20/24] Fix --- data.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/data.json b/data.json index 6b603d6..8536a42 100644 --- a/data.json +++ b/data.json @@ -3,102 +3,119 @@ "message": "Berlin baby", "hearts": 2, "createdAt": "2025-05-19T22:07:08.999Z", + "createdBy": "64b2f3c6a87e2b12e4567890", "__v": 0 }, { "message": "My family!", "hearts": 0, "createdAt": "2025-05-22T22:29:32.232Z", + "createdBy": "64b2f3c6a87e2b12e4567890", "__v": 0 }, { "message": "The smell of coffee in the morning....", "hearts": 23, "createdAt": "2025-05-22T22:11:16.075Z", + "createdBy": "64b2f3c6a87e2b12e4567890", "__v": 0 }, { "message": "Newly washed bedlinen, kids that sleeps through the night.. FINGERS CROSSED 🤞🏼\n", "hearts": 62, "createdAt": "2025-05-21T21:42:23.862Z", + "createdBy": "64b2f3c6a87e2b12e4567890", "__v": 0 }, { "message": "I am happy that I feel healthy and have energy again", "hearts": 13, "createdAt": "2025-05-21T21:28:32.196Z", + "createdBy": "64b2f3c6a87e2b12e4567890", "__v": 0 }, { "message": "cold beer", "hearts": 2, "createdAt": "2025-05-21T19:05:34.113Z", + "createdBy": "64b2f3c6a87e2b12e4567890", "__v": 0 }, { "message": "My friend is visiting this weekend! <3", "hearts": 6, "createdAt": "2025-05-21T18:59:58.121Z", + "createdBy": "64b2f3c6a87e2b12e4567890", "__v": 0 }, { "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", + "createdBy": "64b2f3c6a87e2b12e4567890", "__v": 0 }, { "message": "Tacos and tequila🌮🍹", "hearts": 2, "createdAt": "2025-05-19T20:53:18.899Z", + "createdBy": "64b2f3c6a87e2b12e4567890", "__v": 0 }, { "message": "Netflix and late night ice-cream🍦", "hearts": 1, "createdAt": "2025-05-18T20:51:34.494Z", + "createdBy": "64b2f3c6a87e2b12e4567890", "__v": 0 }, { "message": "Summer is coming...", "hearts": 2, "createdAt": "2025-05-20T15:03:22.379Z", + "createdBy": "64b2f3c6a87e2b12e4567890", "__v": 0 }, { "message": "Exercise? I thought you said extra fries! 🍟😂", "hearts": 14, "createdAt": "2025-05-20T12:07:08.185Z", + "createdBy": "64b2f3c6a87e2b12e4567890", "__v": 0 }, { "message": "I’m on a seafood diet. I see food, and I eat it.", "hearts": 4, "createdAt": "2025-05-20T12:04:49.978Z", + "createdBy": "64b2f3c6a87e2b12e4567890", "__v": 0 }, { "message": "Cute monkeys🐒", "hearts": 2, "createdAt": "2025-05-20T12:01:18.308Z", + "createdBy": "64b2f3c6a87e2b12e4567890", "__v": 0 }, { "message": "The weather is nice!", "hearts": 0, "createdAt": "2025-05-20T11:58:29.662Z", + "createdBy": "64b2f3c6a87e2b12e4567890", "__v": 0 }, { "message": "good vibes and good things", "hearts": 3, "createdAt": "2025-05-20T03:57:40.322Z", + "createdBy": "64b2f3c6a87e2b12e4567890", "__v": 0 }, { "message": "Berlin baby", "hearts": 37, "createdAt": "2025-05-19T22:07:08.999Z", + "createdBy": "64b2f3c6a87e2b12e4567890", "__v": 0 } ] \ No newline at end of file From e527861de74b5d0dc103c4857461650a61f6b006 Mon Sep 17 00:00:00 2001 From: simfrisk Date: Fri, 13 Jun 2025 13:31:25 +0200 Subject: [PATCH 21/24] Console log --- endpoints/getThoughts.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/endpoints/getThoughts.js b/endpoints/getThoughts.js index b30d7d9..196037d 100644 --- a/endpoints/getThoughts.js +++ b/endpoints/getThoughts.js @@ -26,6 +26,10 @@ export const getThoughts = async (req, res) => { // Page function // URL example: http://localhost:8080/thoughts?page=1 const pagedResults = getPages(result, page) + + pagedResults.forEach(thought => { + console.log("Thought user id:", thought.userId) // or thought._id if that is the user id field + }) // const totalPages = Math.ceil(result.length / 10) // res.json({ From 0829b1f23e1741034466f2c48a5c0dadec70c87b Mon Sep 17 00:00:00 2001 From: simfrisk Date: Fri, 13 Jun 2025 14:09:52 +0200 Subject: [PATCH 22/24] Cleande --- endpoints/getThoughts.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/endpoints/getThoughts.js b/endpoints/getThoughts.js index 196037d..b30d7d9 100644 --- a/endpoints/getThoughts.js +++ b/endpoints/getThoughts.js @@ -26,10 +26,6 @@ export const getThoughts = async (req, res) => { // Page function // URL example: http://localhost:8080/thoughts?page=1 const pagedResults = getPages(result, page) - - pagedResults.forEach(thought => { - console.log("Thought user id:", thought.userId) // or thought._id if that is the user id field - }) // const totalPages = Math.ceil(result.length / 10) // res.json({ From 159fa5df1227c1e8c718f21935507b5c32d81f7a Mon Sep 17 00:00:00 2001 From: simfrisk Date: Fri, 13 Jun 2025 14:25:33 +0200 Subject: [PATCH 23/24] loging --- endpoints/getThoughts.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/endpoints/getThoughts.js b/endpoints/getThoughts.js index b30d7d9..ef75d96 100644 --- a/endpoints/getThoughts.js +++ b/endpoints/getThoughts.js @@ -26,7 +26,8 @@ export const getThoughts = async (req, res) => { // Page function // URL example: http://localhost:8080/thoughts?page=1 const pagedResults = getPages(result, page) - // const totalPages = Math.ceil(result.length / 10) + const totalPages = Math.ceil(result.length / 10) + console.log(totalPages) // res.json({ // pagedResults, From 7ae59030810202b9de2cd2a597fb3970341fe893 Mon Sep 17 00:00:00 2001 From: simfrisk Date: Fri, 13 Jun 2025 14:27:35 +0200 Subject: [PATCH 24/24] Send it --- endpoints/getThoughts.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/endpoints/getThoughts.js b/endpoints/getThoughts.js index ef75d96..15e7398 100644 --- a/endpoints/getThoughts.js +++ b/endpoints/getThoughts.js @@ -27,13 +27,12 @@ export const getThoughts = async (req, res) => { // URL example: http://localhost:8080/thoughts?page=1 const pagedResults = getPages(result, page) const totalPages = Math.ceil(result.length / 10) - console.log(totalPages) - // res.json({ - // pagedResults, - // totalPages - // }) - res.json(pagedResults) + res.json({ + pagedResults, + totalPages + }) + // res.json(pagedResults) } catch (error) { console.error("Error fetching thoughts:", error) res.status(500).json({ error: "Failed to fetch thoughts." })