From dfb213af2ee20c986d0e066392bb0870d75a1fc4 Mon Sep 17 00:00:00 2001 From: solen80a Date: Wed, 28 May 2025 12:39:28 +0200 Subject: [PATCH 01/34] Created notes, started with endpoints and installed dependencies. --- notes.md | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + server.js | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 notes.md diff --git a/notes.md b/notes.md new file mode 100644 index 0000000..0ce06cc --- /dev/null +++ b/notes.md @@ -0,0 +1,59 @@ +W1: +[] Your API should have at least three (for now) routes. Try to push yourself to do more, though! + [] The endpoint "/" should return documentation of your API using e.g. Express List Endpoints + [] A minimum of one endpoint to return a collection of results (an array of elements). + [] A minimum of one endpoint to return a single result (single element). +[] Your API should be RESTful +[] You should follow the guidelines on how to write clean code. + +W2: +[] Your API should use Mongoose models to model your data and use these models to fetch data from the database. +[] Your API should validate user input and return appropriate errors if the input is invalid. +[] You should implement error handling for all your routes, with proper response statuses. +[] Your frontend should be updated with the possibility to Update and Delete a thought. + +W3: +[] Signup and Login existing Happy Thoughts +[] Your API should have routes to register and log in +[] Your endpoints to Create, Update and Delete should be authenticated +[] Your frontend should have a registration form which POSTs to the API to create a new user. +[] Your frontend should have a login form to authenticate the user. +[] Your passwords in the database should be encrypted with bcrypt. +[] You should implement error handling. Your API should let the user know if something went wrong. Be as specific as possible to help the user, e.g. by validating the user input when creating a new user, and return "That email address already exists". Include correct status codes. Error messages should also be shown on the frontend. +[] The validation should ensure unique email addresses and/or usernames, depending on how you'd like to structure your User model. + + +Requirements: +[] Your API must have at least the following routes. Try to push yourself to do more, though! Endpoints for: + [] Documentation of your API using e.g. Express List Endpoints + [] Reading thoughts + [] Reading a single thought + [] Liking a thought + [] Creating a thought (authenticated) + [] Updating a thought (authenticated) + [] Deleting a thought (authenticated) + [] Signing up + [] Logging in +[] Your API should be RESTful +[] You should follow the guidelines on how to write clean code +[] Your API should use Mongoose models to model your data and use these models to fetch data from the database. +[] Your API should validate user input and return appropriate errors if the input is invalid. +[] The validation should ensure unique email addresses and/or usernames depending on how you'd like to structure your User model. +[] You should implement error handling for all your routes, with proper response statuses. +[] Your frontend should be updated with the possibility to Update and Delete a thought, as well as signing up and logging in and some error handling if something goes wrong. +[] Your passwords in the database should be encrypted with bcrypt. +[] Your API should be deployed to Render or similar. +[] Everything in your backend should be reflected in your frontend. + +Stretch goal options: +[] Allow anonymous (not-logged-in) users to post thoughts +[] As a logged-in user, you should be able to see a list of the thoughts that you've liked. +[] Give the thoughts a category or tags. So you could organise them. For example, 'Food thoughts', 'Project thoughts', 'Home thoughts', etc. +[] Add filtering and sorting options to the endpoint which returns all thoughts. Examples: + [] Sorting on date or number of likes + [] Filtering to only see thoughts with more than x hearts, thoughts newer than x date or thoughts in a specific category (if you implemented categories) +[] Implement pagination in your backend & frontend so you can click through pages of thoughts. The frontend could request a specific page and show only that page. The backend would take the request for that page and return only the thoughts for that page. +[] You could also experiment with implementing infinite scrolling on the frontend rather than having a list of page numbers. This idea is similar to paging and involves frontend & backend changes. +[] When registering, display error messages from the API in the frontend, next to the field which has the error. For example, if the email address is invalid, show an error message next to the email input. +[] In the frontend, store the token in localStorage and send it in headers to persist the logged-in state for the user. +[] Validate the email address format using a regular expression. \ No newline at end of file diff --git a/package.json b/package.json index bf25bb6..00addae 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@babel/preset-env": "^7.16.11", "cors": "^2.8.5", "express": "^4.17.3", + "express-list-endpoints": "^7.1.1", "nodemon": "^3.0.1" } } diff --git a/server.js b/server.js index f47771b..6978fe4 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,6 @@ import cors from "cors" import express from "express" +import data from "./data.json" // Defines the port the app will run on. Defaults to 8080, but can be overridden // when starting the server. Example command to overwrite PORT env variable value: @@ -12,10 +13,70 @@ app.use(cors()) app.use(express.json()) // Start defining your routes here + app.get("/", (req, res) => { - res.send("Hello Technigo!") + res.send(` + + + Happy Thoughts API + + +

Welcome to the Happy Thoughts API

+

This is the documentation page.

+

Endpoints:

+

+

/messages

+

/messages&liked

+

/messages

+ + + `) + }) +//Show all messages first version +// Show the data in data.json +// app.get("/messages", (req, res) => { +// res.json(data) +// }) + +//Show all messages +//Filter liked messages, /messages&liked +app.get("/messages", (req, res) => { + const showLiked = req.query.hasOwnProperty("liked"); + + const filteredMessages = showLiked + ? data.filter(item => Number(item.hearts) > 0) + : data; + + if (filteredMessages.length === 0) { + return res.status(404).json({ error: 'There are no liked messages to show' }); + } + + res.json(filteredMessages); +}); + +//Show all messages !!Is this not relevant? Should maybe be a qury param instead?!! +// app.get("/messages", (req, res) => { +// res.json(data.map((item) => item.message)) +// }) + +//Show a single message id +app.get("/messages/:id", (req, res) => { + + // be aware! The id that comes from the param is of type string. and in our json it is of type number. You have to turn them into the same type before you can compare them. trun a string to a number by adding + 👇 + const messageID = data.find((message) => message._id === req.params.id) + + // tiny error handling if we get an id that doesnt exist in our data + if (!messageID) { + return res.status(404).json({ error: 'message not found' }) + } + + res.json(messageID) +}) + + + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) From 30afbdc1f0300507dc1ce431d49d6abeaa1f4287 Mon Sep 17 00:00:00 2001 From: solen80a Date: Thu, 29 May 2025 10:12:34 +0200 Subject: [PATCH 02/34] Added query param for messages added today, /messagesfromtoday --- data.json | 2 +- server.js | 114 ++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 104 insertions(+), 12 deletions(-) diff --git a/data.json b/data.json index a2c844f..33e975d 100644 --- a/data.json +++ b/data.json @@ -115,7 +115,7 @@ "_id": "682bab8c12155b00101732ce", "message": "Berlin baby", "hearts": 37, - "createdAt": "2025-05-19T22:07:08.999Z", + "createdAt": "2025-05-29T02:07:08.999Z", "__v": 0 } ] \ No newline at end of file diff --git a/server.js b/server.js index 6978fe4..fef4137 100644 --- a/server.js +++ b/server.js @@ -19,15 +19,92 @@ app.get("/", (req, res) => { Happy Thoughts API + -

Welcome to the Happy Thoughts API

-

This is the documentation page.

+

Welcome to Happy Thoughts API

+ +

This is the documentation of Happy thoughts API.

+

Endpoints:

-

-

/messages

-

/messages&liked

-

/messages

+

GET /messages

+

Returns a list of all happy thoughts.

+

Response:

+

+        [
+          {
+             "_id": "682c6f0e951f7a0017130022",
+            "message": "Cute monkeys🐒",
+            "hearts": 2,
+            "createdAt": "2025-05-20T12:01:18.308Z",
+            "__v": 0
+          },
+          ...
+        ]
+        
+

GET /messages?liked

+

Returns a list of all happy thoughts with likes, >0.

+

Response:

+

+        [
+          {
+             "_id": "682c6f0e951f7a0017130022",
+            "message": "Cute monkeys🐒",
+            "hearts": 2,
+            "createdAt": "2025-05-20T12:01:18.308Z",
+            "__v": 0
+          },
+          ...
+        ]
+        
+

GET /messages?messagesfromtoday

+

Returns a list of all happy thoughts from today .

+

Response:

+

+        [
+          {
+             "_id": "682c6f0e951f7a0017130022",
+            "message": "Cute monkeys🐒",
+            "hearts": 2,
+            "createdAt": "2025-05-20T12:01:18.308Z",
+            "__v": 0
+          },
+          ...
+        ]
+        
+

GET /messages/:id

+

Returns a specific happy thought by id.

+

Response:

+

+        [
+          {
+             "_id": "682c6f0e951f7a0017130022",
+            "message": "Cute monkeys🐒",
+            "hearts": 2,
+            "createdAt": "2025-05-20T12:01:18.308Z",
+            "__v": 0
+          }
+        ]        
+        
+ `) @@ -41,16 +118,31 @@ app.get("/", (req, res) => { // }) //Show all messages -//Filter liked messages, /messages&liked +//Filter liked messages, /messages?liked, +//Filter messages from today /messages?messagesfromtoday app.get("/messages", (req, res) => { const showLiked = req.query.hasOwnProperty("liked"); + const showMessagesFromToday = req.query.hasOwnProperty("messagesfromtoday") + const today = new Date() + const todayDate = new Date(today.getFullYear(), today.getMonth(), today.getDate()) - const filteredMessages = showLiked - ? data.filter(item => Number(item.hearts) > 0) - : data; + let filteredMessages = data + + if (showLiked){ + filteredMessages = filteredMessages.filter(message => message.hearts >0) + } + + if (showMessagesFromToday){ + filteredMessages = filteredMessages.filter(message => { + const createdAt = new Date(message.createdAt) + const messageData = new Date(createdAt.getFullYear(), createdAt.getMonth(), createdAt.getDate()) + + return messageData.getTime() === todayDate.getTime() + }) + } if (filteredMessages.length === 0) { - return res.status(404).json({ error: 'There are no liked messages to show' }); + return res.status(404).json({ error: 'There are no messages to show' }); } res.json(filteredMessages); From b638bd4d2b85301066964e1e52a827268e30d44c Mon Sep 17 00:00:00 2001 From: solen80a Date: Fri, 30 May 2025 11:18:22 +0200 Subject: [PATCH 03/34] Connected the root to listEndpoints and moved my html documentation to /documentation. --- data.json | 2 +- server.js | 129 +++++++++++++++++++++++++++++------------------------- 2 files changed, 71 insertions(+), 60 deletions(-) diff --git a/data.json b/data.json index 33e975d..9fed3ae 100644 --- a/data.json +++ b/data.json @@ -115,7 +115,7 @@ "_id": "682bab8c12155b00101732ce", "message": "Berlin baby", "hearts": 37, - "createdAt": "2025-05-29T02:07:08.999Z", + "createdAt": "2025-05-30T02:07:08.999Z", "__v": 0 } ] \ No newline at end of file diff --git a/server.js b/server.js index fef4137..d466814 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,7 @@ import cors from "cors" import express from "express" import data from "./data.json" +import listEndpoints from "express-list-endpoints" // Defines the port the app will run on. Defaults to 8080, but can be overridden // when starting the server. Example command to overwrite PORT env variable value: @@ -13,8 +14,76 @@ app.use(cors()) app.use(express.json()) // Start defining your routes here - +// Endpoints with listEndpoints app.get("/", (req, res) => { + const endpoints = listEndpoints(app) + res.json({ + message: "Welcomen to the Happy Thoughts API", + endpoints: endpoints + }) + +}) + + +//Show all messages first version +// Show the data in data.json +// app.get("/messages", (req, res) => { +// res.json(data) +// }) + +//Show all messages +//Filter liked messages, /messages?liked, +//Filter messages from today /messages?messagesfromtoday +app.get("/messages", (req, res) => { + const showLiked = req.query.hasOwnProperty("liked"); + const showMessagesFromToday = req.query.hasOwnProperty("messagesfromtoday") + const today = new Date() + const todayDate = new Date(today.getFullYear(), today.getMonth(), today.getDate()) + + let filteredMessages = data + + if (showLiked){ + filteredMessages = filteredMessages.filter(message => message.hearts >0) + } + + if (showMessagesFromToday){ + filteredMessages = filteredMessages.filter(message => { + const createdAt = new Date(message.createdAt) + const messageData = new Date(createdAt.getFullYear(), createdAt.getMonth(), createdAt.getDate()) + + return messageData.getTime() === todayDate.getTime() + }) + } + + if (filteredMessages.length === 0) { + return res.status(404).json({ error: 'There are no messages to show' }); + } + + res.json(filteredMessages); +}); + +//Show all messages !!Is this not relevant? Should maybe be a qury param instead?!! +// app.get("/messages", (req, res) => { +// res.json(data.map((item) => item.message)) +// }) + +//Show a single message id +app.get("/messages/:id", (req, res) => { + + // be aware! The id that comes from the param is of type string. and in our json it is of type number. You have to turn them into the same type before you can compare them. trun a string to a number by adding + 👇 + const messageID = data.find((message) => message._id === req.params.id) + + // tiny error handling if we get an id that doesnt exist in our data + if (!messageID) { + return res.status(404).json({ error: 'message not found' }) + } + + res.json(messageID) +}) + + +//Nicer documentation including queries +app.get("/documentation", (req, res) => { res.send(` @@ -111,64 +180,6 @@ app.get("/", (req, res) => { }) -//Show all messages first version -// Show the data in data.json -// app.get("/messages", (req, res) => { -// res.json(data) -// }) - -//Show all messages -//Filter liked messages, /messages?liked, -//Filter messages from today /messages?messagesfromtoday -app.get("/messages", (req, res) => { - const showLiked = req.query.hasOwnProperty("liked"); - const showMessagesFromToday = req.query.hasOwnProperty("messagesfromtoday") - const today = new Date() - const todayDate = new Date(today.getFullYear(), today.getMonth(), today.getDate()) - - let filteredMessages = data - - if (showLiked){ - filteredMessages = filteredMessages.filter(message => message.hearts >0) - } - - if (showMessagesFromToday){ - filteredMessages = filteredMessages.filter(message => { - const createdAt = new Date(message.createdAt) - const messageData = new Date(createdAt.getFullYear(), createdAt.getMonth(), createdAt.getDate()) - - return messageData.getTime() === todayDate.getTime() - }) - } - - if (filteredMessages.length === 0) { - return res.status(404).json({ error: 'There are no messages to show' }); - } - - res.json(filteredMessages); -}); - -//Show all messages !!Is this not relevant? Should maybe be a qury param instead?!! -// app.get("/messages", (req, res) => { -// res.json(data.map((item) => item.message)) -// }) - -//Show a single message id -app.get("/messages/:id", (req, res) => { - - // be aware! The id that comes from the param is of type string. and in our json it is of type number. You have to turn them into the same type before you can compare them. trun a string to a number by adding + 👇 - const messageID = data.find((message) => message._id === req.params.id) - - // tiny error handling if we get an id that doesnt exist in our data - if (!messageID) { - return res.status(404).json({ error: 'message not found' }) - } - - res.json(messageID) -}) - - - // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) From 374626333cf0c9a95c85abd2d8422ac65244c646 Mon Sep 17 00:00:00 2001 From: solen80a Date: Wed, 4 Jun 2025 12:56:23 +0200 Subject: [PATCH 04/34] Changed from messages to thoughts --- data.json | 2 +- notes.md | 12 ++++++------ server.js | 52 +++++++++++++++++++++++++++------------------------- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/data.json b/data.json index 9fed3ae..365a0fc 100644 --- a/data.json +++ b/data.json @@ -3,7 +3,7 @@ "_id": "682bab8c12155b00101732ce", "message": "Berlin baby", "hearts": 37, - "createdAt": "2025-05-19T22:07:08.999Z", + "createdAt": "2025-05-31T02:07:08.999Z", "__v": 0 }, { diff --git a/notes.md b/notes.md index 0ce06cc..2877b69 100644 --- a/notes.md +++ b/notes.md @@ -1,10 +1,10 @@ W1: -[] Your API should have at least three (for now) routes. Try to push yourself to do more, though! - [] The endpoint "/" should return documentation of your API using e.g. Express List Endpoints - [] A minimum of one endpoint to return a collection of results (an array of elements). - [] A minimum of one endpoint to return a single result (single element). -[] Your API should be RESTful -[] You should follow the guidelines on how to write clean code. +[x] Your API should have at least three (for now) routes. Try to push yourself to do more, though! + [x] The endpoint "/" should return documentation of your API using e.g. Express List Endpoints + [x] A minimum of one endpoint to return a collection of results (an array of elements). + [x] A minimum of one endpoint to return a single result (single element). +[x] Your API should be RESTful +[x] You should follow the guidelines on how to write clean code. W2: [] Your API should use Mongoose models to model your data and use these models to fetch data from the database. diff --git a/server.js b/server.js index d466814..3f083d1 100644 --- a/server.js +++ b/server.js @@ -31,35 +31,37 @@ app.get("/", (req, res) => { // res.json(data) // }) -//Show all messages -//Filter liked messages, /messages?liked, -//Filter messages from today /messages?messagesfromtoday -app.get("/messages", (req, res) => { +//Show all thoughts +//Filter liked thoughts, thoughts?liked, +//Filter thoughts from today thoughts?thoughtsfromtoday +app.get("/thoughts", (req, res) => { const showLiked = req.query.hasOwnProperty("liked"); - const showMessagesFromToday = req.query.hasOwnProperty("messagesfromtoday") + const showThoughtsFromToday = req.query.hasOwnProperty("thoughtsfromtoday") const today = new Date() const todayDate = new Date(today.getFullYear(), today.getMonth(), today.getDate()) - let filteredMessages = data + const { hearts, createdAt } = req.query + + let filteredThoughts = data if (showLiked){ - filteredMessages = filteredMessages.filter(message => message.hearts >0) + filteredThoughts = filteredThoughts.filter(thought => thought.hearts >0) } - if (showMessagesFromToday){ - filteredMessages = filteredMessages.filter(message => { - const createdAt = new Date(message.createdAt) - const messageData = new Date(createdAt.getFullYear(), createdAt.getMonth(), createdAt.getDate()) + if (showThoughtsFromToday){ + filteredThoughts = filteredThoughts.filter(thought => { + const createdAt = new Date(thought.createdAt) + const thoughtsDate = new Date(createdAt.getFullYear(), createdAt.getMonth(), createdAt.getDate()) - return messageData.getTime() === todayDate.getTime() + return thoughtsDate.getTime() === todayDate.getTime() }) } - if (filteredMessages.length === 0) { - return res.status(404).json({ error: 'There are no messages to show' }); + if (filteredThoughts.length === 0) { + return res.status(404).json({ error: 'There are no thoughts to show' }); } - res.json(filteredMessages); + res.json(filteredThoughts); }); //Show all messages !!Is this not relevant? Should maybe be a qury param instead?!! @@ -67,18 +69,18 @@ app.get("/messages", (req, res) => { // res.json(data.map((item) => item.message)) // }) -//Show a single message id -app.get("/messages/:id", (req, res) => { +//Show a single thought id +app.get("/thoughts/:id", (req, res) => { // be aware! The id that comes from the param is of type string. and in our json it is of type number. You have to turn them into the same type before you can compare them. trun a string to a number by adding + 👇 - const messageID = data.find((message) => message._id === req.params.id) + const thoughtID = data.find((thought) => thought._id === req.params.id) // tiny error handling if we get an id that doesnt exist in our data - if (!messageID) { - return res.status(404).json({ error: 'message not found' }) + if (!thoughtID) { + return res.status(404).json({ error: 'thought not found' }) } - res.json(messageID) + res.json(thoughtID) }) @@ -114,7 +116,7 @@ app.get("/documentation", (req, res) => {

This is the documentation of Happy thoughts API.

Endpoints:

-

GET /messages

+

GET /thoughts

Returns a list of all happy thoughts.

Response:


@@ -129,7 +131,7 @@ app.get("/documentation", (req, res) => {
           ...
         ]
         
-

GET /messages?liked

+

GET /thoughts?liked

Returns a list of all happy thoughts with likes, >0.

Response:


@@ -144,7 +146,7 @@ app.get("/documentation", (req, res) => {
           ...
         ]
         
-

GET /messages?messagesfromtoday

+

GET /thoughts?messagesfromtoday

Returns a list of all happy thoughts from today .

Response:


@@ -159,7 +161,7 @@ app.get("/documentation", (req, res) => {
           ...
         ]
         
-

GET /messages/:id

+

GET /thoughts/:id

Returns a specific happy thought by id.

Response:



From 06e60570e6d9ae867c8dba5b7920aabbcb1d8426 Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Wed, 4 Jun 2025 12:57:40 +0200
Subject: [PATCH 05/34] Installed and imported mongoose

---
 package.json | 1 +
 server.js    | 4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 00addae..84d5f9f 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
     "cors": "^2.8.5",
     "express": "^4.17.3",
     "express-list-endpoints": "^7.1.1",
+    "mongoose": "^8.15.1",
     "nodemon": "^3.0.1"
   }
 }
diff --git a/server.js b/server.js
index 3f083d1..53ff56a 100644
--- a/server.js
+++ b/server.js
@@ -1,7 +1,9 @@
 import cors from "cors"
 import express from "express"
-import data from "./data.json"
 import listEndpoints from "express-list-endpoints"
+import mongoose from "mongoose"
+
+import data from "./data.json"
 
 // Defines the port the app will run on. Defaults to 8080, but can be overridden
 // when starting the server. Example command to overwrite PORT env variable value:

From dafb7fc7fb91cf7afe1fc8daec8646df4387037b Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Wed, 4 Jun 2025 13:03:19 +0200
Subject: [PATCH 06/34] Added Url and Schema

---
 server.js | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/server.js b/server.js
index 53ff56a..41b6719 100644
--- a/server.js
+++ b/server.js
@@ -5,6 +5,11 @@ import mongoose from "mongoose"
 
 import data from "./data.json"
 
+//To connect to the DB
+const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/happy-thoughts"
+mongoose.connect(mongoUrl)
+
+
 // Defines the port the app will run on. Defaults to 8080, but can be overridden
 // when starting the server. Example command to overwrite PORT env variable value:
 // PORT=9000 npm start
@@ -15,6 +20,15 @@ const app = express()
 app.use(cors())
 app.use(express.json())
 
+const thoughtSchema = new mongoose.Schema({
+  message: String,
+  hearts: Number,
+  createdAt: {
+    type: Date,
+    default: Date.now
+  }
+})
+
 // Start defining your routes here
 // Endpoints with listEndpoints
 app.get("/", (req, res) => {

From e790ebd27786fe628450023b46e111fe915d1d91 Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Wed, 4 Jun 2025 13:37:42 +0200
Subject: [PATCH 07/34] Seeded the DB with data from json. Started to transform
 the code to fetch from DB.

---
 data.json |  2 +-
 server.js | 66 +++++++++++++++++++++++++++++++++++++------------------
 2 files changed, 46 insertions(+), 22 deletions(-)

diff --git a/data.json b/data.json
index 365a0fc..4d5c0d7 100644
--- a/data.json
+++ b/data.json
@@ -112,7 +112,7 @@
     "__v": 0
   },
   {
-    "_id": "682bab8c12155b00101732ce",
+    "_id": "682bab8c12155b00101732cc",
     "message": "Berlin baby",
     "hearts": 37,
     "createdAt": "2025-05-30T02:07:08.999Z",
diff --git a/server.js b/server.js
index 41b6719..45c7890 100644
--- a/server.js
+++ b/server.js
@@ -29,6 +29,19 @@ const thoughtSchema = new mongoose.Schema({
   }
 })
 
+const Thought = mongoose.model("Thought", thoughtSchema)
+
+//RESET_DB=true npm run dev. DElete when not needed anymore.
+// if(process.env.RESET_DB){
+//   const seedDatabase = async () => {
+//     await Thought.deleteMany({})
+//     data.forEach(thought => {
+//       new Thought(thought).save()
+//     })
+//   }
+//   seedDatabase()
+// }
+
 // Start defining your routes here
 // Endpoints with listEndpoints
 app.get("/", (req, res) => {
@@ -47,37 +60,48 @@ app.get("/", (req, res) => {
 //   res.json(data)
 // })
 
-//Show all thoughts
+//Endpoint to show all thoughts
 //Filter liked thoughts, thoughts?liked, 
 //Filter thoughts from today thoughts?thoughtsfromtoday
-app.get("/thoughts", (req, res) => {
-  const showLiked = req.query.hasOwnProperty("liked");
-  const showThoughtsFromToday = req.query.hasOwnProperty("thoughtsfromtoday")
+app.get("/thoughts", async(req, res) => {
+
+  //const showLiked = req.query.hasOwnProperty("liked");
+  //const showThoughtsFromToday = req.query.hasOwnProperty("thoughtsfromtoday")
   const today = new Date()
   const todayDate = new Date(today.getFullYear(), today.getMonth(), today.getDate())
 
-  const { hearts, createdAt } = req.query
+  const { liked, thoughtsfromtoday } = req.query
 
-  let filteredThoughts = data   
-  
-    if (showLiked){
-      filteredThoughts = filteredThoughts.filter(thought => thought.hearts >0) 
-    } 
+  const query = {}  
 
-    if (showThoughtsFromToday){
-      filteredThoughts = filteredThoughts.filter(thought => {
-        const createdAt = new Date(thought.createdAt)
-        const thoughtsDate = new Date(createdAt.getFullYear(), createdAt.getMonth(), createdAt.getDate())
+  if (liked){
+    query.hearts = liked
+    filteredThoughts = filteredThoughts.filter(thought => thought.hearts >0)
+  }
 
-        return thoughtsDate.getTime() === todayDate.getTime()
-      })
-    }  
+  if (thoughtsfromtoday){
+    query.createdAt = thoughtsfromtoday
+    filteredThoughts = filteredThoughts.filter(thought => {
+      const createdAt = new Date(thought.createdAt)
+      const thoughtsDate = new Date(createdAt.getFullYear(), createdAt.getMonth(), createdAt.getDate())
+
+      return thoughtsDate.getTime() === todayDate.getTime()
+    }
+  )}
+    
+  try{
+    let filteredThoughts = await Thought.find(query) 
+
+    if (filteredThoughts.length === 0){
+      return res.status(404).json({ error: "There are no thoughts to show" })       
+    } 
+    res.status(200).json({ message: "Success"})   
 
-  if (filteredThoughts.length === 0) {
-    return res.status(404).json({ error: 'There are no thoughts to show' });
-  }
+  } catch (error) {
+    res.status(500).json({ message: "Failed to fetch thoughts"})
+  } 
 
-  res.json(filteredThoughts);
+  //res.json(filteredThoughts);
 });
 
 //Show all messages !!Is this not relevant? Should maybe be a qury param instead?!!

From 744fa8b09c1a75f96e83a85598c4657a2ee21d7f Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Wed, 4 Jun 2025 13:59:02 +0200
Subject: [PATCH 08/34] Endpoint /thoughts with query params updated to fetch
 from API

---
 server.js | 35 +++++++++++++++++++++--------------
 1 file changed, 21 insertions(+), 14 deletions(-)

diff --git a/server.js b/server.js
index 45c7890..50c9487 100644
--- a/server.js
+++ b/server.js
@@ -74,28 +74,35 @@ app.get("/thoughts", async(req, res) => {
 
   const query = {}  
 
-  if (liked){
-    query.hearts = liked
-    filteredThoughts = filteredThoughts.filter(thought => thought.hearts >0)
+  if (liked !== undefined){
+    query.hearts = { $gt: 0 } //greater than 0
+    //filteredThoughts = filteredThoughts.filter(thought => thought.hearts >0)
   }
 
-  if (thoughtsfromtoday){
-    query.createdAt = thoughtsfromtoday
-    filteredThoughts = filteredThoughts.filter(thought => {
-      const createdAt = new Date(thought.createdAt)
-      const thoughtsDate = new Date(createdAt.getFullYear(), createdAt.getMonth(), createdAt.getDate())
-
-      return thoughtsDate.getTime() === todayDate.getTime()
-    }
-  )}
+  if (thoughtsfromtoday !== undefined){
+    // query.createdAt = thoughtsfromtoday
+    // filteredThoughts = filteredThoughts.filter(thought => {
+    //   const createdAt = new Date(thought.createdAt)
+    //   const thoughtsDate = new Date(createdAt.getFullYear(), createdAt.getMonth(), createdAt.getDate())
+
+    //   return thoughtsDate.getTime() === todayDate.getTime()
+    // })
+    const tomorrowDate = new Date(todayDate);
+    tomorrowDate.setDate(todayDate.getDate() + 1);
+
+    query.createdAt = {
+      $gte: todayDate, //greater than or equal to todayDate
+      $lt: tomorrowDate, //less than tomorrowDate
+    };
+  }
     
   try{
-    let filteredThoughts = await Thought.find(query) 
+    const filteredThoughts = await Thought.find(query) 
 
     if (filteredThoughts.length === 0){
       return res.status(404).json({ error: "There are no thoughts to show" })       
     } 
-    res.status(200).json({ message: "Success"})   
+    res.status(200).json({ response: filteredThoughts })   
 
   } catch (error) {
     res.status(500).json({ message: "Failed to fetch thoughts"})

From 3df91848285d1006ba5246ae4d9de725c4033434 Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Wed, 4 Jun 2025 14:15:07 +0200
Subject: [PATCH 09/34] Updated endpoint /thoughts/:id to fetch from DB.

---
 server.js | 50 +++++++++++++++++++++++++-------------------------
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/server.js b/server.js
index 50c9487..b2d1e60 100644
--- a/server.js
+++ b/server.js
@@ -1,5 +1,5 @@
 import cors from "cors"
-import express from "express"
+import express, { response } from "express"
 import listEndpoints from "express-list-endpoints"
 import mongoose from "mongoose"
 
@@ -65,8 +65,6 @@ app.get("/", (req, res) => {
 //Filter thoughts from today thoughts?thoughtsfromtoday
 app.get("/thoughts", async(req, res) => {
 
-  //const showLiked = req.query.hasOwnProperty("liked");
-  //const showThoughtsFromToday = req.query.hasOwnProperty("thoughtsfromtoday")
   const today = new Date()
   const todayDate = new Date(today.getFullYear(), today.getMonth(), today.getDate())
 
@@ -75,18 +73,10 @@ app.get("/thoughts", async(req, res) => {
   const query = {}  
 
   if (liked !== undefined){
-    query.hearts = { $gt: 0 } //greater than 0
-    //filteredThoughts = filteredThoughts.filter(thought => thought.hearts >0)
+    query.hearts = { $gt: 0 } //greater than 0    
   }
 
-  if (thoughtsfromtoday !== undefined){
-    // query.createdAt = thoughtsfromtoday
-    // filteredThoughts = filteredThoughts.filter(thought => {
-    //   const createdAt = new Date(thought.createdAt)
-    //   const thoughtsDate = new Date(createdAt.getFullYear(), createdAt.getMonth(), createdAt.getDate())
-
-    //   return thoughtsDate.getTime() === todayDate.getTime()
-    // })
+  if (thoughtsfromtoday !== undefined){  
     const tomorrowDate = new Date(todayDate);
     tomorrowDate.setDate(todayDate.getDate() + 1);
 
@@ -105,10 +95,8 @@ app.get("/thoughts", async(req, res) => {
     res.status(200).json({ response: filteredThoughts })   
 
   } catch (error) {
-    res.status(500).json({ message: "Failed to fetch thoughts"})
-  } 
-
-  //res.json(filteredThoughts);
+    res.status(500).json({ error: "Failed to fetch thoughts"})
+  }    
 });
 
 //Show all messages !!Is this not relevant? Should maybe be a qury param instead?!!
@@ -116,18 +104,30 @@ app.get("/thoughts", async(req, res) => {
 //   res.json(data.map((item) => item.message))   
 // })
 
-//Show a single thought id 
-app.get("/thoughts/:id", (req, res) => {
+//Endpoint to show a single thought id 
+app.get("/thoughts/:id", async (req, res) => {
+  const { id } = req.params
+  try{
+    const thought = await Thought.findById(id)
 
-  // be aware! The id that comes from the param is of type string. and in our json it is of type number. You have to turn them into the same type before you can compare them. trun a string to a number by adding + 👇
-  const thoughtID = data.find((thought) => thought._id === req.params.id)
+    if (!thought){
+      return res.status(404).json({ error: "There is no thought with that id" })
+    }
+    res.status(200).json({ response: thought})
 
-  // tiny error handling if we get an id that doesnt exist in our data
-  if (!thoughtID) {
-    return res.status(404).json({ error: 'thought not found' })
+  } catch (error) {
+    res.status(500).json({ error: "Thoughts not found"})
   }
+
+  // // be aware! The id that comes from the param is of type string. and in our json it is of type number. You have to turn them into the same type before you can compare them. trun a string to a number by adding + 👇
+  // const thoughtID = data.find((thought) => thought._id === req.params.id)
+
+  // // tiny error handling if we get an id that doesnt exist in our data
+  // if (!thoughtID) {
+  //   return res.status(404).json({ error: 'thought not found' })
+  // }
  
-  res.json(thoughtID)
+  // res.json(thoughtID)
 })
 
 

From 45c8320fe1671c7630f64ec6043a04b0a2fb829d Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Wed, 4 Jun 2025 14:16:05 +0200
Subject: [PATCH 10/34] Some cleaning.

---
 server.js | 21 ---------------------
 1 file changed, 21 deletions(-)

diff --git a/server.js b/server.js
index b2d1e60..0bb13a4 100644
--- a/server.js
+++ b/server.js
@@ -53,13 +53,6 @@ app.get("/", (req, res) => {
 
 })
 
-
-//Show all messages first version
-// Show the data in data.json
-// app.get("/messages", (req, res) => {
-//   res.json(data)
-// })
-
 //Endpoint to show all thoughts
 //Filter liked thoughts, thoughts?liked, 
 //Filter thoughts from today thoughts?thoughtsfromtoday
@@ -99,11 +92,6 @@ app.get("/thoughts", async(req, res) => {
   }    
 });
 
-//Show all messages !!Is this not relevant? Should maybe be a qury param instead?!!
-// app.get("/messages", (req, res) => {
-//   res.json(data.map((item) => item.message))   
-// })
-
 //Endpoint to show a single thought id 
 app.get("/thoughts/:id", async (req, res) => {
   const { id } = req.params
@@ -118,16 +106,7 @@ app.get("/thoughts/:id", async (req, res) => {
   } catch (error) {
     res.status(500).json({ error: "Thoughts not found"})
   }
-
-  // // be aware! The id that comes from the param is of type string. and in our json it is of type number. You have to turn them into the same type before you can compare them. trun a string to a number by adding + 👇
-  // const thoughtID = data.find((thought) => thought._id === req.params.id)
-
-  // // tiny error handling if we get an id that doesnt exist in our data
-  // if (!thoughtID) {
-  //   return res.status(404).json({ error: 'thought not found' })
-  // }
  
-  // res.json(thoughtID)
 })
 
 

From dfde63dd42dd36fbf608cc60a3789ec868ed076d Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Wed, 4 Jun 2025 14:36:08 +0200
Subject: [PATCH 11/34] Added a POST for new thoughts.

---
 notes.md  |  9 ++++++++-
 server.js | 15 +++++++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/notes.md b/notes.md
index 2877b69..a55dfff 100644
--- a/notes.md
+++ b/notes.md
@@ -7,10 +7,17 @@ W1:
 [x] You should follow the guidelines on how to write clean code.
 
 W2:
-[] Your API should use Mongoose models to model your data and use these models to fetch data from the database.
+[X] Your API should use Mongoose models to model your data and use these models to fetch data from the database.
 [] Your API should validate user input and return appropriate errors if the input is invalid.
 [] You should implement error handling for all your routes, with proper response statuses.
 [] Your frontend should be updated with the possibility to Update and Delete a thought.
+[] Deployed backend with deployed DB
+[] Posibility to: 
+  [] POST 
+  [] PATCH 
+  [] DELETE
+[] Frontend posibility to POST (to your API)
+[] Nice to have: Frontend possibility to edit and delete
 
 W3:
 [] Signup and Login existing Happy Thoughts
diff --git a/server.js b/server.js
index 0bb13a4..87ae974 100644
--- a/server.js
+++ b/server.js
@@ -42,6 +42,7 @@ const Thought = mongoose.model("Thought", thoughtSchema)
 //   seedDatabase()
 // }
 
+//GET
 // Start defining your routes here
 // Endpoints with listEndpoints
 app.get("/", (req, res) => {
@@ -208,6 +209,20 @@ app.get("/documentation", (req, res) => {
   
 })
 
+//POST
+app.post("/thoughts", async(req, res) => {
+  const { message, hearts, createdAt } = req.body
+
+  try {
+    const newThought = await new Thought({ message, hearts, createdAt }).save()
+
+    res.status(201).json({ response: newThought })
+
+  } catch (error) {
+    res.status(500).json({ error: "Thought could not be created"})
+  }
+})
+
 // Start the server
 app.listen(port, () => {
   console.log(`Server running on http://localhost:${port}`)

From c3d46091a7ee816ac9f8717d36f94618bdcaaa54 Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Wed, 4 Jun 2025 14:48:45 +0200
Subject: [PATCH 12/34] Added a DELETE for endpoint /thoughts/:id.

---
 server.js | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/server.js b/server.js
index 87ae974..9c1dadd 100644
--- a/server.js
+++ b/server.js
@@ -205,8 +205,7 @@ app.get("/documentation", (req, res) => {
         
       
     
-    `)
-  
+    `)  
 })
 
 //POST
@@ -223,6 +222,22 @@ app.post("/thoughts", async(req, res) => {
   }
 })
 
+//DELETE
+app.delete("/thoughts/:id", async(req, res) => {
+  const { id } = req.params
+
+  try{
+    const thought = await Thought.findByIdAndDelete(id)
+
+    if (!thought) {
+      return res.status(404).json({ error: "Thought id was not found, could not deleted" })
+    }
+    res.status(200).json({message: `Thought with message: ${thought.message}, was deleted`})
+  } catch (error) {
+    res.status(500).json({ error: "Thought id was not found"})
+  }
+})
+
 // Start the server
 app.listen(port, () => {
   console.log(`Server running on http://localhost:${port}`)

From c938b18d021b1b2a1203add36bc0b6cc27d3bd80 Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Wed, 4 Jun 2025 15:23:47 +0200
Subject: [PATCH 13/34] Added PATCH for new thougth message and like.

---
 server.js | 28 +++++++++++++++++++++++++---
 1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/server.js b/server.js
index 9c1dadd..9557db8 100644
--- a/server.js
+++ b/server.js
@@ -22,7 +22,10 @@ app.use(express.json())
 
 const thoughtSchema = new mongoose.Schema({
   message: String,
-  hearts: Number,
+  hearts: {
+    type: Number,
+    default: 0
+  },
   createdAt: {
     type: Date,
     default: Date.now
@@ -105,7 +108,7 @@ app.get("/thoughts/:id", async (req, res) => {
     res.status(200).json({ response: thought})
 
   } catch (error) {
-    res.status(500).json({ error: "Thoughts not found"})
+    res.status(500).json({ error: "Failed to fetch thoughts"})
   }
  
 })
@@ -234,7 +237,26 @@ app.delete("/thoughts/:id", async(req, res) => {
     }
     res.status(200).json({message: `Thought with message: ${thought.message}, was deleted`})
   } catch (error) {
-    res.status(500).json({ error: "Thought id was not found"})
+    res.status(500).json({ error: "Failed to fetch thoughts"})
+  }
+})
+
+//PATCH
+app.patch("/thoughts/:id", async(req, res) => {
+  const { id } = req.params
+  const { newThoughtMessage } = req.body
+  const { newThoughtLike } = req.body
+
+  try{
+    const thought = await Thought.findByIdAndUpdate(id, { message: newThoughtMessage }, { hearts: newThoughtLike }, { new: true }, { runValidators: true })
+
+    if(!thought){
+      return res.status(404).json({ error: "Thought id was not found, could not update" })
+    }
+    res.status(200).json({ message: `Thought was updated`})
+
+  } catch (error) {
+    res.status(500).json({ error: "Failed to fetch thoughts"})
   }
 })
 

From e44a2aeec56ad5c89b79ea9bf7ec3dc12b3ae23c Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Thu, 5 Jun 2025 20:38:04 +0200
Subject: [PATCH 14/34] Added POSt to increase likes to a thought. Also added
 message to a like as required and minlength of 5 caracters.

---
 notes.md  | 15 +++++++--------
 server.js | 40 ++++++++++++++++++++++++++++++++++------
 2 files changed, 41 insertions(+), 14 deletions(-)

diff --git a/notes.md b/notes.md
index a55dfff..4355074 100644
--- a/notes.md
+++ b/notes.md
@@ -8,16 +8,15 @@ W1:
 
 W2:
 [X] Your API should use Mongoose models to model your data and use these models to fetch data from the database.
-[] Your API should validate user input and return appropriate errors if the input is invalid.
-[] You should implement error handling for all your routes, with proper response statuses.
+[x] Your API should validate user input and return appropriate errors if the input is invalid.
+[x] You should implement error handling for all your routes, with proper response statuses.
 [] Your frontend should be updated with the possibility to Update and Delete a thought.
-[] Deployed backend with deployed DB
-[] Posibility to: 
-  [] POST 
-  [] PATCH 
-  [] DELETE
+[] Deployed backend API with deployed DB
+[x] Posibility to: 
+  [x] POST 
+  [x] PATCH 
+  [x] DELETE
 [] Frontend posibility to POST (to your API)
-[] Nice to have: Frontend possibility to edit and delete
 
 W3:
 [] Signup and Login existing Happy Thoughts
diff --git a/server.js b/server.js
index 9557db8..5f781ea 100644
--- a/server.js
+++ b/server.js
@@ -21,7 +21,11 @@ app.use(cors())
 app.use(express.json())
 
 const thoughtSchema = new mongoose.Schema({
-  message: String,
+  message: {
+    type: String,
+    required: true,
+    minlength: 5
+  },
   hearts: {
     type: Number,
     default: 0
@@ -213,10 +217,10 @@ app.get("/documentation", (req, res) => {
 
 //POST
 app.post("/thoughts", async(req, res) => {
-  const { message, hearts, createdAt } = req.body
+  const { message } = req.body
 
   try {
-    const newThought = await new Thought({ message, hearts, createdAt }).save()
+    const newThought = await new Thought({ message }).save()
 
     res.status(201).json({ response: newThought })
 
@@ -225,6 +229,31 @@ app.post("/thoughts", async(req, res) => {
   }
 })
 
+app.post("/thoughts/:id/like", async (req, res) => {
+  const { id } = req.params;
+
+  try {
+    const newThoughtLike = await Thought.findByIdAndUpdate(
+      id,
+      { $inc: { hearts: 1 } },
+      { new: true } // return the updated document
+    );
+
+    if (!newThoughtLike) {
+      return res.status(404).json({ error: "Thought not found, could not update" });
+    }
+
+    res.status(200).json({ 
+      message: `Thought with message: ${newThoughtLike.message}, was liked.`,
+      hearts: newThoughtLike.hearts,
+    });
+
+  } catch (error) {
+    res.status(500).json({ error: "Failed to fetch thoughts" });
+  }
+});
+
+
 //DELETE
 app.delete("/thoughts/:id", async(req, res) => {
   const { id } = req.params
@@ -244,11 +273,10 @@ app.delete("/thoughts/:id", async(req, res) => {
 //PATCH
 app.patch("/thoughts/:id", async(req, res) => {
   const { id } = req.params
-  const { newThoughtMessage } = req.body
-  const { newThoughtLike } = req.body
+  const { newThoughtMessage } = req.body  
 
   try{
-    const thought = await Thought.findByIdAndUpdate(id, { message: newThoughtMessage }, { hearts: newThoughtLike }, { new: true }, { runValidators: true })
+    const thought = await Thought.findByIdAndUpdate(id, { message: newThoughtMessage }, { new: true }, { runValidators: true })
 
     if(!thought){
       return res.status(404).json({ error: "Thought id was not found, could not update" })

From e209250506ee6f778f771e23abd21c2afda72c70 Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Thu, 5 Jun 2025 21:25:35 +0200
Subject: [PATCH 15/34] Changed the response on my get /thoughts

---
 server.js | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/server.js b/server.js
index 5f781ea..a7be023 100644
--- a/server.js
+++ b/server.js
@@ -93,7 +93,7 @@ app.get("/thoughts", async(req, res) => {
     if (filteredThoughts.length === 0){
       return res.status(404).json({ error: "There are no thoughts to show" })       
     } 
-    res.status(200).json({ response: filteredThoughts })   
+    res.status(200).json(filteredThoughts)   
 
   } catch (error) {
     res.status(500).json({ error: "Failed to fetch thoughts"})
@@ -242,7 +242,6 @@ app.post("/thoughts/:id/like", async (req, res) => {
     if (!newThoughtLike) {
       return res.status(404).json({ error: "Thought not found, could not update" });
     }
-
     res.status(200).json({ 
       message: `Thought with message: ${newThoughtLike.message}, was liked.`,
       hearts: newThoughtLike.hearts,

From 3c662ce4e341000f48e675ad01e2a551dca9e420 Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Fri, 6 Jun 2025 09:28:00 +0200
Subject: [PATCH 16/34] Note update

---
 notes.md | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/notes.md b/notes.md
index 4355074..a61558b 100644
--- a/notes.md
+++ b/notes.md
@@ -11,12 +11,14 @@ W2:
 [x] Your API should validate user input and return appropriate errors if the input is invalid.
 [x] You should implement error handling for all your routes, with proper response statuses.
 [] Your frontend should be updated with the possibility to Update and Delete a thought.
+  [] Update
+  [x] Delete
 [] Deployed backend API with deployed DB
 [x] Posibility to: 
   [x] POST 
   [x] PATCH 
   [x] DELETE
-[] Frontend posibility to POST (to your API)
+[x] Frontend posibility to POST (to your API)
 
 W3:
 [] Signup and Login existing Happy Thoughts

From 1b80d420dcbae3483f7de3aaa60a910f261c1ded Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Tue, 10 Jun 2025 14:56:09 +0200
Subject: [PATCH 17/34] Deployed and connected API and DB. Installed dotenv and
 created a env file.

---
 notes.md     | 2 +-
 package.json | 1 +
 server.js    | 5 ++++-
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/notes.md b/notes.md
index a61558b..c1099ee 100644
--- a/notes.md
+++ b/notes.md
@@ -13,7 +13,7 @@ W2:
 [] Your frontend should be updated with the possibility to Update and Delete a thought.
   [] Update
   [x] Delete
-[] Deployed backend API with deployed DB
+[x] Deployed backend API with deployed DB
 [x] Posibility to: 
   [x] POST 
   [x] PATCH 
diff --git a/package.json b/package.json
index 84d5f9f..d320bcb 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
     "@babel/node": "^7.16.8",
     "@babel/preset-env": "^7.16.11",
     "cors": "^2.8.5",
+    "dotenv": "^16.5.0",
     "express": "^4.17.3",
     "express-list-endpoints": "^7.1.1",
     "mongoose": "^8.15.1",
diff --git a/server.js b/server.js
index a7be023..a2c8dc3 100644
--- a/server.js
+++ b/server.js
@@ -1,10 +1,13 @@
 import cors from "cors"
+import dotenv from "dotenv"
 import express, { response } from "express"
 import listEndpoints from "express-list-endpoints"
 import mongoose from "mongoose"
 
 import data from "./data.json"
 
+dotenv.config()
+
 //To connect to the DB
 const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/happy-thoughts"
 mongoose.connect(mongoUrl)
@@ -280,7 +283,7 @@ app.patch("/thoughts/:id", async(req, res) => {
     if(!thought){
       return res.status(404).json({ error: "Thought id was not found, could not update" })
     }
-    res.status(200).json({ message: `Thought was updated`})
+    res.status(200).json({ message: `Thought was updated to: ${newThoughtMessage}`})
 
   } catch (error) {
     res.status(500).json({ error: "Failed to fetch thoughts"})

From b2d38fc6f2f73476eae89ac2f220cce90f59974f Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Tue, 10 Jun 2025 21:31:47 +0200
Subject: [PATCH 18/34] Added bcrypt. Created models thoughts and users

---
 Model/thoughts.js |  0
 Model/users.js    | 71 +++++++++++++++++++++++++++++++++++++++++++++++
 package.json      |  1 +
 server.js         |  2 +-
 4 files changed, 73 insertions(+), 1 deletion(-)
 create mode 100644 Model/thoughts.js
 create mode 100644 Model/users.js

diff --git a/Model/thoughts.js b/Model/thoughts.js
new file mode 100644
index 0000000..e69de29
diff --git a/Model/users.js b/Model/users.js
new file mode 100644
index 0000000..3635585
--- /dev/null
+++ b/Model/users.js
@@ -0,0 +1,71 @@
+import bcrypt from "bcrypt"
+import crypto from "crypto"
+import mongoose from "mongoose";
+
+const userSchema = new mongoose.Schema({
+  name: {
+    type: String,
+    unique: true,
+    required: true,
+    minlength: 3,
+    maxlength: 100
+  },
+  email: {
+    type: String,
+    required: true,
+    unique: true,
+    minlength: 3,
+    maxlength: 100
+  },
+  password: {
+    type: String,
+    required: true,
+    minlength: 3,
+    maxlength: 100
+  },
+  accessToken: {
+    type: String,
+    default: () => crypto.randomBytes(128).toString("hex")
+  },
+  createdAt: {
+    type: Date,
+    default: Date.now
+  }
+}) 
+
+const User = mongoose.model("User", userSchema)
+
+//Middleware function
+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})
+  }
+}
+
+app.get("/users", 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(200).json({userId:user._id, accessToken: user.accessToken})
+  } catch(error){
+    res.status(400).json({message: "Could not create user", errors: error.errors})
+  }  
+})
+
+app.get("/secrets", authenticateUser)
+
+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, accessToken: user.accessToken})
+  } else {
+    res.json({notFound: true})
+  }
+})
\ No newline at end of file
diff --git a/package.json b/package.json
index d320bcb..4811395 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
     "@babel/core": "^7.17.9",
     "@babel/node": "^7.16.8",
     "@babel/preset-env": "^7.16.11",
+    "bcrypt": "^6.0.0",
     "cors": "^2.8.5",
     "dotenv": "^16.5.0",
     "express": "^4.17.3",
diff --git a/server.js b/server.js
index a2c8dc3..3c3e935 100644
--- a/server.js
+++ b/server.js
@@ -275,7 +275,7 @@ app.delete("/thoughts/:id", async(req, res) => {
 //PATCH
 app.patch("/thoughts/:id", async(req, res) => {
   const { id } = req.params
-  const { newThoughtMessage } = req.body  
+  const { newThoughtMessage } = req.body.message  
 
   try{
     const thought = await Thought.findByIdAndUpdate(id, { message: newThoughtMessage }, { new: true }, { runValidators: true })

From 03c4556dafba55cae9e2f251033f925eaac2ed8e Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Tue, 10 Jun 2025 21:47:56 +0200
Subject: [PATCH 19/34] Updated patch

---
 server.js | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/server.js b/server.js
index 3c3e935..1f5cdf3 100644
--- a/server.js
+++ b/server.js
@@ -275,15 +275,15 @@ app.delete("/thoughts/:id", async(req, res) => {
 //PATCH
 app.patch("/thoughts/:id", async(req, res) => {
   const { id } = req.params
-  const { newThoughtMessage } = req.body.message  
+  const { newThoughtMessage } = req.body
 
   try{
-    const thought = await Thought.findByIdAndUpdate(id, { message: newThoughtMessage }, { new: true }, { runValidators: true })
+    const thought = await Thought.findByIdAndUpdate(id, { message: newThoughtMessage }, { new: true , runValidators: true })
 
     if(!thought){
       return res.status(404).json({ error: "Thought id was not found, could not update" })
     }
-    res.status(200).json({ message: `Thought was updated to: ${newThoughtMessage}`})
+    res.status(200).json({ response: thought, message: `Thought was updated to: ${thought}`})
 
   } catch (error) {
     res.status(500).json({ error: "Failed to fetch thoughts"})

From 7b7a74ee3de24f428a548ad1a905f59a7d483dc9 Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Tue, 10 Jun 2025 21:54:36 +0200
Subject: [PATCH 20/34] Updates to patch

---
 server.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/server.js b/server.js
index 1f5cdf3..055ff0d 100644
--- a/server.js
+++ b/server.js
@@ -283,7 +283,7 @@ app.patch("/thoughts/:id", async(req, res) => {
     if(!thought){
       return res.status(404).json({ error: "Thought id was not found, could not update" })
     }
-    res.status(200).json({ response: thought, message: `Thought was updated to: ${thought}`})
+    res.status(200).json({ response: newThoughtMessage, message: `Thought was updated to: ${newThoughtMessage}`})
 
   } catch (error) {
     res.status(500).json({ error: "Failed to fetch thoughts"})

From 2ec257a037573e1ebc12cfc90cd7ba7110b822d5 Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Wed, 11 Jun 2025 08:08:51 +0200
Subject: [PATCH 21/34] Made som comments.

---
 notes.md  | 4 ++--
 server.js | 3 ++-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/notes.md b/notes.md
index c1099ee..21de44c 100644
--- a/notes.md
+++ b/notes.md
@@ -10,8 +10,8 @@ W2:
 [X] Your API should use Mongoose models to model your data and use these models to fetch data from the database.
 [x] Your API should validate user input and return appropriate errors if the input is invalid.
 [x] You should implement error handling for all your routes, with proper response statuses.
-[] Your frontend should be updated with the possibility to Update and Delete a thought.
-  [] Update
+[x] Your frontend should be updated with the possibility to Update and Delete a thought.
+  [x] Update
   [x] Delete
 [x] Deployed backend API with deployed DB
 [x] Posibility to: 
diff --git a/server.js b/server.js
index 055ff0d..115727b 100644
--- a/server.js
+++ b/server.js
@@ -273,6 +273,7 @@ app.delete("/thoughts/:id", async(req, res) => {
 })
 
 //PATCH
+//Endpoint /thoughts/:id, json body {"newThoughtMessage": "edited message"}
 app.patch("/thoughts/:id", async(req, res) => {
   const { id } = req.params
   const { newThoughtMessage } = req.body
@@ -283,7 +284,7 @@ app.patch("/thoughts/:id", async(req, res) => {
     if(!thought){
       return res.status(404).json({ error: "Thought id was not found, could not update" })
     }
-    res.status(200).json({ response: newThoughtMessage, message: `Thought was updated to: ${newThoughtMessage}`})
+    res.status(200).json({ message: `Thought was updated to: ${thought}`})
 
   } catch (error) {
     res.status(500).json({ error: "Failed to fetch thoughts"})

From 6df9d702e99e5335de19eb79d8f5d09c985ead05 Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Wed, 11 Jun 2025 14:27:43 +0200
Subject: [PATCH 22/34] Broke out models for user and thought. Created get post
 for users and authentication.

---
 Model/thoughts.js |  0
 Model/users.js    | 71 -------------------------------------
 models/thought.js | 19 ++++++++++
 models/user.js    | 64 +++++++++++++++++++++++++++++++++
 server.js         | 90 ++++++++++++++++++++++++++++++++++++++---------
 utils/postUser.js | 47 +++++++++++++++++++++++++
 6 files changed, 203 insertions(+), 88 deletions(-)
 delete mode 100644 Model/thoughts.js
 delete mode 100644 Model/users.js
 create mode 100644 models/thought.js
 create mode 100644 models/user.js
 create mode 100644 utils/postUser.js

diff --git a/Model/thoughts.js b/Model/thoughts.js
deleted file mode 100644
index e69de29..0000000
diff --git a/Model/users.js b/Model/users.js
deleted file mode 100644
index 3635585..0000000
--- a/Model/users.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import bcrypt from "bcrypt"
-import crypto from "crypto"
-import mongoose from "mongoose";
-
-const userSchema = new mongoose.Schema({
-  name: {
-    type: String,
-    unique: true,
-    required: true,
-    minlength: 3,
-    maxlength: 100
-  },
-  email: {
-    type: String,
-    required: true,
-    unique: true,
-    minlength: 3,
-    maxlength: 100
-  },
-  password: {
-    type: String,
-    required: true,
-    minlength: 3,
-    maxlength: 100
-  },
-  accessToken: {
-    type: String,
-    default: () => crypto.randomBytes(128).toString("hex")
-  },
-  createdAt: {
-    type: Date,
-    default: Date.now
-  }
-}) 
-
-const User = mongoose.model("User", userSchema)
-
-//Middleware function
-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})
-  }
-}
-
-app.get("/users", 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(200).json({userId:user._id, accessToken: user.accessToken})
-  } catch(error){
-    res.status(400).json({message: "Could not create user", errors: error.errors})
-  }  
-})
-
-app.get("/secrets", authenticateUser)
-
-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, accessToken: user.accessToken})
-  } else {
-    res.json({notFound: true})
-  }
-})
\ No newline at end of file
diff --git a/models/thought.js b/models/thought.js
new file mode 100644
index 0000000..0e68ddd
--- /dev/null
+++ b/models/thought.js
@@ -0,0 +1,19 @@
+import mongoose from "mongoose";
+
+const thoughtSchema = new mongoose.Schema({
+  message: {
+    type: String,
+    required: true,
+    minlength: 5
+  },
+  hearts: {
+    type: Number,
+    default: 0
+  },
+  createdAt: {
+    type: Date,
+    default: Date.now
+  }
+})
+
+export const Thought = mongoose.model("Thought", thoughtSchema)
\ No newline at end of file
diff --git a/models/user.js b/models/user.js
new file mode 100644
index 0000000..e477fef
--- /dev/null
+++ b/models/user.js
@@ -0,0 +1,64 @@
+//import bcrypt from "bcrypt"
+import crypto from "crypto"
+import mongoose from "mongoose";
+
+const userSchema = new mongoose.Schema({
+  email: {
+    type: String,
+    required: true,
+    unique: true,
+    minlength: 3,
+    maxlength: 100
+  },
+  password: {
+    type: String,
+    required: true,
+    minlength: 3,
+    maxlength: 100
+  },
+  accessToken: {
+    type: String,
+    default: () => crypto.randomBytes(128).toString("hex")
+  },
+  createdAt: {
+    type: Date,
+    default: Date.now
+  }
+}) 
+
+export const User = mongoose.model("User", userSchema)
+
+// //Middleware function
+// 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})
+//   }
+// }
+
+// app.get("/users", async (req, res) => {
+//   try{
+//     const { email, password } = req.body
+//     const salt = bcrypt.genSaltSync()
+//     const user = new User({email, password: bcrypt.hashSync(password, salt)})
+//     user.save()
+//     res.status(200).json({userId:user._id, accessToken: user.accessToken})
+//   } catch(error){
+//     res.status(400).json({message: "Could not create user", errors: error.errors})
+//   }  
+// })
+
+// app.get("/secrets", authenticateUser)
+
+// 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, accessToken: user.accessToken})
+//   } else {
+//     res.json({notFound: true})
+//   }
+// })
\ No newline at end of file
diff --git a/server.js b/server.js
index 115727b..a500ac9 100644
--- a/server.js
+++ b/server.js
@@ -1,3 +1,4 @@
+import bcrypt from "bcrypt"
 import cors from "cors"
 import dotenv from "dotenv"
 import express, { response } from "express"
@@ -5,6 +6,9 @@ import listEndpoints from "express-list-endpoints"
 import mongoose from "mongoose"
 
 import data from "./data.json"
+import { Thought } from "./models/thought"
+import { User } from "./models/user"
+import { postUser } from "./utils/postUser"
 
 dotenv.config()
 
@@ -23,23 +27,34 @@ const app = express()
 app.use(cors())
 app.use(express.json())
 
-const thoughtSchema = new mongoose.Schema({
-  message: {
-    type: String,
-    required: true,
-    minlength: 5
-  },
-  hearts: {
-    type: Number,
-    default: 0
-  },
-  createdAt: {
-    type: Date,
-    default: Date.now
+//Middleware function
+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})
   }
-})
+}
+
+// const thoughtSchema = new mongoose.Schema({
+//   message: {
+//     type: String,
+//     required: true,
+//     minlength: 5
+//   },
+//   hearts: {
+//     type: Number,
+//     default: 0
+//   },
+//   createdAt: {
+//     type: Date,
+//     default: Date.now
+//   }
+// })
 
-const Thought = mongoose.model("Thought", thoughtSchema)
+// const Thought = mongoose.model("Thought", thoughtSchema)
 
 //RESET_DB=true npm run dev. DElete when not needed anymore.
 // if(process.env.RESET_DB){
@@ -91,7 +106,7 @@ app.get("/thoughts", async(req, res) => {
   }
     
   try{
-    const filteredThoughts = await Thought.find(query) 
+    const filteredThoughts = await Thought.find(query).sort({createdAt: "desc"}) 
 
     if (filteredThoughts.length === 0){
       return res.status(404).json({ error: "There are no thoughts to show" })       
@@ -284,13 +299,54 @@ app.patch("/thoughts/:id", async(req, res) => {
     if(!thought){
       return res.status(404).json({ error: "Thought id was not found, could not update" })
     }
-    res.status(200).json({ message: `Thought was updated to: ${thought}`})
+    res.status(200).json({ message: `Thought was updated to: ${newThoughtMessage}`})
 
   } catch (error) {
     res.status(500).json({ error: "Failed to fetch thoughts"})
   }
 })
 
+app.get("/users", async (req, res) => {
+  const { email } = req.params  
+
+  try {
+    const user = await User.find(email)
+
+    if (!user) {
+      return res.status(404).json({
+        success: false,
+        response: null,
+        message: "No users found"
+      })
+    }
+
+    res.status(200).json({
+      success: true,
+      response: user
+    })
+  } catch (error) {
+    res.status(500).json({
+      success: false,
+      response: error,
+      message: "Failed to fetch users"
+    })
+  }
+})
+
+app.post("/users", postUser)
+
+app.get("/secrets", authenticateUser)
+
+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, accessToken: user.accessToken})
+  } else {
+    res.json({notFound: true})
+  }
+})
+
 // Start the server
 app.listen(port, () => {
   console.log(`Server running on http://localhost:${port}`)
diff --git a/utils/postUser.js b/utils/postUser.js
new file mode 100644
index 0000000..1033609
--- /dev/null
+++ b/utils/postUser.js
@@ -0,0 +1,47 @@
+import bcrypt from "bcrypt"
+import { response } from "express";
+
+import { User } from "../models/user";
+
+// export const postUser async (req, res) => {
+//   try{
+//     const {email, password} = req.body
+//     const salt = bcrypt.genSaltSync()
+
+//     const user = new User({ email, password: bcrypt.hashSync(password, salt) })
+//     await user.save()
+
+//     res.status(200).json({
+//       success: true,
+//       message: "User created succesfully",
+//       response: {
+//         id: user._id,
+//         accessToken: user.accessToken
+//       }
+
+//     })
+
+//   } catch (error) {
+//     res.status(400).json({
+//       success: false,
+//       message: "Failed to create user",
+//       response: error
+//     })
+//   }
+// }
+
+
+
+//app.get("/users", async (req, res) => 
+export const postUser = async (req, res) => {
+  try{
+    const { email, password } = req.body
+    const salt = bcrypt.genSaltSync()
+    const user = new User({email, password: bcrypt.hashSync(password, salt)})
+    user.save()
+    res.status(200).json({userId:user._id, accessToken: user.accessToken})
+  } catch(error){
+    res.status(400).json({message: "Could not create user", errors: error.errors})
+  }  
+}
+

From d2509ade1f05c876357b19003f43838f98f3dccf Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Fri, 13 Jun 2025 18:07:13 +0200
Subject: [PATCH 23/34] Broke out authanticateuser and created routes for
 thoughts and user, not broken out yet.

---
 middleware/authMiddleware.js | 11 +++++++++++
 notes.md                     | 24 ++++++++++++------------
 routes/thoughtRoutes.js      |  0
 routes/userRoutes.js         |  0
 server.js                    | 30 ++++++++++++++++--------------
 utils/postUser.js            | 13 +++++++++++--
 6 files changed, 50 insertions(+), 28 deletions(-)
 create mode 100644 middleware/authMiddleware.js
 create mode 100644 routes/thoughtRoutes.js
 create mode 100644 routes/userRoutes.js

diff --git a/middleware/authMiddleware.js b/middleware/authMiddleware.js
new file mode 100644
index 0000000..dc9f017
--- /dev/null
+++ b/middleware/authMiddleware.js
@@ -0,0 +1,11 @@
+import { User } from "../models/user"
+
+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/notes.md b/notes.md
index 21de44c..d833f59 100644
--- a/notes.md
+++ b/notes.md
@@ -24,27 +24,27 @@ W3:
 [] Signup and Login existing Happy Thoughts
 [] Your API should have routes to register and log in
 [] Your endpoints to Create, Update and Delete should be authenticated
-[] Your frontend should have a registration form which POSTs to the API to create a new user.
+[x] Your frontend should have a registration form which POSTs to the API to create a new user.
 [] Your frontend should have a login form to authenticate the user.
-[] Your passwords in the database should be encrypted with bcrypt.
+[x] Your passwords in the database should be encrypted with bcrypt.
 [] You should implement error handling. Your API should let the user know if something went wrong. Be as specific as possible to help the user, e.g. by validating the user input when creating a new user, and return "That email address already exists". Include correct status codes. Error messages should also be shown on the frontend.
-[] The validation should ensure unique email addresses and/or usernames, depending on how you'd like to structure your User model.
+[x] The validation should ensure unique email addresses and/or usernames, depending on how you'd like to structure your User model.
 
 
 Requirements:
 [] Your API must have at least the following routes. Try to push yourself to do more, though! Endpoints for:
-  [] Documentation of your API using e.g. Express List Endpoints
-  [] Reading thoughts
-  [] Reading a single thought
-  [] Liking a thought
-  [] Creating a thought (authenticated)
-  [] Updating a thought (authenticated)
-  [] Deleting a thought (authenticated)
+  [x] Documentation of your API using e.g. Express List Endpoints
+  [x] Reading thoughts
+  [x] Reading a single thought
+  [x] Liking a thought
+  [x] Creating a thought (authenticated)
+  [x] Updating a thought (authenticated)
+  [x] Deleting a thought (authenticated)
   [] Signing up
   [] Logging in 
-[] Your API should be RESTful
+[x] Your API should be RESTful
 [] You should follow the guidelines on how to write clean code
-[] Your API should use Mongoose models to model your data and use these models to fetch data from the database.
+[x] Your API should use Mongoose models to model your data and use these models to fetch data from the database.
 [] Your API should validate user input and return appropriate errors if the input is invalid.
 [] The validation should ensure unique email addresses and/or usernames depending on how you'd like to structure your User model.
 [] You should implement error handling for all your routes, with proper response statuses.
diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js
new file mode 100644
index 0000000..e69de29
diff --git a/routes/userRoutes.js b/routes/userRoutes.js
new file mode 100644
index 0000000..e69de29
diff --git a/server.js b/server.js
index a500ac9..5640165 100644
--- a/server.js
+++ b/server.js
@@ -6,6 +6,7 @@ import listEndpoints from "express-list-endpoints"
 import mongoose from "mongoose"
 
 import data from "./data.json"
+import { authenticateUser } from "./middleware/authMiddleware"
 import { Thought } from "./models/thought"
 import { User } from "./models/user"
 import { postUser } from "./utils/postUser"
@@ -27,16 +28,16 @@ const app = express()
 app.use(cors())
 app.use(express.json())
 
-//Middleware function
-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})
-  }
-}
+// //Middleware function
+// 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})
+//   }
+// }
 
 // const thoughtSchema = new mongoose.Schema({
 //   message: {
@@ -234,7 +235,7 @@ app.get("/documentation", (req, res) => {
 })
 
 //POST
-app.post("/thoughts", async(req, res) => {
+app.post("/thoughts", authenticateUser, async(req, res) => {
   const { message } = req.body
 
   try {
@@ -242,7 +243,7 @@ app.post("/thoughts", async(req, res) => {
 
     res.status(201).json({ response: newThought })
 
-  } catch (error) {
+  } catch (error) {    
     res.status(500).json({ error: "Thought could not be created"})
   }
 })
@@ -272,7 +273,7 @@ app.post("/thoughts/:id/like", async (req, res) => {
 
 
 //DELETE
-app.delete("/thoughts/:id", async(req, res) => {
+app.delete("/thoughts/:id", authenticateUser, async(req, res) => {
   const { id } = req.params
 
   try{
@@ -289,7 +290,7 @@ app.delete("/thoughts/:id", async(req, res) => {
 
 //PATCH
 //Endpoint /thoughts/:id, json body {"newThoughtMessage": "edited message"}
-app.patch("/thoughts/:id", async(req, res) => {
+app.patch("/thoughts/:id", authenticateUser, async(req, res) => {
   const { id } = req.params
   const { newThoughtMessage } = req.body
 
@@ -337,6 +338,7 @@ app.post("/users", postUser)
 
 app.get("/secrets", authenticateUser)
 
+//Signin endpoint
 app.post("/sessions", async (req, res) => {
   const user = await User.findOne({email: req.body.email})
 
diff --git a/utils/postUser.js b/utils/postUser.js
index 1033609..e47c226 100644
--- a/utils/postUser.js
+++ b/utils/postUser.js
@@ -39,9 +39,18 @@ export const postUser = async (req, res) => {
     const salt = bcrypt.genSaltSync()
     const user = new User({email, password: bcrypt.hashSync(password, salt)})
     user.save()
-    res.status(200).json({userId:user._id, accessToken: user.accessToken})
+    res.status(200).json({
+      success: true,
+      response: email,
+      userId:user._id, 
+      accessToken: user.accessToken
+
+    })
   } catch(error){
-    res.status(400).json({message: "Could not create user", errors: error.errors})
+    res.status(400).json({
+      message: "Could not create user", 
+      errors: error.errors
+    })
   }  
 }
 

From 09dd7fd05788ec72d29e8bf0ac8110212d3367c7 Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Sun, 15 Jun 2025 23:09:44 +0200
Subject: [PATCH 24/34] Made som cleaning of unused code.

---
 models/user.js    | 34 ----------------------------------
 server.js         | 29 -----------------------------
 utils/postUser.js | 29 -----------------------------
 3 files changed, 92 deletions(-)

diff --git a/models/user.js b/models/user.js
index e477fef..07d4d94 100644
--- a/models/user.js
+++ b/models/user.js
@@ -28,37 +28,3 @@ const userSchema = new mongoose.Schema({
 
 export const User = mongoose.model("User", userSchema)
 
-// //Middleware function
-// 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})
-//   }
-// }
-
-// app.get("/users", async (req, res) => {
-//   try{
-//     const { email, password } = req.body
-//     const salt = bcrypt.genSaltSync()
-//     const user = new User({email, password: bcrypt.hashSync(password, salt)})
-//     user.save()
-//     res.status(200).json({userId:user._id, accessToken: user.accessToken})
-//   } catch(error){
-//     res.status(400).json({message: "Could not create user", errors: error.errors})
-//   }  
-// })
-
-// app.get("/secrets", authenticateUser)
-
-// 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, accessToken: user.accessToken})
-//   } else {
-//     res.json({notFound: true})
-//   }
-// })
\ No newline at end of file
diff --git a/server.js b/server.js
index 5640165..32cc3fa 100644
--- a/server.js
+++ b/server.js
@@ -28,35 +28,6 @@ const app = express()
 app.use(cors())
 app.use(express.json())
 
-// //Middleware function
-// 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})
-//   }
-// }
-
-// const thoughtSchema = new mongoose.Schema({
-//   message: {
-//     type: String,
-//     required: true,
-//     minlength: 5
-//   },
-//   hearts: {
-//     type: Number,
-//     default: 0
-//   },
-//   createdAt: {
-//     type: Date,
-//     default: Date.now
-//   }
-// })
-
-// const Thought = mongoose.model("Thought", thoughtSchema)
-
 //RESET_DB=true npm run dev. DElete when not needed anymore.
 // if(process.env.RESET_DB){
 //   const seedDatabase = async () => {
diff --git a/utils/postUser.js b/utils/postUser.js
index e47c226..ad12448 100644
--- a/utils/postUser.js
+++ b/utils/postUser.js
@@ -3,35 +3,6 @@ import { response } from "express";
 
 import { User } from "../models/user";
 
-// export const postUser async (req, res) => {
-//   try{
-//     const {email, password} = req.body
-//     const salt = bcrypt.genSaltSync()
-
-//     const user = new User({ email, password: bcrypt.hashSync(password, salt) })
-//     await user.save()
-
-//     res.status(200).json({
-//       success: true,
-//       message: "User created succesfully",
-//       response: {
-//         id: user._id,
-//         accessToken: user.accessToken
-//       }
-
-//     })
-
-//   } catch (error) {
-//     res.status(400).json({
-//       success: false,
-//       message: "Failed to create user",
-//       response: error
-//     })
-//   }
-// }
-
-
-
 //app.get("/users", async (req, res) => 
 export const postUser = async (req, res) => {
   try{

From fac38d2c4ce79ec19d2f2c66523091ca5f0e86c0 Mon Sep 17 00:00:00 2001
From: solen80a 
Date: Mon, 16 Jun 2025 09:09:19 +0200
Subject: [PATCH 25/34] Added to include user for edit, delete, post/get
 thought.

---
 models/thought.js |   5 ++
 server.js         | 117 +++++++---------------------------------------
 2 files changed, 22 insertions(+), 100 deletions(-)

diff --git a/models/thought.js b/models/thought.js
index 0e68ddd..9511edf 100644
--- a/models/thought.js
+++ b/models/thought.js
@@ -13,6 +13,11 @@ const thoughtSchema = new mongoose.Schema({
   createdAt: {
     type: Date,
     default: Date.now
+  },
+  user: {
+    type: mongoose.Schema.Types.ObjectId,
+    ref: "User",
+    required: true
   }
 })
 
diff --git a/server.js b/server.js
index 32cc3fa..42907c2 100644
--- a/server.js
+++ b/server.js
@@ -78,7 +78,9 @@ app.get("/thoughts", async(req, res) => {
   }
     
   try{
-    const filteredThoughts = await Thought.find(query).sort({createdAt: "desc"}) 
+    const filteredThoughts = await Thought.find(query)
+      .sort({ createdAt: "desc" })
+      .populate("user", "_id") 
 
     if (filteredThoughts.length === 0){
       return res.status(404).json({ error: "There are no thoughts to show" })       
@@ -107,110 +109,15 @@ app.get("/thoughts/:id", async (req, res) => {
  
 })
 
-
-//Nicer documentation including queries
-app.get("/documentation", (req, res) => {
-  res.send(`
-    
-      
-        Happy Thoughts API
-             
-      
-      
-        

Welcome to Happy Thoughts API

- -

This is the documentation of Happy thoughts API.

-
-

Endpoints:

-

GET /thoughts

-

Returns a list of all happy thoughts.

-

Response:

-

-        [
-          {
-             "_id": "682c6f0e951f7a0017130022",
-            "message": "Cute monkeys🐒",
-            "hearts": 2,
-            "createdAt": "2025-05-20T12:01:18.308Z",
-            "__v": 0
-          },
-          ...
-        ]
-        
-

GET /thoughts?liked

-

Returns a list of all happy thoughts with likes, >0.

-

Response:

-

-        [
-          {
-             "_id": "682c6f0e951f7a0017130022",
-            "message": "Cute monkeys🐒",
-            "hearts": 2,
-            "createdAt": "2025-05-20T12:01:18.308Z",
-            "__v": 0
-          },
-          ...
-        ]
-        
-

GET /thoughts?messagesfromtoday

-

Returns a list of all happy thoughts from today .

-

Response:

-

-        [
-          {
-             "_id": "682c6f0e951f7a0017130022",
-            "message": "Cute monkeys🐒",
-            "hearts": 2,
-            "createdAt": "2025-05-20T12:01:18.308Z",
-            "__v": 0
-          },
-          ...
-        ]
-        
-

GET /thoughts/:id

-

Returns a specific happy thought by id.

-

Response:

-

-        [
-          {
-             "_id": "682c6f0e951f7a0017130022",
-            "message": "Cute monkeys🐒",
-            "hearts": 2,
-            "createdAt": "2025-05-20T12:01:18.308Z",
-            "__v": 0
-          }
-        ]        
-        
- - - - `) -}) - //POST app.post("/thoughts", authenticateUser, async(req, res) => { const { message } = req.body try { - const newThought = await new Thought({ message }).save() + const newThought = await new Thought({ + message, + user: req.user._id + }).save() res.status(201).json({ response: newThought }) @@ -253,6 +160,12 @@ app.delete("/thoughts/:id", authenticateUser, async(req, res) => { if (!thought) { return res.status(404).json({ error: "Thought id was not found, could not deleted" }) } + + if(!thought.user.equals(req.user._id)){ + return res.status(403).json({ error: "Not authorized to delete this thought" }) + } + + await thought.deleteOne() res.status(200).json({message: `Thought with message: ${thought.message}, was deleted`}) } catch (error) { res.status(500).json({ error: "Failed to fetch thoughts"}) @@ -271,6 +184,10 @@ app.patch("/thoughts/:id", authenticateUser, async(req, res) => { if(!thought){ return res.status(404).json({ error: "Thought id was not found, could not update" }) } + + if(!thought.user.equals(req.user._id)) { + return res.status(403).json({ error: "Not authorized to edit this thought" }) + } res.status(200).json({ message: `Thought was updated to: ${newThoughtMessage}`}) } catch (error) { From 427b13b3ad0971ae4bee52eea7c26792f008e1fc Mon Sep 17 00:00:00 2001 From: solen80a Date: Mon, 16 Jun 2025 09:54:43 +0200 Subject: [PATCH 26/34] More fixes to POST thought to identified user. --- server.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server.js b/server.js index 42907c2..c752350 100644 --- a/server.js +++ b/server.js @@ -111,6 +111,10 @@ app.get("/thoughts/:id", async (req, res) => { //POST app.post("/thoughts", authenticateUser, async(req, res) => { + if(!req.user) { + return res.status(403).json({ error: "You must be logged in to post" }) + } + const { message } = req.body try { From e9039050fcbc263a5b6263c26944313cfffbea3a Mon Sep 17 00:00:00 2001 From: solen80a Date: Mon, 16 Jun 2025 11:02:07 +0200 Subject: [PATCH 27/34] More authentication fixes. --- server.js | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/server.js b/server.js index c752350..6fbd7ca 100644 --- a/server.js +++ b/server.js @@ -111,16 +111,20 @@ app.get("/thoughts/:id", async (req, res) => { //POST app.post("/thoughts", authenticateUser, async(req, res) => { - if(!req.user) { - return res.status(403).json({ error: "You must be logged in to post" }) + const { message } = req.body + + if (!message) { + return res.status(400).json({ error: "Message is required" }); } - const { message } = req.body + if(!req.user) { + return res.status(403).json({ error: "You must be logged in to post" }) + } try { const newThought = await new Thought({ message, - user: req.user._id + userId: req.user._id }).save() res.status(201).json({ response: newThought }) @@ -159,7 +163,8 @@ app.delete("/thoughts/:id", authenticateUser, async(req, res) => { const { id } = req.params try{ - const thought = await Thought.findByIdAndDelete(id) + //const thought = await Thought.findByIdAndDelete(id) + const thought = await Thought.findById(id); if (!thought) { return res.status(404).json({ error: "Thought id was not found, could not deleted" }) @@ -183,7 +188,8 @@ app.patch("/thoughts/:id", authenticateUser, async(req, res) => { const { newThoughtMessage } = req.body try{ - const thought = await Thought.findByIdAndUpdate(id, { message: newThoughtMessage }, { new: true , runValidators: true }) + //const thought = await Thought.findByIdAndUpdate(id, { message: newThoughtMessage }, { new: true , runValidators: true }) + const thought = await Thought.findById(id); if(!thought){ return res.status(404).json({ error: "Thought id was not found, could not update" }) @@ -192,6 +198,10 @@ app.patch("/thoughts/:id", authenticateUser, async(req, res) => { if(!thought.user.equals(req.user._id)) { return res.status(403).json({ error: "Not authorized to edit this thought" }) } + + thought.message = newThoughtMessage; + await thought.save(); + res.status(200).json({ message: `Thought was updated to: ${newThoughtMessage}`}) } catch (error) { @@ -228,16 +238,18 @@ app.get("/users", async (req, res) => { app.post("/users", postUser) -app.get("/secrets", authenticateUser) +app.get("/secrets", authenticateUser, (req, res) => { + res.status(200).json({ message: "This is a protected route", user: req.user }) +}) //Signin endpoint 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, accessToken: user.accessToken}) + res.status(200).json({userId: user._id, accessToken: user.accessToken}) } else { - res.json({notFound: true}) + res.status(401).json({ error: "Invalid email or password"}) } }) From e71a4fd70e03461fb967522a2d98791991687f6b Mon Sep 17 00:00:00 2001 From: solen80a Date: Mon, 16 Jun 2025 11:32:53 +0200 Subject: [PATCH 28/34] more fixes --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index 6fbd7ca..f779d50 100644 --- a/server.js +++ b/server.js @@ -124,7 +124,7 @@ app.post("/thoughts", authenticateUser, async(req, res) => { try { const newThought = await new Thought({ message, - userId: req.user._id + user: req.user._id }).save() res.status(201).json({ response: newThought }) From cfeda6d563b33445fa20c15d1429ad89dc82e246 Mon Sep 17 00:00:00 2001 From: solen80a Date: Mon, 16 Jun 2025 13:45:01 +0200 Subject: [PATCH 29/34] Cleaning and checking tasks. --- notes.md | 32 ++++++++++++++++---------------- server.js | 2 +- utils/postUser.js | 1 - 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/notes.md b/notes.md index d833f59..3339ee5 100644 --- a/notes.md +++ b/notes.md @@ -21,18 +21,18 @@ W2: [x] Frontend posibility to POST (to your API) W3: -[] Signup and Login existing Happy Thoughts -[] Your API should have routes to register and log in -[] Your endpoints to Create, Update and Delete should be authenticated +[x] Signup and Login existing Happy Thoughts +[x] Your API should have routes to register and log in +[x] Your endpoints to Create, Update and Delete should be authenticated [x] Your frontend should have a registration form which POSTs to the API to create a new user. -[] Your frontend should have a login form to authenticate the user. +[x] Your frontend should have a login form to authenticate the user. [x] Your passwords in the database should be encrypted with bcrypt. -[] You should implement error handling. Your API should let the user know if something went wrong. Be as specific as possible to help the user, e.g. by validating the user input when creating a new user, and return "That email address already exists". Include correct status codes. Error messages should also be shown on the frontend. +[x] You should implement error handling. Your API should let the user know if something went wrong. Be as specific as possible to help the user, e.g. by validating the user input when creating a new user, and return "That email address already exists". Include correct status codes. Error messages should also be shown on the frontend. [x] The validation should ensure unique email addresses and/or usernames, depending on how you'd like to structure your User model. Requirements: -[] Your API must have at least the following routes. Try to push yourself to do more, though! Endpoints for: +[x] Your API must have at least the following routes. Try to push yourself to do more, though! Endpoints for: [x] Documentation of your API using e.g. Express List Endpoints [x] Reading thoughts [x] Reading a single thought @@ -40,18 +40,18 @@ Requirements: [x] Creating a thought (authenticated) [x] Updating a thought (authenticated) [x] Deleting a thought (authenticated) - [] Signing up - [] Logging in + [x] Signing up + [x] Logging in [x] Your API should be RESTful -[] You should follow the guidelines on how to write clean code +[x] You should follow the guidelines on how to write clean code [x] Your API should use Mongoose models to model your data and use these models to fetch data from the database. -[] Your API should validate user input and return appropriate errors if the input is invalid. -[] The validation should ensure unique email addresses and/or usernames depending on how you'd like to structure your User model. -[] You should implement error handling for all your routes, with proper response statuses. -[] Your frontend should be updated with the possibility to Update and Delete a thought, as well as signing up and logging in and some error handling if something goes wrong. -[] Your passwords in the database should be encrypted with bcrypt. -[] Your API should be deployed to Render or similar. -[] Everything in your backend should be reflected in your frontend. +[x] Your API should validate user input and return appropriate errors if the input is invalid. +[x] The validation should ensure unique email addresses and/or usernames depending on how you'd like to structure your User model. +[x] You should implement error handling for all your routes, with proper response statuses. +[x] Your frontend should be updated with the possibility to Update and Delete a thought, as well as signing up and logging in and some error handling if something goes wrong. +[x] Your passwords in the database should be encrypted with bcrypt. +[x] Your API should be deployed to Render or similar. +[x] Everything in your backend should be reflected in your frontend. Stretch goal options: [] Allow anonymous (not-logged-in) users to post thoughts diff --git a/server.js b/server.js index f779d50..75966b5 100644 --- a/server.js +++ b/server.js @@ -163,7 +163,7 @@ app.delete("/thoughts/:id", authenticateUser, async(req, res) => { const { id } = req.params try{ - //const thought = await Thought.findByIdAndDelete(id) + const thought = await Thought.findById(id); if (!thought) { diff --git a/utils/postUser.js b/utils/postUser.js index ad12448..5b5ba15 100644 --- a/utils/postUser.js +++ b/utils/postUser.js @@ -1,5 +1,4 @@ import bcrypt from "bcrypt" -import { response } from "express"; import { User } from "../models/user"; From 5097a6d255c16aef19324a12956636b75329780e Mon Sep 17 00:00:00 2001 From: solen80a Date: Tue, 17 Jun 2025 08:46:09 +0200 Subject: [PATCH 30/34] Update deployed frontend and backend. --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 0f9f073..86b25e6 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,6 @@ Install dependencies with `npm install`, then start the server by running `npm r ## View it live Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. +https://happy-thoughts-happy-mind.netlify.app/ +https://js-project-api-afon.onrender.com/ + From e25664bed3faa166febc0f7fbf43dbc599121c55 Mon Sep 17 00:00:00 2001 From: solen80a Date: Wed, 3 Sep 2025 09:41:50 +0200 Subject: [PATCH 31/34] Fixed user already exist error handling. --- server.js | 4 ++-- utils/postUser.js | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 75966b5..bf09a06 100644 --- a/server.js +++ b/server.js @@ -247,9 +247,9 @@ 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.status(200).json({userId: user._id, accessToken: user.accessToken}) + res.status(200).json({success: true, userId: user._id, accessToken: user.accessToken}) } else { - res.status(401).json({ error: "Invalid email or password"}) + res.status(401).json({ success: false, error: "Invalid email or password"}) } }) diff --git a/utils/postUser.js b/utils/postUser.js index 5b5ba15..a1d94e4 100644 --- a/utils/postUser.js +++ b/utils/postUser.js @@ -6,6 +6,16 @@ import { User } from "../models/user"; export const postUser = async (req, res) => { try{ const { email, password } = req.body + + // Check if user already exists + const existingUser = await User.findOne({ email }); + if (existingUser) { + return res.status(400).json({ + success: false, + message: "User already exists" + }); + } + const salt = bcrypt.genSaltSync() const user = new User({email, password: bcrypt.hashSync(password, salt)}) user.save() From 21f3752d8b146b75d76d75fad24230e1d3bbd98f Mon Sep 17 00:00:00 2001 From: solen80a Date: Wed, 3 Sep 2025 14:43:38 +0200 Subject: [PATCH 32/34] Removed unused code. Added maxlength to message. Added await to the user save. --- models/thought.js | 3 ++- server.js | 13 +------------ utils/postUser.js | 2 +- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/models/thought.js b/models/thought.js index 9511edf..56548a6 100644 --- a/models/thought.js +++ b/models/thought.js @@ -4,7 +4,8 @@ const thoughtSchema = new mongoose.Schema({ message: { type: String, required: true, - minlength: 5 + minlength: 5, + maxlength: 140 }, hearts: { type: Number, diff --git a/server.js b/server.js index bf09a06..bbaab65 100644 --- a/server.js +++ b/server.js @@ -28,17 +28,6 @@ const app = express() app.use(cors()) app.use(express.json()) -//RESET_DB=true npm run dev. DElete when not needed anymore. -// if(process.env.RESET_DB){ -// const seedDatabase = async () => { -// await Thought.deleteMany({}) -// data.forEach(thought => { -// new Thought(thought).save() -// }) -// } -// seedDatabase() -// } - //GET // Start defining your routes here // Endpoints with listEndpoints @@ -188,7 +177,7 @@ app.patch("/thoughts/:id", authenticateUser, async(req, res) => { const { newThoughtMessage } = req.body try{ - //const thought = await Thought.findByIdAndUpdate(id, { message: newThoughtMessage }, { new: true , runValidators: true }) + const thought = await Thought.findById(id); if(!thought){ diff --git a/utils/postUser.js b/utils/postUser.js index a1d94e4..6b5bd6d 100644 --- a/utils/postUser.js +++ b/utils/postUser.js @@ -18,7 +18,7 @@ export const postUser = async (req, res) => { const salt = bcrypt.genSaltSync() const user = new User({email, password: bcrypt.hashSync(password, salt)}) - user.save() + await user.save() res.status(200).json({ success: true, response: email, From 55b2a19d5dbbd6bec3ba394eaaeaa67355e5705a Mon Sep 17 00:00:00 2001 From: solen80a Date: Wed, 3 Sep 2025 16:10:05 +0200 Subject: [PATCH 33/34] Added check for password length. --- utils/postUser.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/utils/postUser.js b/utils/postUser.js index 6b5bd6d..c26c56a 100644 --- a/utils/postUser.js +++ b/utils/postUser.js @@ -16,6 +16,13 @@ export const postUser = async (req, res) => { }); } + if (password.length < 3) { + return res.status(400).json({ + success: false, + message: "Password must be at least 3 characters long" + }); + } + const salt = bcrypt.genSaltSync() const user = new User({email, password: bcrypt.hashSync(password, salt)}) await user.save() From ccdc4ef4e2ec9c8d4db3a6bb9f083b79d88d2737 Mon Sep 17 00:00:00 2001 From: solen80a Date: Thu, 4 Sep 2025 10:22:06 +0200 Subject: [PATCH 34/34] removed empty files. --- routes/thoughtRoutes.js | 0 routes/userRoutes.js | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 routes/thoughtRoutes.js delete mode 100644 routes/userRoutes.js diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js deleted file mode 100644 index e69de29..0000000 diff --git a/routes/userRoutes.js b/routes/userRoutes.js deleted file mode 100644 index e69de29..0000000