From 07c45743e8436857f05fa531ef0e9eada188af24 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Tue, 29 Jul 2025 15:39:19 +0200 Subject: [PATCH 01/58] added dependencies, imports and js code --- data.json | 121 ---------------- data/flowers.json | 362 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 + server.js | 53 ++++++- 4 files changed, 413 insertions(+), 125 deletions(-) delete mode 100644 data.json create mode 100644 data/flowers.json diff --git a/data.json b/data.json deleted file mode 100644 index a2c844f..0000000 --- a/data.json +++ /dev/null @@ -1,121 +0,0 @@ -[ - { - "_id": "682bab8c12155b00101732ce", - "message": "Berlin baby", - "hearts": 37, - "createdAt": "2025-05-19T22:07:08.999Z", - "__v": 0 - }, - { - "_id": "682e53cc4fddf50010bbe739", - "message": "My family!", - "hearts": 0, - "createdAt": "2025-05-22T22:29:32.232Z", - "__v": 0 - }, - { - "_id": "682e4f844fddf50010bbe738", - "message": "The smell of coffee in the morning....", - "hearts": 23, - "createdAt": "2025-05-22T22:11:16.075Z", - "__v": 0 - }, - { - "_id": "682e48bf4fddf50010bbe737", - "message": "Newly washed bedlinen, kids that sleeps through the night.. FINGERS CROSSED 🤞🏼\n", - "hearts": 6, - "createdAt": "2025-05-21T21:42:23.862Z", - "__v": 0 - }, - { - "_id": "682e45804fddf50010bbe736", - "message": "I am happy that I feel healthy and have energy again", - "hearts": 13, - "createdAt": "2025-05-21T21:28:32.196Z", - "__v": 0 - }, - { - "_id": "682e23fecf615800105107aa", - "message": "cold beer", - "hearts": 2, - "createdAt": "2025-05-21T19:05:34.113Z", - "__v": 0 - }, - { - "_id": "682e22aecf615800105107a9", - "message": "My friend is visiting this weekend! <3", - "hearts": 6, - "createdAt": "2025-05-21T18:59:58.121Z", - "__v": 0 - }, - { - "_id": "682cec1b17487d0010a298b6", - "message": "A god joke: \nWhy did the scarecrow win an award?\nBecause he was outstanding in his field!", - "hearts": 12, - "createdAt": "2025-05-20T20:54:51.082Z", - "__v": 0 - }, - { - "_id": "682cebbe17487d0010a298b5", - "message": "Tacos and tequila🌮🍹", - "hearts": 2, - "createdAt": "2025-05-19T20:53:18.899Z", - "__v": 0 - }, - { - "_id": "682ceb5617487d0010a298b4", - "message": "Netflix and late night ice-cream🍦", - "hearts": 1, - "createdAt": "2025-05-18T20:51:34.494Z", - "__v": 0 - }, - { - "_id": "682c99ba3bff2d0010f5d44e", - "message": "Summer is coming...", - "hearts": 2, - "createdAt": "2025-05-20T15:03:22.379Z", - "__v": 0 - }, - { - "_id": "682c706c951f7a0017130024", - "message": "Exercise? I thought you said extra fries! 🍟😂", - "hearts": 14, - "createdAt": "2025-05-20T12:07:08.185Z", - "__v": 0 - }, - { - "_id": "682c6fe1951f7a0017130023", - "message": "I’m on a seafood diet. I see food, and I eat it.", - "hearts": 4, - "createdAt": "2025-05-20T12:04:49.978Z", - "__v": 0 - }, - { - "_id": "682c6f0e951f7a0017130022", - "message": "Cute monkeys🐒", - "hearts": 2, - "createdAt": "2025-05-20T12:01:18.308Z", - "__v": 0 - }, - { - "_id": "682c6e65951f7a0017130021", - "message": "The weather is nice!", - "hearts": 0, - "createdAt": "2025-05-20T11:58:29.662Z", - "__v": 0 - }, - { - "_id": "682bfdb4270ca300105af221", - "message": "good vibes and good things", - "hearts": 3, - "createdAt": "2025-05-20T03:57:40.322Z", - "__v": 0 - }, - { - "_id": "682bab8c12155b00101732ce", - "message": "Berlin baby", - "hearts": 37, - "createdAt": "2025-05-19T22:07:08.999Z", - "__v": 0 - } -] \ No newline at end of file diff --git a/data/flowers.json b/data/flowers.json new file mode 100644 index 0000000..781c2db --- /dev/null +++ b/data/flowers.json @@ -0,0 +1,362 @@ +[ + { + "id": 1, + "name": "Rose", + "scientificName": "Rosa rubiginosa", + "botanicalFamily": "Rosaceae", + "color": "Red", + "isSpotted": true, + "scent": "Sweet", + "size": "Medium", + "symbolism": ["Love", "Passion", "Beauty"], + "lastSpottedTimestamp": "2025-05-26T10:15:00Z" + }, + { + "id": 2, + "name": "Tulip", + "scientificName": "Tulipa gesneriana", + "botanicalFamily": "Liliaceae", + "color": "Yellow", + "isSpotted": false, + "scent": "Mild", + "size": "Medium", + "symbolism": ["Perfect Love", "Fame", "Declaration of Love"], + "lastSpottedTimestamp": null + }, + { + "id": 3, + "name": "Daisy", + "scientificName": "Bellis perennis", + "botanicalFamily": "Asteraceae", + "color": "White", + "isSpotted": true, + "scent": "Slightly Sweet", + "size": "Small", + "symbolism": ["Innocence", "Purity", "New Beginnings"], + "lastSpottedTimestamp": "2025-05-25T14:30:00Z" + }, + { + "id": 4, + "name": "Sunflower", + "scientificName": "Helianthus annuus", + "botanicalFamily": "Asteraceae", + "color": "Yellow", + "isSpotted": true, + "scent": "Earthy", + "size": "Large", + "symbolism": ["Adoration", "Loyalty", "Longevity"], + "lastSpottedTimestamp": "2025-05-26T18:00:00Z" + }, + { + "id": 5, + "name": "Lily", + "scientificName": "Lilium candidum", + "botanicalFamily": "Liliaceae", + "color": "White", + "isSpotted": false, + "scent": "Strongly Sweet", + "size": "Large", + "symbolism": ["Purity", "Majesty", "Wealth"], + "lastSpottedTimestamp": null + }, + { + "id": 6, + "name": "Orchid", + "scientificName": "Phalaenopsis amabilis", + "botanicalFamily": "Orchidaceae", + "color": "Purple", + "isSpotted": true, + "scent": "Delicate", + "size": "Medium", + "symbolism": ["Luxury", "Beauty", "Strength", "Love"], + "lastSpottedTimestamp": "2025-05-24T11:00:00Z" + }, + { + "id": 7, + "name": "Carnation", + "scientificName": "Dianthus caryophyllus", + "botanicalFamily": "Caryophyllaceae", + "color": "Pink", + "isSpotted": false, + "scent": "Spicy", + "size": "Medium", + "symbolism": ["Love (general)", "Fascination", "Distinction"], + "lastSpottedTimestamp": null + }, + { + "id": 8, + "name": "Daffodil", + "scientificName": "Narcissus pseudonarcissus", + "botanicalFamily": "Amaryllidaceae", + "color": "Yellow", + "isSpotted": true, + "scent": "Sweet", + "size": "Medium", + "symbolism": ["Rebirth", "New Beginnings", "Unrequited Love"], + "lastSpottedTimestamp": "2025-05-23T09:45:00Z" + }, + { + "id": 9, + "name": "Peony", + "scientificName": "Paeonia lactiflora", + "botanicalFamily": "Paeoniaceae", + "color": "Pink", + "isSpotted": true, + "scent": "Rosy", + "size": "Large", + "symbolism": ["Romance", "Prosperity", "Good Fortune", "Honor"], + "lastSpottedTimestamp": "2025-05-26T12:00:00Z" + }, + { + "id": 10, + "name": "Marigold", + "scientificName": "Tagetes erecta", + "botanicalFamily": "Asteraceae", + "color": "Orange", + "isSpotted": false, + "scent": "Pungent", + "size": "Medium", + "symbolism": ["Despair (historically)", "Grief", "Creativity", "Passion"], + "lastSpottedTimestamp": null + }, + { + "id": 11, + "name": "Lavender", + "scientificName": "Lavandula angustifolia", + "botanicalFamily": "Lamiaceae", + "color": "Purple", + "isSpotted": true, + "scent": "Sweet", + "size": "Medium", + "symbolism": ["Purity", "Silence", "Devotion", "Calmness"], + "lastSpottedTimestamp": "2025-05-25T08:30:00Z" + }, + { + "id": 12, + "name": "Poppy", + "scientificName": "Papaver rhoeas", + "botanicalFamily": "Papaveraceae", + "color": "Red", + "isSpotted": true, + "scent": "Slight", + "size": "Medium", + "symbolism": ["Remembrance", "Sleep", "Peace"], + "lastSpottedTimestamp": "2025-05-22T17:00:00Z" + }, + { + "id": 13, + "name": "Iris", + "scientificName": "Iris germanica", + "botanicalFamily": "Iridaceae", + "color": "Blue", + "isSpotted": false, + "scent": "Grape-like", + "size": "Large", + "symbolism": ["Faith", "Hope", "Wisdom", "Valor"], + "lastSpottedTimestamp": null + }, + { + "id": 14, + "name": "Snapdragon", + "scientificName": "Antirrhinum majus", + "botanicalFamily": "Plantaginaceae", + "color": "Pink", + "isSpotted": true, + "scent": "Mildly Sweet", + "size": "Medium", + "symbolism": ["Graciousness", "Strength", "Deception"], + "lastSpottedTimestamp": "2025-05-26T09:00:00Z" + }, + { + "id": 15, + "name": "Zinnia", + "scientificName": "Zinnia elegans", + "botanicalFamily": "Asteraceae", + "color": "Orange", + "isSpotted": true, + "scent": "None", + "size": "Medium", + "symbolism": ["Thoughts of friends", "Endurance", "Lasting affection"], + "lastSpottedTimestamp": "2025-05-24T16:20:00Z" + }, + { + "id": 16, + "name": "Chrysanthemum", + "scientificName": "Chrysanthemum morifolium", + "botanicalFamily": "Asteraceae", + "color": "Yellow", + "isSpotted": false, + "scent": "Earthy", + "size": "Medium", + "symbolism": ["Joy", "Optimism", "Longevity"], + "lastSpottedTimestamp": null + }, + { + "id": 17, + "name": "Geranium", + "scientificName": "Pelargonium hortorum", + "botanicalFamily": "Geraniaceae", + "color": "Red", + "isSpotted": true, + "scent": "Varied", + "size": "Medium", + "symbolism": ["Comfort", "Gentility"], + "lastSpottedTimestamp": "2025-05-26T11:00:00Z" + }, + { + "id": 18, + "name": "Begonia", + "scientificName": "Begonia semperflorens", + "botanicalFamily": "Begoniaceae", + "color": "Pink", + "isSpotted": false, + "scent": "None", + "size": "Small", + "symbolism": ["Beware", "Dark thoughts", "Gratitude"], + "lastSpottedTimestamp": null + }, + { + "id": 19, + "name": "Petunia", + "scientificName": "Petunia x hybrida", + "botanicalFamily": "Solanaceae", + "color": "Purple", + "isSpotted": true, + "scent": "Sweet", + "size": "Small", + "symbolism": ["Resentment", "Anger", "Your presence soothes me"], + "lastSpottedTimestamp": "2025-05-25T21:00:00Z" + }, + { + "id": 20, + "name": "Pansy", + "scientificName": "Viola tricolor var. hortensis", + "botanicalFamily": "Violaceae", + "color": "Yellow", + "isSpotted": true, + "scent": "Delicate", + "size": "Small", + "symbolism": ["Loving thoughts", "Remembrance", "Free-thinking"], + "lastSpottedTimestamp": "2025-05-26T15:10:00Z" + }, + { + "id": 21, + "name": "Forget-Me-Not", + "scientificName": "Myosotis sylvatica", + "botanicalFamily": "Boraginaceae", + "color": "Blue", + "isSpotted": true, + "scent": "None", + "size": "Small", + "symbolism": ["True love", "Remembrance", "Faithfulness"], + "lastSpottedTimestamp": "2025-05-23T10:00:00Z" + }, + { + "id": 22, + "name": "Bluebell", + "scientificName": "Hyacinthoides non-scripta", + "botanicalFamily": "Asparagaceae", + "color": "Blue-Violet", + "isSpotted": false, + "scent": "Sweet", + "size": "Small", + "symbolism": ["Humility", "Gratitude", "Everlasting love"], + "lastSpottedTimestamp": null + }, + { + "id": 23, + "name": "Crocus", + "scientificName": "Crocus vernus", + "botanicalFamily": "Iridaceae", + "color": "Purple", + "isSpotted": true, + "scent": "Slightly Sweet", + "size": "Small", + "symbolism": ["Youthful gladness", "Cheerfulness"], + "lastSpottedTimestamp": "2025-03-10T12:00:00Z" + }, + { + "id": 24, + "name": "Snowdrop", + "scientificName": "Galanthus nivalis", + "botanicalFamily": "Amaryllidaceae", + "color": "White", + "isSpotted": false, + "scent": "Mildly Sweet", + "size": "Small", + "symbolism": ["Hope", "Purity", "Consolation", "Rebirth"], + "lastSpottedTimestamp": null + }, + { + "id": 25, + "name": "Hibiscus", + "scientificName": "Hibiscus rosa-sinensis", + "botanicalFamily": "Malvaceae", + "color": "Red", + "isSpotted": true, + "scent": "None", + "size": "Large", + "symbolism": ["Delicate beauty", "Consumed by love"], + "lastSpottedTimestamp": "2025-05-20T14:00:00Z" + }, + { + "id": 26, + "name": "Jasmine", + "scientificName": "Jasminum officinale", + "botanicalFamily": "Oleaceae", + "color": "White", + "isSpotted": true, + "scent": "Strongly Sweet", + "size": "Medium", + "symbolism": ["Love", "Beauty", "Sensuality", "Grace"], + "lastSpottedTimestamp": "2025-05-26T20:30:00Z" + }, + { + "id": 27, + "name": "Lilac", + "scientificName": "Syringa vulgaris", + "botanicalFamily": "Oleaceae", + "color": "Purple", + "isSpotted": false, + "scent": "Strongly Sweet", + "size": "Large", + "symbolism": ["First emotions of love", "Innocence", "Confidence"], + "lastSpottedTimestamp": null + }, + { + "id": 28, + "name": "Magnolia", + "scientificName": "Magnolia grandiflora", + "botanicalFamily": "Magnoliaceae", + "color": "White", + "isSpotted": true, + "scent": "Sweet", + "size": "Large", + "symbolism": ["Dignity", "Nobility", "Perseverance"], + "lastSpottedTimestamp": "2025-04-30T11:30:00Z" + }, + { + "id": 29, + "name": "Camellia", + "scientificName": "Camellia japonica", + "botanicalFamily": "Theaceae", + "color": "Pink", + "isSpotted": false, + "scent": "Slight", + "size": "Medium", + "symbolism": ["Admiration", "Perfection", "Faithfulness"], + "lastSpottedTimestamp": null + }, + { + "id": 30, + "name": "Gardenia", + "scientificName": "Gardenia jasminoides", + "botanicalFamily": "Rubiaceae", + "color": "White", + "isSpotted": true, + "scent": "Strongly Sweet", + "size": "Medium", + "symbolism": ["Purity", "Sweet love", "Joy", "You're lovely"], + "lastSpottedTimestamp": "2025-05-22T19:45:00Z" + } +] \ No newline at end of file diff --git a/package.json b/package.json index bf25bb6..70ca4d2 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,9 @@ "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", "cors": "^2.8.5", + "dotenv": "^16.5.0", "express": "^4.17.3", + "express-list-endpoints": "^7.1.1", "nodemon": "^3.0.1" } } diff --git a/server.js b/server.js index f47771b..d045bf0 100644 --- a/server.js +++ b/server.js @@ -1,9 +1,9 @@ import cors from "cors" import express from "express" +import listEndpoints from "express-list-endpoints" + +import flowerData from "./data/flowers.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: -// PORT=9000 npm start const port = process.env.PORT || 8080 const app = express() @@ -13,7 +13,52 @@ app.use(express.json()) // Start defining your routes here app.get("/", (req, res) => { - res.send("Hello Technigo!") +const endpoints = listEndpoints(app) +res.json({ + message: "Welcome to the Flower API", + endpoints: endpoints +}) + +}) + +// endpoint for getting all flowers +app.get ("/flowers", (req, res) => { + const { color, botanicalFamily } = req.query + + let filteredFlowers = flowerData + + if (color) { + filteredFlowers = filteredFlowers.filter(flower => flower.color.toLowerCase() === color.toLowerCase()) + } + + res.json(filteredFlowers) +}) + +/* Checking scent instead of color with ?scent=sweet +app.get ("/flowers", (req, res) => { + const { scent, botanicalFamily } = req.query + + let filteredFlowers = flowerData + + if (scent) { + filteredFlowers = filteredFlowers.filter(flower => flower.scent.toLowerCase() === scent.toLowerCase()) + } + + res.json(filteredFlowers) +}) +*/ + +// endpoint for getting one flower +app.get ("/flowers/:id", (req, res) => { + + const flower = flowerData.find((flower) => flower.id === +req.params.id) + +// tiny error handling if we get an id that doesnt exist in our data + if (!flower) { + return res.status(404).json({ error: "flower not found" }) + } + + res.json(flower) }) // Start the server From ee05b6a0460b2de36c14d1ed2e7e67dc7652d176 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Sun, 3 Aug 2025 11:01:35 +0200 Subject: [PATCH 02/58] added comment --- README.md | 1 + server.js | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0f9f073..3e257bd 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,4 @@ 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. + diff --git a/server.js b/server.js index d045bf0..d382a15 100644 --- a/server.js +++ b/server.js @@ -7,11 +7,11 @@ import flowerData from "./data/flowers.json" const port = process.env.PORT || 8080 const app = express() -// Add middlewares to enable cors and json body parsing +// Add middlewares to enable cors and json body parsing. Middleware is code that runs between the request and the response, it can modify the request, the response, or decide how the server should continue. app.use(cors()) app.use(express.json()) -// Start defining your routes here +// Start defining your routes here. Add documentation of the API here with express-list-endpoints. app.get("/", (req, res) => { const endpoints = listEndpoints(app) res.json({ @@ -21,7 +21,7 @@ res.json({ }) -// endpoint for getting all flowers +// Endpoint for getting all flowers and should be called /flowers. We're using RESTFUL APIs. app.get ("/flowers", (req, res) => { const { color, botanicalFamily } = req.query From 21ba718ba673f7653fd788d374069a3266549358 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 19:23:39 +0200 Subject: [PATCH 03/58] removed flowers data --- data/flowers.json | 362 ---------------------------------------------- 1 file changed, 362 deletions(-) delete mode 100644 data/flowers.json diff --git a/data/flowers.json b/data/flowers.json deleted file mode 100644 index 781c2db..0000000 --- a/data/flowers.json +++ /dev/null @@ -1,362 +0,0 @@ -[ - { - "id": 1, - "name": "Rose", - "scientificName": "Rosa rubiginosa", - "botanicalFamily": "Rosaceae", - "color": "Red", - "isSpotted": true, - "scent": "Sweet", - "size": "Medium", - "symbolism": ["Love", "Passion", "Beauty"], - "lastSpottedTimestamp": "2025-05-26T10:15:00Z" - }, - { - "id": 2, - "name": "Tulip", - "scientificName": "Tulipa gesneriana", - "botanicalFamily": "Liliaceae", - "color": "Yellow", - "isSpotted": false, - "scent": "Mild", - "size": "Medium", - "symbolism": ["Perfect Love", "Fame", "Declaration of Love"], - "lastSpottedTimestamp": null - }, - { - "id": 3, - "name": "Daisy", - "scientificName": "Bellis perennis", - "botanicalFamily": "Asteraceae", - "color": "White", - "isSpotted": true, - "scent": "Slightly Sweet", - "size": "Small", - "symbolism": ["Innocence", "Purity", "New Beginnings"], - "lastSpottedTimestamp": "2025-05-25T14:30:00Z" - }, - { - "id": 4, - "name": "Sunflower", - "scientificName": "Helianthus annuus", - "botanicalFamily": "Asteraceae", - "color": "Yellow", - "isSpotted": true, - "scent": "Earthy", - "size": "Large", - "symbolism": ["Adoration", "Loyalty", "Longevity"], - "lastSpottedTimestamp": "2025-05-26T18:00:00Z" - }, - { - "id": 5, - "name": "Lily", - "scientificName": "Lilium candidum", - "botanicalFamily": "Liliaceae", - "color": "White", - "isSpotted": false, - "scent": "Strongly Sweet", - "size": "Large", - "symbolism": ["Purity", "Majesty", "Wealth"], - "lastSpottedTimestamp": null - }, - { - "id": 6, - "name": "Orchid", - "scientificName": "Phalaenopsis amabilis", - "botanicalFamily": "Orchidaceae", - "color": "Purple", - "isSpotted": true, - "scent": "Delicate", - "size": "Medium", - "symbolism": ["Luxury", "Beauty", "Strength", "Love"], - "lastSpottedTimestamp": "2025-05-24T11:00:00Z" - }, - { - "id": 7, - "name": "Carnation", - "scientificName": "Dianthus caryophyllus", - "botanicalFamily": "Caryophyllaceae", - "color": "Pink", - "isSpotted": false, - "scent": "Spicy", - "size": "Medium", - "symbolism": ["Love (general)", "Fascination", "Distinction"], - "lastSpottedTimestamp": null - }, - { - "id": 8, - "name": "Daffodil", - "scientificName": "Narcissus pseudonarcissus", - "botanicalFamily": "Amaryllidaceae", - "color": "Yellow", - "isSpotted": true, - "scent": "Sweet", - "size": "Medium", - "symbolism": ["Rebirth", "New Beginnings", "Unrequited Love"], - "lastSpottedTimestamp": "2025-05-23T09:45:00Z" - }, - { - "id": 9, - "name": "Peony", - "scientificName": "Paeonia lactiflora", - "botanicalFamily": "Paeoniaceae", - "color": "Pink", - "isSpotted": true, - "scent": "Rosy", - "size": "Large", - "symbolism": ["Romance", "Prosperity", "Good Fortune", "Honor"], - "lastSpottedTimestamp": "2025-05-26T12:00:00Z" - }, - { - "id": 10, - "name": "Marigold", - "scientificName": "Tagetes erecta", - "botanicalFamily": "Asteraceae", - "color": "Orange", - "isSpotted": false, - "scent": "Pungent", - "size": "Medium", - "symbolism": ["Despair (historically)", "Grief", "Creativity", "Passion"], - "lastSpottedTimestamp": null - }, - { - "id": 11, - "name": "Lavender", - "scientificName": "Lavandula angustifolia", - "botanicalFamily": "Lamiaceae", - "color": "Purple", - "isSpotted": true, - "scent": "Sweet", - "size": "Medium", - "symbolism": ["Purity", "Silence", "Devotion", "Calmness"], - "lastSpottedTimestamp": "2025-05-25T08:30:00Z" - }, - { - "id": 12, - "name": "Poppy", - "scientificName": "Papaver rhoeas", - "botanicalFamily": "Papaveraceae", - "color": "Red", - "isSpotted": true, - "scent": "Slight", - "size": "Medium", - "symbolism": ["Remembrance", "Sleep", "Peace"], - "lastSpottedTimestamp": "2025-05-22T17:00:00Z" - }, - { - "id": 13, - "name": "Iris", - "scientificName": "Iris germanica", - "botanicalFamily": "Iridaceae", - "color": "Blue", - "isSpotted": false, - "scent": "Grape-like", - "size": "Large", - "symbolism": ["Faith", "Hope", "Wisdom", "Valor"], - "lastSpottedTimestamp": null - }, - { - "id": 14, - "name": "Snapdragon", - "scientificName": "Antirrhinum majus", - "botanicalFamily": "Plantaginaceae", - "color": "Pink", - "isSpotted": true, - "scent": "Mildly Sweet", - "size": "Medium", - "symbolism": ["Graciousness", "Strength", "Deception"], - "lastSpottedTimestamp": "2025-05-26T09:00:00Z" - }, - { - "id": 15, - "name": "Zinnia", - "scientificName": "Zinnia elegans", - "botanicalFamily": "Asteraceae", - "color": "Orange", - "isSpotted": true, - "scent": "None", - "size": "Medium", - "symbolism": ["Thoughts of friends", "Endurance", "Lasting affection"], - "lastSpottedTimestamp": "2025-05-24T16:20:00Z" - }, - { - "id": 16, - "name": "Chrysanthemum", - "scientificName": "Chrysanthemum morifolium", - "botanicalFamily": "Asteraceae", - "color": "Yellow", - "isSpotted": false, - "scent": "Earthy", - "size": "Medium", - "symbolism": ["Joy", "Optimism", "Longevity"], - "lastSpottedTimestamp": null - }, - { - "id": 17, - "name": "Geranium", - "scientificName": "Pelargonium hortorum", - "botanicalFamily": "Geraniaceae", - "color": "Red", - "isSpotted": true, - "scent": "Varied", - "size": "Medium", - "symbolism": ["Comfort", "Gentility"], - "lastSpottedTimestamp": "2025-05-26T11:00:00Z" - }, - { - "id": 18, - "name": "Begonia", - "scientificName": "Begonia semperflorens", - "botanicalFamily": "Begoniaceae", - "color": "Pink", - "isSpotted": false, - "scent": "None", - "size": "Small", - "symbolism": ["Beware", "Dark thoughts", "Gratitude"], - "lastSpottedTimestamp": null - }, - { - "id": 19, - "name": "Petunia", - "scientificName": "Petunia x hybrida", - "botanicalFamily": "Solanaceae", - "color": "Purple", - "isSpotted": true, - "scent": "Sweet", - "size": "Small", - "symbolism": ["Resentment", "Anger", "Your presence soothes me"], - "lastSpottedTimestamp": "2025-05-25T21:00:00Z" - }, - { - "id": 20, - "name": "Pansy", - "scientificName": "Viola tricolor var. hortensis", - "botanicalFamily": "Violaceae", - "color": "Yellow", - "isSpotted": true, - "scent": "Delicate", - "size": "Small", - "symbolism": ["Loving thoughts", "Remembrance", "Free-thinking"], - "lastSpottedTimestamp": "2025-05-26T15:10:00Z" - }, - { - "id": 21, - "name": "Forget-Me-Not", - "scientificName": "Myosotis sylvatica", - "botanicalFamily": "Boraginaceae", - "color": "Blue", - "isSpotted": true, - "scent": "None", - "size": "Small", - "symbolism": ["True love", "Remembrance", "Faithfulness"], - "lastSpottedTimestamp": "2025-05-23T10:00:00Z" - }, - { - "id": 22, - "name": "Bluebell", - "scientificName": "Hyacinthoides non-scripta", - "botanicalFamily": "Asparagaceae", - "color": "Blue-Violet", - "isSpotted": false, - "scent": "Sweet", - "size": "Small", - "symbolism": ["Humility", "Gratitude", "Everlasting love"], - "lastSpottedTimestamp": null - }, - { - "id": 23, - "name": "Crocus", - "scientificName": "Crocus vernus", - "botanicalFamily": "Iridaceae", - "color": "Purple", - "isSpotted": true, - "scent": "Slightly Sweet", - "size": "Small", - "symbolism": ["Youthful gladness", "Cheerfulness"], - "lastSpottedTimestamp": "2025-03-10T12:00:00Z" - }, - { - "id": 24, - "name": "Snowdrop", - "scientificName": "Galanthus nivalis", - "botanicalFamily": "Amaryllidaceae", - "color": "White", - "isSpotted": false, - "scent": "Mildly Sweet", - "size": "Small", - "symbolism": ["Hope", "Purity", "Consolation", "Rebirth"], - "lastSpottedTimestamp": null - }, - { - "id": 25, - "name": "Hibiscus", - "scientificName": "Hibiscus rosa-sinensis", - "botanicalFamily": "Malvaceae", - "color": "Red", - "isSpotted": true, - "scent": "None", - "size": "Large", - "symbolism": ["Delicate beauty", "Consumed by love"], - "lastSpottedTimestamp": "2025-05-20T14:00:00Z" - }, - { - "id": 26, - "name": "Jasmine", - "scientificName": "Jasminum officinale", - "botanicalFamily": "Oleaceae", - "color": "White", - "isSpotted": true, - "scent": "Strongly Sweet", - "size": "Medium", - "symbolism": ["Love", "Beauty", "Sensuality", "Grace"], - "lastSpottedTimestamp": "2025-05-26T20:30:00Z" - }, - { - "id": 27, - "name": "Lilac", - "scientificName": "Syringa vulgaris", - "botanicalFamily": "Oleaceae", - "color": "Purple", - "isSpotted": false, - "scent": "Strongly Sweet", - "size": "Large", - "symbolism": ["First emotions of love", "Innocence", "Confidence"], - "lastSpottedTimestamp": null - }, - { - "id": 28, - "name": "Magnolia", - "scientificName": "Magnolia grandiflora", - "botanicalFamily": "Magnoliaceae", - "color": "White", - "isSpotted": true, - "scent": "Sweet", - "size": "Large", - "symbolism": ["Dignity", "Nobility", "Perseverance"], - "lastSpottedTimestamp": "2025-04-30T11:30:00Z" - }, - { - "id": 29, - "name": "Camellia", - "scientificName": "Camellia japonica", - "botanicalFamily": "Theaceae", - "color": "Pink", - "isSpotted": false, - "scent": "Slight", - "size": "Medium", - "symbolism": ["Admiration", "Perfection", "Faithfulness"], - "lastSpottedTimestamp": null - }, - { - "id": 30, - "name": "Gardenia", - "scientificName": "Gardenia jasminoides", - "botanicalFamily": "Rubiaceae", - "color": "White", - "isSpotted": true, - "scent": "Strongly Sweet", - "size": "Medium", - "symbolism": ["Purity", "Sweet love", "Joy", "You're lovely"], - "lastSpottedTimestamp": "2025-05-22T19:45:00Z" - } -] \ No newline at end of file From 8dbed5434c6c93ef7eea187147bfe6bec820b73f Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 19:38:11 +0200 Subject: [PATCH 04/58] added type and installed devdependencies --- package.json | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 70ca4d2..ddb2cc9 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "project-api", "version": "1.0.0", "description": "Project API", + "type": "module", "scripts": { "start": "babel-node server.js", "dev": "nodemon server.js --exec babel-node" @@ -9,13 +10,18 @@ "author": "", "license": "ISC", "dependencies": { - "@babel/core": "^7.17.9", - "@babel/node": "^7.16.8", - "@babel/preset-env": "^7.16.11", + "bcrypt": "^6.0.0", "cors": "^2.8.5", "dotenv": "^16.5.0", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", - "nodemon": "^3.0.1" + "jsonwebtoken": "^9.0.2", + "mongoose": "^8.17.0" + }, + "devDependencies": { + "@babel/core": "^7.28.0", + "@babel/node": "^7.28.0", + "@babel/preset-env": "^7.28.0", + "nodemon": "^3.1.10" } } From 508cd8d3eb82ded4abac9ceba80e1f6555995f6c Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 19:43:33 +0200 Subject: [PATCH 05/58] removed flowerdata import --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index d382a15..81b4f09 100644 --- a/server.js +++ b/server.js @@ -2,7 +2,7 @@ import cors from "cors" import express from "express" import listEndpoints from "express-list-endpoints" -import flowerData from "./data/flowers.json" + const port = process.env.PORT || 8080 const app = express() From 1a6ea13c4f9dee7e31582aa79a85003d1504608f Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 19:47:26 +0200 Subject: [PATCH 06/58] added mongoose import and connection to mongo db database --- server.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index 81b4f09..c5af9af 100644 --- a/server.js +++ b/server.js @@ -1,8 +1,11 @@ import cors from "cors" import express from "express" import listEndpoints from "express-list-endpoints" +import mongoose from "mongoose" - +// Connect to Mongo DB database +const mongoURL = process.env.MONGO_URL || "mongodb://localhost/happy-thoughts-api" +mongoose.connect(mongoURL) const port = process.env.PORT || 8080 const app = express() From 1f77e0172abb8ec68bd12ab6d7eeb97cf0369173 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 19:49:12 +0200 Subject: [PATCH 07/58] addded gotenv import and config --- server.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server.js b/server.js index c5af9af..cb5d4da 100644 --- a/server.js +++ b/server.js @@ -2,6 +2,9 @@ import cors from "cors" import express from "express" import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" +import dotenv from "dotenv" + +dotenv.config() // Connect to Mongo DB database const mongoURL = process.env.MONGO_URL || "mongodb://localhost/happy-thoughts-api" From 3a639bdc39bb192727902e8284244005a1d012e0 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 19:54:48 +0200 Subject: [PATCH 08/58] added seed database --- server.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index cb5d4da..f43a06f 100644 --- a/server.js +++ b/server.js @@ -13,10 +13,22 @@ mongoose.connect(mongoURL) const port = process.env.PORT || 8080 const app = express() -// Add middlewares to enable cors and json body parsing. Middleware is code that runs between the request and the response, it can modify the request, the response, or decide how the server should continue. +// Add middlewares to enable cors and json body parsing. app.use(cors()) app.use(express.json()) +// Seed database +if (process.env.RESET_DB) { + const seedDatabase = async () => { + await Thought.deleteMany({}) + thoughtData.forEach(thought => { + new Thought(thought).save() + }) + } + seedDatabase() + } + + // Start defining your routes here. Add documentation of the API here with express-list-endpoints. app.get("/", (req, res) => { const endpoints = listEndpoints(app) From f5f7fb3d8c6f8c4ea25e6232dedf32a18788b99c Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 19:57:47 +0200 Subject: [PATCH 09/58] changed json message --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index f43a06f..d5b79a3 100644 --- a/server.js +++ b/server.js @@ -33,7 +33,7 @@ if (process.env.RESET_DB) { app.get("/", (req, res) => { const endpoints = listEndpoints(app) res.json({ - message: "Welcome to the Flower API", + message: "Welcome to the Happy Toughts", endpoints: endpoints }) From 4a6899ed57e339c0f65ad0838097b993bddcd78b Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 20:37:25 +0200 Subject: [PATCH 10/58] Added thought and user routes --- routes/thoughtRoutes.js | 0 routes/userRoutes.js | 0 server.js | 15 ++++++++++----- 3 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 routes/thoughtRoutes.js create mode 100644 routes/userRoutes.js 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 d5b79a3..3e2c1f1 100644 --- a/server.js +++ b/server.js @@ -3,6 +3,8 @@ import express from "express" import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" import dotenv from "dotenv" +import thoughtRoutes from "./routes/thoughtRoutes" +import userRoutes from "./routes/userRoutes" dotenv.config() @@ -31,13 +33,16 @@ if (process.env.RESET_DB) { // Start defining your routes here. Add documentation of the API here with express-list-endpoints. app.get("/", (req, res) => { -const endpoints = listEndpoints(app) -res.json({ - message: "Welcome to the Happy Toughts", - endpoints: endpoints + const endpoints = listEndpoints(app) + res.json({ + message: "Welcome to the Happy Toughts", + endpoints: endpoints + }) }) -}) +app.use("/users", userRoutes) +app.use("/thoughts", thoughtRoutes) + // Endpoint for getting all flowers and should be called /flowers. We're using RESTFUL APIs. app.get ("/flowers", (req, res) => { From f769b97cc66aecb974301934532004a424bc95cf Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 20:42:48 +0200 Subject: [PATCH 11/58] moved code to thoughtRoutes file --- server.js | 45 ++++----------------------------------------- 1 file changed, 4 insertions(+), 41 deletions(-) diff --git a/server.js b/server.js index 3e2c1f1..059034a 100644 --- a/server.js +++ b/server.js @@ -8,6 +8,7 @@ import userRoutes from "./routes/userRoutes" dotenv.config() + // Connect to Mongo DB database const mongoURL = process.env.MONGO_URL || "mongodb://localhost/happy-thoughts-api" mongoose.connect(mongoURL) @@ -15,10 +16,12 @@ mongoose.connect(mongoURL) const port = process.env.PORT || 8080 const app = express() + // Add middlewares to enable cors and json body parsing. app.use(cors()) app.use(express.json()) + // Seed database if (process.env.RESET_DB) { const seedDatabase = async () => { @@ -40,50 +43,10 @@ app.get("/", (req, res) => { }) }) -app.use("/users", userRoutes) app.use("/thoughts", thoughtRoutes) +app.use("/users", userRoutes) -// Endpoint for getting all flowers and should be called /flowers. We're using RESTFUL APIs. -app.get ("/flowers", (req, res) => { - const { color, botanicalFamily } = req.query - - let filteredFlowers = flowerData - - if (color) { - filteredFlowers = filteredFlowers.filter(flower => flower.color.toLowerCase() === color.toLowerCase()) - } - - res.json(filteredFlowers) -}) - -/* Checking scent instead of color with ?scent=sweet -app.get ("/flowers", (req, res) => { - const { scent, botanicalFamily } = req.query - - let filteredFlowers = flowerData - - if (scent) { - filteredFlowers = filteredFlowers.filter(flower => flower.scent.toLowerCase() === scent.toLowerCase()) - } - - res.json(filteredFlowers) -}) -*/ - -// endpoint for getting one flower -app.get ("/flowers/:id", (req, res) => { - - const flower = flowerData.find((flower) => flower.id === +req.params.id) - -// tiny error handling if we get an id that doesnt exist in our data - if (!flower) { - return res.status(404).json({ error: "flower not found" }) - } - - res.json(flower) -}) - // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) From 836630b7431efee2be34ca014fa36e64bd991efb Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 20:47:05 +0200 Subject: [PATCH 12/58] added user and thought models --- models/Thought.js | 0 models/User.js | 0 routes/thoughtRoutes.js | 27 +++++++++++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 models/Thought.js create mode 100644 models/User.js diff --git a/models/Thought.js b/models/Thought.js new file mode 100644 index 0000000..e69de29 diff --git a/models/User.js b/models/User.js new file mode 100644 index 0000000..e69de29 diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index e69de29..93bb1cc 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -0,0 +1,27 @@ + +// Endpoint for getting all flowers and should be called /flowers. We're using RESTFUL APIs. +app.get ("/flowers", (req, res) => { + const { color, botanicalFamily } = req.query + + let filteredFlowers = flowerData + + if (color) { + filteredFlowers = filteredFlowers.filter(flower => flower.color.toLowerCase() === color.toLowerCase()) + } + + res.json(filteredFlowers) +}) + + +// endpoint for getting one flower +app.get ("/flowers/:id", (req, res) => { + + const flower = flowerData.find((flower) => flower.id === +req.params.id) + +// tiny error handling if we get an id that doesnt exist in our data + if (!flower) { + return res.status(404).json({ error: "flower not found" }) + } + + res.json(flower) +}) \ No newline at end of file From 5ca0e0f33c7052767db259e4926e755ef3016636 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 20:50:47 +0200 Subject: [PATCH 13/58] Created thought model --- models/Thought.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/models/Thought.js b/models/Thought.js index e69de29..c000078 100644 --- a/models/Thought.js +++ b/models/Thought.js @@ -0,0 +1,26 @@ +import mongoose from "mongoose" + +const thoughtSchema = new mongoose.Schema({ + message: { + type: String, + required: true, + minlength: 5, + maxlength: 140 + }, + hearts: { + type: Number, + default: 0 + }, + user: { + type: mongoose.Schema.Types.ObjectId, + ref: "User", + required: true + }, + createdAt: { + type: Date, + default: Date.now + }, + }); + + + export const Thought = mongoose.model("Thought", thoughtSchema) \ No newline at end of file From 14100f92cb6955a4aab5ed9e376c0a5dd13d8670 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 20:52:10 +0200 Subject: [PATCH 14/58] Created user model with access token --- models/User.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/models/User.js b/models/User.js index e69de29..63d9eb3 100644 --- a/models/User.js +++ b/models/User.js @@ -0,0 +1,26 @@ +import mongoose from "mongoose" +import crypto from "crypto"; + + +const userSchema = new mongoose.Schema({ + name: { + type: String, + required: true, + }, + email: { + type: String, + required: true, + unique: true + }, + password: { + type: String, + required: true, + }, + accessToken: { + type: String, + default: () => crypto.randomBytes(128).toString('hex') + } +}); + + +export const User = mongoose.model("User", userSchema); From a3d98c50060349ceede5cb3d9b76c53e5e58b90c Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 20:58:37 +0200 Subject: [PATCH 15/58] Set up Express router --- routes/thoughtRoutes.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index 93bb1cc..86e3d9b 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -1,3 +1,7 @@ +import express from "express" + + +const router = express.Router() // Endpoint for getting all flowers and should be called /flowers. We're using RESTFUL APIs. app.get ("/flowers", (req, res) => { From 83f2a43a1dbf9bfdf947faea34ada92a739ae0af Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 21:05:26 +0200 Subject: [PATCH 16/58] Add GET /thoughts endpoint with query filtering --- routes/thoughtRoutes.js | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index 86e3d9b..e52a191 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -1,22 +1,44 @@ import express from "express" - +import { Thought } from './models/Thought.js'; +import { authenticateUser } from "../middleware/authenticateUser.js" const router = express.Router() // Endpoint for getting all flowers and should be called /flowers. We're using RESTFUL APIs. -app.get ("/flowers", (req, res) => { +router.get ("/thoughts", async (req, res) => { const { color, botanicalFamily } = req.query - - let filteredFlowers = flowerData - - if (color) { - filteredFlowers = filteredFlowers.filter(flower => flower.color.toLowerCase() === color.toLowerCase()) + try { + const query = req.query; + const filteredThoughts = await Thought.find(query) + + if (filteredThoughts.length === 0) { + // Return 404 if no thoughts are found + return res.status(404).json({ + success: false, + response: [], + message: "No thoughts found for that query. Try another one." + }) } - res.json(filteredFlowers) + // Return 200 if thoughts are found + res.status(200).json({ + success: true, + response: filteredThoughts, + message: "Success!" + }) + + } catch (error) { + // Return 500 server error database query fails. + res.status(500).json({ + success: false, + response: error, + message: "Internal server error! Failed to fetch thoughts." + }) + } }) + // endpoint for getting one flower app.get ("/flowers/:id", (req, res) => { From b764be3b2a0179a649f260679c4b760931fe7040 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 21:12:36 +0200 Subject: [PATCH 17/58] Add GET /thoughts/:id endpoint --- routes/thoughtRoutes.js | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index e52a191..34c385e 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -38,16 +38,31 @@ router.get ("/thoughts", async (req, res) => { }) +// GET - Get a single thought by ID (endpoint is /thoughts/:id) +router.get ("/thoughts/:id", async (req, res) => { + const { id } = req.params -// endpoint for getting one flower -app.get ("/flowers/:id", (req, res) => { - - const flower = flowerData.find((flower) => flower.id === +req.params.id) + try { + const thought = await Thought.findById(id) -// tiny error handling if we get an id that doesnt exist in our data - if (!flower) { - return res.status(404).json({ error: "flower not found" }) + if (!thought) { + return res.status(404).json({ + success: false, + response: [], + message: "Thought not found" + }) } - res.json(flower) -}) \ No newline at end of file + res.status(200).json({ + success: true, + response: thought + }) + + } catch (error) { + res.status(500).json({ + success: false, + response: error, + message: "Internal server error! Failed to fetch thought." + }) + } +}) From c635810485771945202ac9bcacf059c5fca49056 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 21:14:53 +0200 Subject: [PATCH 18/58] fixed mispellings and removed unnecessary code --- routes/thoughtRoutes.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index 34c385e..aa9d568 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -4,9 +4,8 @@ import { authenticateUser } from "../middleware/authenticateUser.js" const router = express.Router() -// Endpoint for getting all flowers and should be called /flowers. We're using RESTFUL APIs. -router.get ("/thoughts", async (req, res) => { - const { color, botanicalFamily } = req.query +// Endpoint for getting all thoughts. +router.get("/thoughts", async (req, res) => { try { const query = req.query; const filteredThoughts = await Thought.find(query) @@ -39,7 +38,7 @@ router.get ("/thoughts", async (req, res) => { // GET - Get a single thought by ID (endpoint is /thoughts/:id) -router.get ("/thoughts/:id", async (req, res) => { +router.get("/thoughts/:id", async (req, res) => { const { id } = req.params try { From 0e9b9f0145b5fb14ce317fe39dc7e6c8d39d52cb Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 21:18:16 +0200 Subject: [PATCH 19/58] Add PATCH /thoughts/:id/like endpoint --- routes/thoughtRoutes.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index aa9d568..6eea3d3 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -65,3 +65,37 @@ router.get("/thoughts/:id", async (req, res) => { }) } }) + + +// PATCH - Like a thought +router.patch("/thoughts/:id/like", async (req,res) => { + const { id } = req.params + + try { + const updatedThought = await Thought.findByIdAndUpdate( + id, + { $inc: { hearts: 1 }}, // increase like by 1 + { new: true } + ) + if (!updatedThought) { + return res.status(404).json({ + success: false, + response: [], + message: "Thought not found." + }) + } + + res.status(200).json({ + success: true, + response: updatedThought, + message: "Thought liked successfully." + }) + + } catch (error) { + res.status(500).json({ + success: false, + response: error, + message: "Internal server error! Failed to like the thought." + }) + } +}) From 3b087147af305eec57839226cca38e0dcf135c95 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 21:27:38 +0200 Subject: [PATCH 20/58] Added POST /thoughts endpoint with authentication --- routes/thoughtRoutes.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index 6eea3d3..1081296 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -99,3 +99,35 @@ router.patch("/thoughts/:id/like", async (req,res) => { }) } }) + + +// POST - Create a thought (endpoint is /thoughts) +router.post("/thoughts", authenticateUser, async (req, res) => { + const { message } = req.body + const user = req.user + + try { + const newThought = await new Thought({ message, user: user._id }).save() + + if (!newThought) + res.status(400).json({ + success: false, + response: [], + message: "Failed to post thought" + }) + + res.status(201).json({ + success: true, + response: newThought, + message: "Thought created successfully." + }) + + } catch (error) { + res.status(500).json({ + success: false, + response: error, + message: "Internal server error! Failed to post thought" + }) + } +}) + \ No newline at end of file From 0cb7f84abf98f306e7e0497d8aa9dd236889c17b Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 21:29:55 +0200 Subject: [PATCH 21/58] Added PATCH /thoughts/:id endpoint with authentication --- routes/thoughtRoutes.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index 1081296..4c3d245 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -130,4 +130,38 @@ router.post("/thoughts", authenticateUser, async (req, res) => { }) } }) + + +// PATCH - Update a thought (endpoint is thoughts/:id) +router.patch("/thoughts/:id", authenticateUser, async (req, res) => { + const { id } = req.params + const { message } = req.body + + try { + const updatedThought = await Thought.findByIdAndUpdate(id, { message }, { + new: true, + runValidators: true + }) + + if(!updatedThought) { + return res.status(404).json({ + success: false, + response: [], + message: "Thought not found"}) + } + + res.status(200).json({ + success: true, + response: updatedThought, + message: "Thought updated successfully" + }) + + } catch (error) { + res.status(500).json({ + success: false, + response: error, + message: "Internal server error! Failed to update thought." + }) + } + }) \ No newline at end of file From bed460ae8b6f6baa2ff3b05521b066b5eda8d4de Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 21:31:59 +0200 Subject: [PATCH 22/58] Added DELETE /thoughts/:id endpoint with authentication and authorization --- routes/thoughtRoutes.js | 46 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index 4c3d245..240fe5d 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -164,4 +164,50 @@ router.patch("/thoughts/:id", authenticateUser, async (req, res) => { }) } }) + + +// DELETE - Delete a thought (endpoint is thoughts/:id) +router.delete("/thoughts/:id", authenticateUser, async (req, res) => { + const { id } = req.params + const userId = req.user._id + + try { + const thought = await Thought.findById(id) + + if (!thought) { + return res.status(404).json({ + success: false, + response: [], + message: "Failed to delete thought! Thought not found"}) + } + + if (thought.user.toString() !== userId.toString()) { + return res.status(403).json({ + success: false, + response: [], + message: "Failed to delete thought! You are not authorized to delete this thought." + }) + } + + // Delete the thought + await Thought.findByIdAndDelete(id) + + res.status(200).json({ + success: true, + response: id, + message: "Thought deleted successfully" + }) + + } catch (error) { + res.status(500).json({ + success: false, + response: error, + message: "Internal server error! Failed to update thought." + }) + } + }) + + + export default router + \ No newline at end of file From c9330ed1752eaf3fdf50b3a26f659f470b2ed36a Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 21:34:15 +0200 Subject: [PATCH 23/58] Set up Express router --- routes/userRoutes.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/routes/userRoutes.js b/routes/userRoutes.js index e69de29..6f291ea 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -0,0 +1,3 @@ +import express from 'express' + +const router = express.Router() \ No newline at end of file From 4ca70486b3654fdd2ef3c828adbd88c44ac2149a Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 21:36:55 +0200 Subject: [PATCH 24/58] Added POST /register endpoint with password hashing --- routes/userRoutes.js | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/routes/userRoutes.js b/routes/userRoutes.js index 6f291ea..bc9c966 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -1,3 +1,39 @@ import express from 'express' +import bcrypt from 'bcryptjs' +import { User } from '../models/User.js' -const router = express.Router() \ No newline at end of file +const router = express.Router() + + +// POST - Register a new user +router.post("/register", async (req, res) => { + try { + const { email, password } = req.body + const salt = bcrypt.genSaltSync() + const user = new User({ email, password: bcrypt.hashSync(password, salt) + }) + + //await to not send response before database finished saving + await user.save() + + res.status(201).json({ + success: true, + message: "User created successfully.", + response: { + id: user._id, + accessToken: user.accessToken + } + }) + + } catch (error) { + res.status(400).json({ + success: false, + message: "Failed to create user.", + response: error + }) + } + }) + + + export default router + \ No newline at end of file From 9b7f6bb52f630e4cf315ca891b20647590062143 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 21:39:35 +0200 Subject: [PATCH 25/58] Added POST /login endpoint with password verification --- routes/userRoutes.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/routes/userRoutes.js b/routes/userRoutes.js index bc9c966..7d5b9dc 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -35,5 +35,36 @@ router.post("/register", async (req, res) => { }) +// POST - Login an existing user +router.post("/login", async (req, res) => { + try { + const { email, password } = req.body + const user = await User.findOne({ email }) + + if (user && bcrypt.compareSync(password, user.password)) { + res.status(200).json({ + success: true, + accessToken: user.accessToken, + id: user.id, + message: "Login successful" + }) + + } else { + res.status(401).json({ + success: false, + message: "Invalid email or password" + }) + } + + } catch (error) { + res.status(500).json({ + success: false, + message: "Something went wrong", + error: error.message + }) + } + }) + + export default router \ No newline at end of file From 0fdcdd5aac1f5a7983b46e926cf499fde56a5a80 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 21:43:11 +0200 Subject: [PATCH 26/58] Added authentication middleware to verify accessToken --- middleware/authenticateUser.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 middleware/authenticateUser.js diff --git a/middleware/authenticateUser.js b/middleware/authenticateUser.js new file mode 100644 index 0000000..5fd5fed --- /dev/null +++ b/middleware/authenticateUser.js @@ -0,0 +1,26 @@ +import { User } from "../models/User.js" + + +export const authenticateUser = async (req, res, next) => { + try { + const user = await User.findOne ({ accessToken: req.header("Authorization") }) + + if (user) { + req.user = user + next() + + } else { + res.status(401).json({ + success: false, + message: "Authorization missing or invalid", + loggedOut: true + }) + } + + } catch (error) { + res.status(500).json({ + message: "Internal server error", + error: error.message + }) + } +} From 6ae4f52e434b8a1f4184b385c25570d2dffcdefa Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 21:50:26 +0200 Subject: [PATCH 27/58] Imported thought model --- server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server.js b/server.js index 059034a..fe1504f 100644 --- a/server.js +++ b/server.js @@ -5,6 +5,7 @@ import mongoose from "mongoose" import dotenv from "dotenv" import thoughtRoutes from "./routes/thoughtRoutes" import userRoutes from "./routes/userRoutes" +import Thought from "../models/Thought.js" dotenv.config() From c9ae7d7205463d75c1b4cd6c8847b9e9f6667fe7 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 21:53:20 +0200 Subject: [PATCH 28/58] Added .js to imports --- server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index fe1504f..a908e5e 100644 --- a/server.js +++ b/server.js @@ -3,8 +3,8 @@ import express from "express" import listEndpoints from "express-list-endpoints" import mongoose from "mongoose" import dotenv from "dotenv" -import thoughtRoutes from "./routes/thoughtRoutes" -import userRoutes from "./routes/userRoutes" +import thoughtRoutes from "./routes/thoughtRoutes.js" +import userRoutes from "./routes/userRoutes.js" import Thought from "../models/Thought.js" dotenv.config() From d7b7425ac5ade00e6a5a84683c9b40bcf8221ad5 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 21:58:26 +0200 Subject: [PATCH 29/58] Fixed import path for thought model --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index a908e5e..3a3f8b2 100644 --- a/server.js +++ b/server.js @@ -5,7 +5,7 @@ import mongoose from "mongoose" import dotenv from "dotenv" import thoughtRoutes from "./routes/thoughtRoutes.js" import userRoutes from "./routes/userRoutes.js" -import Thought from "../models/Thought.js" +import { Thought } from "../models/Thought.js" dotenv.config() From b6ce6abfc94d4a768ade777a30aa5c51957143aa Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Wed, 6 Aug 2025 23:23:51 +0200 Subject: [PATCH 30/58] Changed thought and user imports --- middleware/authenticateUser.js | 2 +- routes/thoughtRoutes.js | 2 +- routes/userRoutes.js | 2 +- server.js | 13 ------------- 4 files changed, 3 insertions(+), 16 deletions(-) diff --git a/middleware/authenticateUser.js b/middleware/authenticateUser.js index 5fd5fed..925ee6d 100644 --- a/middleware/authenticateUser.js +++ b/middleware/authenticateUser.js @@ -1,4 +1,4 @@ -import { User } from "../models/User.js" +import { User } from "../models/user.js" export const authenticateUser = async (req, res, next) => { diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index 240fe5d..d8d362b 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -1,5 +1,5 @@ import express from "express" -import { Thought } from './models/Thought.js'; +import Thought from './models/thought.js' import { authenticateUser } from "../middleware/authenticateUser.js" const router = express.Router() diff --git a/routes/userRoutes.js b/routes/userRoutes.js index 7d5b9dc..275bf41 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -1,6 +1,6 @@ import express from 'express' import bcrypt from 'bcryptjs' -import { User } from '../models/User.js' +import User from './models/user.js' const router = express.Router() diff --git a/server.js b/server.js index 3a3f8b2..2e204af 100644 --- a/server.js +++ b/server.js @@ -5,7 +5,6 @@ import mongoose from "mongoose" import dotenv from "dotenv" import thoughtRoutes from "./routes/thoughtRoutes.js" import userRoutes from "./routes/userRoutes.js" -import { Thought } from "../models/Thought.js" dotenv.config() @@ -21,18 +20,6 @@ const app = express() // Add middlewares to enable cors and json body parsing. app.use(cors()) app.use(express.json()) - - -// Seed database -if (process.env.RESET_DB) { - const seedDatabase = async () => { - await Thought.deleteMany({}) - thoughtData.forEach(thought => { - new Thought(thought).save() - }) - } - seedDatabase() - } // Start defining your routes here. Add documentation of the API here with express-list-endpoints. From 75ccb2d5e81dba9e4b955e067565507f0f67575b Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Thu, 7 Aug 2025 13:22:48 +0200 Subject: [PATCH 31/58] Changed imported routes --- routes/thoughtRoutes.js | 2 +- routes/userRoutes.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index d8d362b..f71daeb 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -1,5 +1,5 @@ import express from "express" -import Thought from './models/thought.js' +import { Thought } from '../models/thought.js' import { authenticateUser } from "../middleware/authenticateUser.js" const router = express.Router() diff --git a/routes/userRoutes.js b/routes/userRoutes.js index 275bf41..1985cdd 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -1,6 +1,6 @@ import express from 'express' -import bcrypt from 'bcryptjs' -import User from './models/user.js' +import bcrypt from 'bcrypt' +import { User } from '../models/user.js' const router = express.Router() From b86b25bb2a0f1bea98d654dec347d8a597b227a9 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Thu, 7 Aug 2025 16:19:19 +0200 Subject: [PATCH 32/58] Moved devDependencies to dependencies --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index ddb2cc9..9e448e1 100644 --- a/package.json +++ b/package.json @@ -16,12 +16,12 @@ "express": "^4.17.3", "express-list-endpoints": "^7.1.1", "jsonwebtoken": "^9.0.2", - "mongoose": "^8.17.0" - }, - "devDependencies": { + "mongoose": "^8.17.0", "@babel/core": "^7.28.0", "@babel/node": "^7.28.0", - "@babel/preset-env": "^7.28.0", + "@babel/preset-env": "^7.28.0" + }, + "devDependencies": { "nodemon": "^3.1.10" } } From f26ade73f80718015e231da8cc391145313fb298 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Thu, 7 Aug 2025 17:25:27 +0200 Subject: [PATCH 33/58] test relative path --- routes/thoughtRoutes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index f71daeb..dd36787 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -1,5 +1,5 @@ import express from "express" -import { Thought } from '../models/thought.js' +import { Thought } from 'models/thought.js' import { authenticateUser } from "../middleware/authenticateUser.js" const router = express.Router() From 37e6bbb57a0a97a5684fcbd9a7c5b10d92d7ad64 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Thu, 7 Aug 2025 17:41:01 +0200 Subject: [PATCH 34/58] Changed start path --- package.json | 4 ++-- routes/thoughtRoutes.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 9e448e1..db85ee0 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "Project API", "type": "module", "scripts": { - "start": "babel-node server.js", - "dev": "nodemon server.js --exec babel-node" + "start": "babel-node src/routes/server.js", + "dev": "nodemon src/routes/server.js --exec babel-node" }, "author": "", "license": "ISC", diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index dd36787..f71daeb 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -1,5 +1,5 @@ import express from "express" -import { Thought } from 'models/thought.js' +import { Thought } from '../models/thought.js' import { authenticateUser } from "../middleware/authenticateUser.js" const router = express.Router() From 64ac6f00637598fdaca22a88fd68b01ccf29d391 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Thu, 7 Aug 2025 17:44:11 +0200 Subject: [PATCH 35/58] Changed path --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index db85ee0..d6cea48 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "Project API", "type": "module", "scripts": { - "start": "babel-node src/routes/server.js", - "dev": "nodemon src/routes/server.js --exec babel-node" + "start": "babel-node routes/server.js", + "dev": "nodemon routes/server.js --exec babel-node" }, "author": "", "license": "ISC", From 24dc3130ff78fa121406f032023c314b71df94da Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Thu, 7 Aug 2025 17:47:40 +0200 Subject: [PATCH 36/58] Changed path --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index d6cea48..9e448e1 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "Project API", "type": "module", "scripts": { - "start": "babel-node routes/server.js", - "dev": "nodemon routes/server.js --exec babel-node" + "start": "babel-node server.js", + "dev": "nodemon server.js --exec babel-node" }, "author": "", "license": "ISC", From b2a2c4cf60dd47aa70a9921db39735185577f12e Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Thu, 7 Aug 2025 17:52:49 +0200 Subject: [PATCH 37/58] Changed thought import --- routes/thoughtRoutes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index f71daeb..fb94e25 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -1,5 +1,5 @@ import express from "express" -import { Thought } from '../models/thought.js' +import { Thought } from '/Users/tavanthiry/Desktop/js-project-api/models/thought.js' import { authenticateUser } from "../middleware/authenticateUser.js" const router = express.Router() From 8f484326ec23f4b757e416117247825b3cbeb6fe Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Thu, 7 Aug 2025 18:13:14 +0200 Subject: [PATCH 38/58] Use single quotations --- middleware/authenticateUser.js | 2 +- models/Thought.js | 2 +- models/User.js | 4 ++-- routes/thoughtRoutes.js | 6 +++--- server.js | 14 +++++++------- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/middleware/authenticateUser.js b/middleware/authenticateUser.js index 925ee6d..d1a286f 100644 --- a/middleware/authenticateUser.js +++ b/middleware/authenticateUser.js @@ -1,4 +1,4 @@ -import { User } from "../models/user.js" +import { User } from '../models/user.js' export const authenticateUser = async (req, res, next) => { diff --git a/models/Thought.js b/models/Thought.js index c000078..839f156 100644 --- a/models/Thought.js +++ b/models/Thought.js @@ -1,4 +1,4 @@ -import mongoose from "mongoose" +import mongoose from 'mongoose' const thoughtSchema = new mongoose.Schema({ message: { diff --git a/models/User.js b/models/User.js index 63d9eb3..181263f 100644 --- a/models/User.js +++ b/models/User.js @@ -1,5 +1,5 @@ -import mongoose from "mongoose" -import crypto from "crypto"; +import mongoose from 'mongoose' +import crypto from 'crypto' const userSchema = new mongoose.Schema({ diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index fb94e25..481a469 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -1,6 +1,6 @@ -import express from "express" -import { Thought } from '/Users/tavanthiry/Desktop/js-project-api/models/thought.js' -import { authenticateUser } from "../middleware/authenticateUser.js" +import express from 'express' +import { Thought } from '../models/thought.js' +import { authenticateUser } from '../middleware/authenticateUser.js' const router = express.Router() diff --git a/server.js b/server.js index 2e204af..f921c31 100644 --- a/server.js +++ b/server.js @@ -1,10 +1,10 @@ -import cors from "cors" -import express from "express" -import listEndpoints from "express-list-endpoints" -import mongoose from "mongoose" -import dotenv from "dotenv" -import thoughtRoutes from "./routes/thoughtRoutes.js" -import userRoutes from "./routes/userRoutes.js" +import cors from 'cors' +import express from 'express' +import listEndpoints from 'express-list-endpoints' +import mongoose from 'mongoose' +import dotenv from 'dotenv' +import thoughtRoutes from './routes/thoughtRoutes.js' +import userRoutes from './routes/userRoutes.js' dotenv.config() From d140a0206e6228f9b27d2c24df146e3d055c3bee Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Thu, 7 Aug 2025 19:07:07 +0200 Subject: [PATCH 39/58] Test run --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index f921c31..428230f 100644 --- a/server.js +++ b/server.js @@ -35,7 +35,7 @@ app.use("/thoughts", thoughtRoutes) app.use("/users", userRoutes) -// Start the server +// Start the server. app.listen(port, () => { console.log(`Server running on http://localhost:${port}`) }) From 904f898024fdf0ff613cf12ba5a2a3dd17ff9684 Mon Sep 17 00:00:00 2001 From: Tavan Thiry <141061580+T-Thiry@users.noreply.github.com> Date: Thu, 7 Aug 2025 19:20:09 +0200 Subject: [PATCH 40/58] Rename Thought.js to thought.js --- models/{Thought.js => thought.js} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename models/{Thought.js => thought.js} (99%) diff --git a/models/Thought.js b/models/thought.js similarity index 99% rename from models/Thought.js rename to models/thought.js index 839f156..da5f6a0 100644 --- a/models/Thought.js +++ b/models/thought.js @@ -23,4 +23,4 @@ const thoughtSchema = new mongoose.Schema({ }); - export const Thought = mongoose.model("Thought", thoughtSchema) \ No newline at end of file + export const Thought = mongoose.model("Thought", thoughtSchema) From a56f4632fe51e718493d52dcd07e08f94920a492 Mon Sep 17 00:00:00 2001 From: Tavan Thiry <141061580+T-Thiry@users.noreply.github.com> Date: Thu, 7 Aug 2025 19:21:40 +0200 Subject: [PATCH 41/58] Rename User.js to user.js --- models/{User.js => user.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename models/{User.js => user.js} (100%) diff --git a/models/User.js b/models/user.js similarity index 100% rename from models/User.js rename to models/user.js From b8a49392068d622426b9702ce4fc2538d9b0e106 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Sun, 10 Aug 2025 23:46:42 +0200 Subject: [PATCH 42/58] changed backend routes --- routes/thoughtRoutes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index 481a469..11df221 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -5,7 +5,7 @@ import { authenticateUser } from '../middleware/authenticateUser.js' const router = express.Router() // Endpoint for getting all thoughts. -router.get("/thoughts", async (req, res) => { +router.get("/", async (req, res) => { try { const query = req.query; const filteredThoughts = await Thought.find(query) @@ -102,7 +102,7 @@ router.patch("/thoughts/:id/like", async (req,res) => { // POST - Create a thought (endpoint is /thoughts) -router.post("/thoughts", authenticateUser, async (req, res) => { +router.post("/", authenticateUser, async (req, res) => { const { message } = req.body const user = req.user From 34ed37708d8920fbc10650a194edb32c7118c26b Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Sun, 10 Aug 2025 23:57:41 +0200 Subject: [PATCH 43/58] Changed more routes --- routes/thoughtRoutes.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index 11df221..4829259 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -38,7 +38,7 @@ router.get("/", async (req, res) => { // GET - Get a single thought by ID (endpoint is /thoughts/:id) -router.get("/thoughts/:id", async (req, res) => { +router.get("/:id", async (req, res) => { const { id } = req.params try { @@ -68,7 +68,7 @@ router.get("/thoughts/:id", async (req, res) => { // PATCH - Like a thought -router.patch("/thoughts/:id/like", async (req,res) => { +router.patch("/:id/like", async (req,res) => { const { id } = req.params try { @@ -133,7 +133,7 @@ router.post("/", authenticateUser, async (req, res) => { // PATCH - Update a thought (endpoint is thoughts/:id) -router.patch("/thoughts/:id", authenticateUser, async (req, res) => { +router.patch("/:id", authenticateUser, async (req, res) => { const { id } = req.params const { message } = req.body @@ -167,7 +167,7 @@ router.patch("/thoughts/:id", authenticateUser, async (req, res) => { // DELETE - Delete a thought (endpoint is thoughts/:id) -router.delete("/thoughts/:id", authenticateUser, async (req, res) => { +router.delete("/:id", authenticateUser, async (req, res) => { const { id } = req.params const userId = req.user._id From 27ad8940f60518574a3248d6d26b5984f2c05f41 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Mon, 11 Aug 2025 01:14:44 +0200 Subject: [PATCH 44/58] Changed URL --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index 428230f..856d28e 100644 --- a/server.js +++ b/server.js @@ -10,7 +10,7 @@ dotenv.config() // Connect to Mongo DB database -const mongoURL = process.env.MONGO_URL || "mongodb://localhost/happy-thoughts-api" +const mongoURL = process.env.MONGO_URL || "mongodb://localhost:27017/happythoughts" mongoose.connect(mongoURL) const port = process.env.PORT || 8080 From b4d4743e797a7dad281d229025f08cb8fd223416 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Tue, 12 Aug 2025 09:53:43 +0200 Subject: [PATCH 45/58] Replaced catch block --- routes/userRoutes.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/routes/userRoutes.js b/routes/userRoutes.js index 1985cdd..701fe8e 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -26,10 +26,11 @@ router.post("/register", async (req, res) => { }) } catch (error) { + console.error("Signup error:", error) res.status(400).json({ success: false, message: "Failed to create user.", - response: error + response: error.message }) } }) From e38129875321140b09a67531eecfdec725522d07 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Tue, 12 Aug 2025 10:19:33 +0200 Subject: [PATCH 46/58] Added name to post --- routes/userRoutes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routes/userRoutes.js b/routes/userRoutes.js index 701fe8e..dde3bc7 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -8,9 +8,9 @@ const router = express.Router() // POST - Register a new user router.post("/register", async (req, res) => { try { - const { email, password } = req.body + const { name, email, password } = req.body const salt = bcrypt.genSaltSync() - const user = new User({ email, password: bcrypt.hashSync(password, salt) + const user = new User({ name, email, password: bcrypt.hashSync(password, salt) }) //await to not send response before database finished saving From a2c4766a5c72a730889704151ab9232c8208ad29 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Tue, 12 Aug 2025 10:27:13 +0200 Subject: [PATCH 47/58] Removed space --- middleware/authenticateUser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/middleware/authenticateUser.js b/middleware/authenticateUser.js index d1a286f..f2980e5 100644 --- a/middleware/authenticateUser.js +++ b/middleware/authenticateUser.js @@ -3,7 +3,7 @@ import { User } from '../models/user.js' export const authenticateUser = async (req, res, next) => { try { - const user = await User.findOne ({ accessToken: req.header("Authorization") }) + const user = await User.findOne({ accessToken: req.header("Authorization") }) if (user) { req.user = user From cded4dbfb89edfd4d702df502c2759ad4562e6f1 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Tue, 12 Aug 2025 10:52:17 +0200 Subject: [PATCH 48/58] Removed req.user and moved user to req.body --- routes/thoughtRoutes.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index 4829259..75d35eb 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -103,8 +103,7 @@ router.patch("/:id/like", async (req,res) => { // POST - Create a thought (endpoint is /thoughts) router.post("/", authenticateUser, async (req, res) => { - const { message } = req.body - const user = req.user + const { message, user } = req.body try { const newThought = await new Thought({ message, user: user._id }).save() From f2296d5b5de4e28cd544e2da5f1b8ddbb2f6686c Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Tue, 12 Aug 2025 11:00:36 +0200 Subject: [PATCH 49/58] Added brackets --- routes/thoughtRoutes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index 75d35eb..2a88244 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -108,13 +108,13 @@ router.post("/", authenticateUser, async (req, res) => { try { const newThought = await new Thought({ message, user: user._id }).save() - if (!newThought) + if (!newThought) { res.status(400).json({ success: false, response: [], message: "Failed to post thought" }) - + } res.status(201).json({ success: true, response: newThought, From 5518431d85967aa5f84726361f2762121f43729b Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Tue, 12 Aug 2025 15:44:52 +0200 Subject: [PATCH 50/58] removed user and extracted and extracted user from middleware --- routes/thoughtRoutes.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index 2a88244..e7cde0e 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -103,10 +103,11 @@ router.patch("/:id/like", async (req,res) => { // POST - Create a thought (endpoint is /thoughts) router.post("/", authenticateUser, async (req, res) => { - const { message, user } = req.body + const { message } = req.body + const userId = req.user._id try { - const newThought = await new Thought({ message, user: user._id }).save() + const newThought = await new Thought({ message, user: userId }).save() if (!newThought) { res.status(400).json({ From 0049405164f5ef4f116652c540970bb5eb7679ee Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Tue, 12 Aug 2025 16:08:39 +0200 Subject: [PATCH 51/58] Added user to req.body and changed user.Id to user._id --- routes/thoughtRoutes.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index e7cde0e..43ddd5c 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -103,11 +103,10 @@ router.patch("/:id/like", async (req,res) => { // POST - Create a thought (endpoint is /thoughts) router.post("/", authenticateUser, async (req, res) => { - const { message } = req.body - const userId = req.user._id + const { user, message } = req.body try { - const newThought = await new Thought({ message, user: userId }).save() + const newThought = await new Thought({ message, user: user._Id }).save() if (!newThought) { res.status(400).json({ From ac4008ccbd9f023578183e9328137c39878d177a Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Tue, 12 Aug 2025 16:14:11 +0200 Subject: [PATCH 52/58] Added user to req.body and changed user.Id to user._ id --- routes/thoughtRoutes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index 43ddd5c..95d138a 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -106,7 +106,7 @@ router.post("/", authenticateUser, async (req, res) => { const { user, message } = req.body try { - const newThought = await new Thought({ message, user: user._Id }).save() + const newThought = await new Thought({ message, user: user._id }).save() if (!newThought) { res.status(400).json({ From 4708a0887aefbe649751408c235e1b9ea592ece9 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Tue, 12 Aug 2025 19:16:41 +0200 Subject: [PATCH 53/58] Added id to userschema --- models/user.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/models/user.js b/models/user.js index 181263f..e16ed63 100644 --- a/models/user.js +++ b/models/user.js @@ -3,6 +3,12 @@ import crypto from 'crypto' const userSchema = new mongoose.Schema({ +_id: { + type: Number, + required: true, + unique: true, + default: () => Math.floor(Math.random() * 1000000) // Random ID for simplicity +}, name: { type: String, required: true, From 2d66c8cde48bff6abdf49349bc0577013917284e Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Tue, 12 Aug 2025 19:54:00 +0200 Subject: [PATCH 54/58] Added id to thoughtschema --- models/thought.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/models/thought.js b/models/thought.js index da5f6a0..72ae21f 100644 --- a/models/thought.js +++ b/models/thought.js @@ -1,6 +1,12 @@ import mongoose from 'mongoose' const thoughtSchema = new mongoose.Schema({ + _id: { + type: Number, + required: true, + unique: true, + default: () => Math.floor(Math.random() * 1000000) // Random ID for simplicity + }, message: { type: String, required: true, From 01aee3633712e49e928a3aae8fa24fcf15219b7b Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Tue, 12 Aug 2025 20:18:37 +0200 Subject: [PATCH 55/58] Updated id definition --- models/thought.js | 6 ++---- models/user.js | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/models/thought.js b/models/thought.js index 72ae21f..b479791 100644 --- a/models/thought.js +++ b/models/thought.js @@ -2,10 +2,8 @@ import mongoose from 'mongoose' const thoughtSchema = new mongoose.Schema({ _id: { - type: Number, - required: true, - unique: true, - default: () => Math.floor(Math.random() * 1000000) // Random ID for simplicity + type: mongoose.Schema.Types.ObjectId, + default: () => new mongoose.Types.ObjectId() }, message: { type: String, diff --git a/models/user.js b/models/user.js index e16ed63..4b8a915 100644 --- a/models/user.js +++ b/models/user.js @@ -4,10 +4,8 @@ import crypto from 'crypto' const userSchema = new mongoose.Schema({ _id: { - type: Number, - required: true, - unique: true, - default: () => Math.floor(Math.random() * 1000000) // Random ID for simplicity + type: mongoose.Schema.Types.ObjectId, + default: () => new mongoose.Types.ObjectId() }, name: { type: String, From fff34ace47c731324feea6c6c645372230c1e9be Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Tue, 12 Aug 2025 20:23:29 +0200 Subject: [PATCH 56/58] Added return on response --- routes/thoughtRoutes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index 95d138a..04491c3 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -109,7 +109,7 @@ router.post("/", authenticateUser, async (req, res) => { const newThought = await new Thought({ message, user: user._id }).save() if (!newThought) { - res.status(400).json({ + return res.status(400).json({ success: false, response: [], message: "Failed to post thought" From fc2d78087dac9524571854bee19fbb30dde8d63f Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Tue, 12 Aug 2025 20:37:33 +0200 Subject: [PATCH 57/58] Pull user from req instead of req.body --- routes/thoughtRoutes.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/routes/thoughtRoutes.js b/routes/thoughtRoutes.js index 04491c3..4743c77 100644 --- a/routes/thoughtRoutes.js +++ b/routes/thoughtRoutes.js @@ -103,11 +103,11 @@ router.patch("/:id/like", async (req,res) => { // POST - Create a thought (endpoint is /thoughts) router.post("/", authenticateUser, async (req, res) => { - const { user, message } = req.body + const { message } = req.body try { - const newThought = await new Thought({ message, user: user._id }).save() - + const newThought = await new Thought({ message, user: req.user._id }).save() + if (!newThought) { return res.status(400).json({ success: false, From 9fb887e1c23051696c3f8d58e2f6a4ccd79face5 Mon Sep 17 00:00:00 2001 From: Tavan Thiry Date: Tue, 12 Aug 2025 20:42:11 +0200 Subject: [PATCH 58/58] Removed id from thougt schema and user schema --- models/thought.js | 4 ---- models/user.js | 4 ---- 2 files changed, 8 deletions(-) diff --git a/models/thought.js b/models/thought.js index b479791..da5f6a0 100644 --- a/models/thought.js +++ b/models/thought.js @@ -1,10 +1,6 @@ import mongoose from 'mongoose' const thoughtSchema = new mongoose.Schema({ - _id: { - type: mongoose.Schema.Types.ObjectId, - default: () => new mongoose.Types.ObjectId() - }, message: { type: String, required: true, diff --git a/models/user.js b/models/user.js index 4b8a915..181263f 100644 --- a/models/user.js +++ b/models/user.js @@ -3,10 +3,6 @@ import crypto from 'crypto' const userSchema = new mongoose.Schema({ -_id: { - type: mongoose.Schema.Types.ObjectId, - default: () => new mongoose.Types.ObjectId() -}, name: { type: String, required: true,