From 12dbd855b88cc84ba49dd48258cc3ae4c82c38fc Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Tue, 27 May 2025 10:37:20 +0200 Subject: [PATCH 01/48] added functions to thoughtServices --- package.json | 1 + routes/happyThoughts.js | 9 ++++++ server.js | 61 +++++++++++++++++++++++++++----------- services/mockData.js | 3 ++ services/thoughtService.js | 46 ++++++++++++++++++++++++++++ 5 files changed, 103 insertions(+), 17 deletions(-) create mode 100644 routes/happyThoughts.js create mode 100644 services/mockData.js create mode 100644 services/thoughtService.js 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/routes/happyThoughts.js b/routes/happyThoughts.js new file mode 100644 index 0000000..ce1279d --- /dev/null +++ b/routes/happyThoughts.js @@ -0,0 +1,9 @@ +import express from 'express'; + +const router = express.Router(); + +//kontroller funtkioner/handalers? +function listAllThoughts(req, res) { + // Här skulle du hämta alla tankar från databasen + res.json({ message: 'List of all thoughts' }); +} diff --git a/server.js b/server.js index f47771b..a675a51 100644 --- a/server.js +++ b/server.js @@ -1,22 +1,49 @@ -import cors from "cors" -import express from "express" +import cors from 'cors'; +import express from 'express'; +const expressListEndpoints = require('express-list-endpoints'); +import dotenv from 'dotenv'; -// 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() +// Ladda in .env-filen +dotenv.config(); +const port = process.env.PORT || 8080; -// Add middlewares to enable cors and json body parsing -app.use(cors()) -app.use(express.json()) +// Skapa en Express-app +const app = express(); -// Start defining your routes here -app.get("/", (req, res) => { - res.send("Hello Technigo!") -}) +// Middleware +app.use(cors()); // Aktivera CORS +app.use(express.json()); // Aktivera JSON-parsing -// Start the server +// 1) Dina vanliga routes +app.get('/', (req, res) => { + const endpoints = expressListEndpoints(app); + res.json(endpoints); +}); +// Exempel på fler routes +app.post('/thoughts', (req, res) => { + // ... lägg till ny todo +}); +app.get('/thoughts', (req, res) => { + // ... returnera alla todos +}); +app.get('/thoughts/:id', (req, res) => { + // ... returnera todo med id +}); + +// Hantera 404 +app.use((req, res) => { + res.status(404).json({ error: 'Not Found' }); +}); + +//Felhantering +app.use((err, req, res, next) => { + console.error('💥 Server Error:', err); + res.status(err.status || 500).json({ + error: err.message || 'Internal Server Error', + }); +}); + +// Starta servern app.listen(port, () => { - console.log(`Server running on http://localhost:${port}`) -}) + console.log(`Server running on http://localhost:${port}`); +}); diff --git a/services/mockData.js b/services/mockData.js new file mode 100644 index 0000000..fb37710 --- /dev/null +++ b/services/mockData.js @@ -0,0 +1,3 @@ +import data from '../data.json'; + +export let thoughts = data.map((item) => ({ ...item })); diff --git a/services/thoughtService.js b/services/thoughtService.js new file mode 100644 index 0000000..f41872c --- /dev/null +++ b/services/thoughtService.js @@ -0,0 +1,46 @@ +import { thoughts } from './mockData'; +import { v4 as uuidv4 } from 'uuid'; + +export function getAllThoughts() { + const thoughtList = [...thoughts]; + return thoughtList; +} + +export function addThought({ message }) { + const newThought = { + _id: uuidv4(), + message: message, + hearts: 0, + createdAt: new Date().toISOString(), + __v: 0, + }; + + thoughts.push(newThought); + return newThought; +} + +export function incrementLike(id) { + const foundThought = thoughts.find((thought) => thought._id === String(id)); + //if the thought is not found, return null + if (!foundThought) return null; + + //else increment the hearts count + foundThought.hearts += 1; + return foundThought; +} + +export function decrementLike(id) { + const foundThought = thoughts.find((thought) => thought._id === String(id)); + //if the thought is not found, return null + if (!foundThought) return null; + + //else decrement the hearts count + if (foundThought.hearts > 0) { + foundThought.hearts -= 1; + } + return foundThought; +} + +export function updateThought(id, updatedThought) {} + +export function removeThought(id) {} From 68f644e3f925d4306118e92295d6de74975e07fe Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Tue, 27 May 2025 11:42:57 +0200 Subject: [PATCH 02/48] All thoughtServices done --- services/thoughtService.js | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/services/thoughtService.js b/services/thoughtService.js index f41872c..01dba5a 100644 --- a/services/thoughtService.js +++ b/services/thoughtService.js @@ -41,6 +41,25 @@ export function decrementLike(id) { return foundThought; } -export function updateThought(id, updatedThought) {} +export function updateThought(id, updatedThought) { + const thought = thoughts.find((thought) => thought._id === String(id)); + if (!thought) return null; -export function removeThought(id) {} + if (updatedThought.message) { + thought.message = updatedThought.message; + } + + thought.__v += 1; + + return thought; +} + +export function removeThought(id) { + const index = thoughts.findIndex((thought) => thought._id === String(id)); + + if (index === -1) return false; + + thoughts.splice(index, 1); + + return true; +} From e48b4be60b9c230cdcab3f750e3627e148a5c377 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Tue, 27 May 2025 12:12:13 +0200 Subject: [PATCH 03/48] Testade mina thoughtServices med assert WOW va grymt --- package.json | 7 +++- server.js | 2 +- services/mockData.js | 7 +++- services/thoughtService.js | 2 +- testService.js | 83 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 testService.js diff --git a/package.json b/package.json index 00addae..1266940 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,11 @@ "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" + "dev": "nodemon server.js --exec babel-node", + "test:service": "node testService.js" }, "author": "", "license": "ISC", @@ -15,6 +17,7 @@ "cors": "^2.8.5", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", - "nodemon": "^3.0.1" + "nodemon": "^3.0.1", + "uuid": "^11.1.0" } } diff --git a/server.js b/server.js index a675a51..c291e6e 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,6 @@ import cors from 'cors'; import express from 'express'; -const expressListEndpoints = require('express-list-endpoints'); +import expressListEndpoints from 'express-list-endpoints'; import dotenv from 'dotenv'; // Ladda in .env-filen diff --git a/services/mockData.js b/services/mockData.js index fb37710..c913399 100644 --- a/services/mockData.js +++ b/services/mockData.js @@ -1,3 +1,8 @@ -import data from '../data.json'; +import fs from 'fs'; +import path from 'path'; + +const dataPath = path.join(process.cwd(), 'data.json'); +const raw = fs.readFileSync(dataPath, 'utf8'); +const data = JSON.parse(raw); export let thoughts = data.map((item) => ({ ...item })); diff --git a/services/thoughtService.js b/services/thoughtService.js index 01dba5a..9ba31a8 100644 --- a/services/thoughtService.js +++ b/services/thoughtService.js @@ -1,4 +1,4 @@ -import { thoughts } from './mockData'; +import { thoughts } from './mockData.js'; import { v4 as uuidv4 } from 'uuid'; export function getAllThoughts() { diff --git a/testService.js b/testService.js new file mode 100644 index 0000000..397b7db --- /dev/null +++ b/testService.js @@ -0,0 +1,83 @@ +import assert from 'assert'; + +import { + getAllThoughts, + addThought, + incrementLike, + decrementLike, + updateThought, + removeThought, +} from './services/thoughtService.js'; + +////////////////////// ASSERT TESTING //////////////////////// + +// 1) Initial count +const before = getAllThoughts().length; + +// 2) Lägg till +const t = addThought({ message: 'Hej på dig' }); +assert.strictEqual( + getAllThoughts().length, + before + 1, + `addThought: förväntar length ${before + 1}, men fick ${ + getAllThoughts().length + }` +); + +// 3) Like +incrementLike(t._id); +assert.strictEqual( + getAllThoughts().find((x) => x._id === t._id).hearts, + 1, + 'incrementLike: hearts borde vara 1' +); + +// 4) Update +updateThought(t._id, { message: 'Uppdaterat!' }); +assert.strictEqual( + getAllThoughts().find((x) => x._id === t._id).message, + 'Uppdaterat!', + 'updateThought: message matchar inte' +); + +// 5) Remove +removeThought(t._id); +assert.strictEqual( + getAllThoughts().some((x) => x._id === t._id), + false, + 'removeThought: ID borde vara borttagen' +); + +console.log('🎉 Alla service-tester gick igenom utan fel!'); + +//////////////////////// MANUAL TESTING //////////////////////// + +// // 1) Börja med en ren mock-array +// console.log('Initial:', getAllThoughts()); + +// // 2) Lägg till en ny +// const newT = addThought({ message: 'Testmeddelande' }); +// console.log('Efter add:', getAllThoughts()); + +// // 3) Gilla och ogilla +// incrementLike(newT._id); +// console.log( +// '✅ Efter +1 like:', +// getAllThoughts().find((t) => t._id === newT._id) +// ); +// decrementLike(newT._id); +// console.log( +// ' ✅ Efter -1 like:', +// getAllThoughts().find((t) => t._id === newT._id) +// ); + +// // 4) Uppdatera +// updateThought(newT._id, { message: 'Uppdaterat meddelande' }); +// console.log( +// ' ✅ Efter update:', +// getAllThoughts().find((t) => t._id === newT._id) +// ); + +// // 5) Ta bort +// removeThought(newT._id); +// console.log(' ✅ Efter remove:', getAllThoughts()); From 03510ad8d4bdb5aa3cd345f7e3fdf39bc56ba4c0 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Wed, 28 May 2025 09:45:57 +0200 Subject: [PATCH 04/48] =?UTF-8?q?=C3=84ndrade=20package.json=20utan=20modu?= =?UTF-8?q?le=20och=20importear=20data=20p=C3=A5=20samma=20s=C3=A4tt=20som?= =?UTF-8?q?=20lektionen=20ig=C3=A5r,=20enklare!=20=C3=84ndrade=20test-scri?= =?UTF-8?q?ptet=20s=C3=A5=20det=20anv=C3=A4nden=20babel.node?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 13 +++++++------ services/mockData.js | 8 +------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 1266940..8643ee4 100644 --- a/package.json +++ b/package.json @@ -2,22 +2,23 @@ "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", - "test:service": "node testService.js" + "test:service": "babel-node testService.js" }, "author": "", "license": "ISC", "dependencies": { - "@babel/core": "^7.17.9", - "@babel/node": "^7.16.8", - "@babel/preset-env": "^7.16.11", "cors": "^2.8.5", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", - "nodemon": "^3.0.1", "uuid": "^11.1.0" + }, + "devDependencies": { + "@babel/core": "^7.27.3", + "@babel/node": "^7.27.1", + "@babel/preset-env": "^7.27.2", + "nodemon": "^3.0.1" } } diff --git a/services/mockData.js b/services/mockData.js index c913399..e203a14 100644 --- a/services/mockData.js +++ b/services/mockData.js @@ -1,8 +1,2 @@ -import fs from 'fs'; -import path from 'path'; - -const dataPath = path.join(process.cwd(), 'data.json'); -const raw = fs.readFileSync(dataPath, 'utf8'); -const data = JSON.parse(raw); - +import data from '../data.json'; export let thoughts = data.map((item) => ({ ...item })); From 2bd403b7c9b2be5d4e1ea5849553ec585b2b577d Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Wed, 28 May 2025 15:39:46 +0200 Subject: [PATCH 05/48] routes for get all thoughts, post createThought, post likeTHought och Patch unLikeThought is done and tested --- routes/happyThoughts.js | 54 +++++++++++++++++++++++++++++++++++++---- server.js | 21 ++++++---------- 2 files changed, 57 insertions(+), 18 deletions(-) diff --git a/routes/happyThoughts.js b/routes/happyThoughts.js index ce1279d..a7aa768 100644 --- a/routes/happyThoughts.js +++ b/routes/happyThoughts.js @@ -1,9 +1,53 @@ import express from 'express'; +import { + getAllThoughts, + addThought, + incrementLike, + decrementLike, + updateThought, + removeThought, +} from '../services/thoughtService.js'; -const router = express.Router(); +const happyRouter = express.Router(); -//kontroller funtkioner/handalers? -function listAllThoughts(req, res) { - // Här skulle du hämta alla tankar från databasen - res.json({ message: 'List of all thoughts' }); +function listAllThoughtsHandler(req, res) { + const allThoughts = getAllThoughts(); + res.json(allThoughts); } + +function addThoughtHandler(req, res) { + const message = addThought(req.body); + res.json(message); +} + +function likeThoughtHandler(req, res) { + const { id } = req.params; + const addLike = incrementLike(id); + + if (!addLike) { + return res + .status(404) + .json({ error: 'Thought not found, could not add your like' }); + } + return res.json(addLike); +} + +function unLikeThoughtHandler(req, res) { + const { id } = req.params; + const unLike = decrementLike(id); + + if (!unLike) { + return res + .status(404) + .json({ error: 'Thought not found, could not unlike your like' }); + } + return res.json(unLike); +} + +//KOMIHÅG ATT URL börjar med /api/thoughts +happyRouter.get('/', listAllThoughtsHandler); +happyRouter.post('/', addThoughtHandler); +happyRouter.post('/:id/like', likeThoughtHandler); +happyRouter.patch('/:id/unlike', unLikeThoughtHandler); + +export default happyRouter; diff --git a/server.js b/server.js index c291e6e..8eb2190 100644 --- a/server.js +++ b/server.js @@ -2,6 +2,7 @@ import cors from 'cors'; import express from 'express'; import expressListEndpoints from 'express-list-endpoints'; import dotenv from 'dotenv'; +import happyRouter from './routes/happyThoughts.js'; // Ladda in .env-filen dotenv.config(); @@ -14,21 +15,15 @@ const app = express(); app.use(cors()); // Aktivera CORS app.use(express.json()); // Aktivera JSON-parsing -// 1) Dina vanliga routes -app.get('/', (req, res) => { +// Rot-endpoint: lista alla endpoints requriement +function ListEndpointsHandler(req, res) { const endpoints = expressListEndpoints(app); res.json(endpoints); -}); -// Exempel på fler routes -app.post('/thoughts', (req, res) => { - // ... lägg till ny todo -}); -app.get('/thoughts', (req, res) => { - // ... returnera alla todos -}); -app.get('/thoughts/:id', (req, res) => { - // ... returnera todo med id -}); +} +app.get('/', ListEndpointsHandler); + +//HappyRouter montering +app.use('/api/thoughts', happyRouter); // Hantera 404 app.use((req, res) => { From eede8e2a53440b196bc8046047416f8880e84e93 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 30 May 2025 11:46:08 +0200 Subject: [PATCH 06/48] added a service for getting one thought, added that one and update and remove thought to HappyRouter --- routes/happyThoughts.js | 40 ++++++++++++++++++++++++++++++++++++++ services/thoughtService.js | 20 +++++++++++++------ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/routes/happyThoughts.js b/routes/happyThoughts.js index a7aa768..c7125fc 100644 --- a/routes/happyThoughts.js +++ b/routes/happyThoughts.js @@ -1,11 +1,13 @@ import express from 'express'; import { getAllThoughts, + getOneThought, addThought, incrementLike, decrementLike, updateThought, removeThought, + deleteThought, } from '../services/thoughtService.js'; const happyRouter = express.Router(); @@ -15,6 +17,15 @@ function listAllThoughtsHandler(req, res) { res.json(allThoughts); } +function getOneThoughtHandler(req, res) { + const { id } = req.params; + const thought = getOneThought(id); + if (!thought) { + return res.status(404).json({ error: 'Thought not found' }); + } + return res.json(thought); +} + function addThoughtHandler(req, res) { const message = addThought(req.body); res.json(message); @@ -44,10 +55,39 @@ function unLikeThoughtHandler(req, res) { return res.json(unLike); } +function updatedThoughtHandler(req, res) { + const { id } = req.params; + const updatedThought = req.body; + + const updated = updateThought(id, updatedThought); + + if (!updated) { + return res.status(404).json({ error: 'Thought not found' }); + } + + return res.json(updated); +} + +function removeThoughtHandler(req, res) { + const { id } = req.params; + const removedThought = removeThought(id); + + if (!removedThought) { + return res.status(404).json({ error: 'Thought not found' }); + } + + return res.json({ + message: `Thought: ${removedThought.message}, removed successfully`, + }); +} + //KOMIHÅG ATT URL börjar med /api/thoughts happyRouter.get('/', listAllThoughtsHandler); +happyRouter.get('/:id', getOneThoughtHandler); happyRouter.post('/', addThoughtHandler); happyRouter.post('/:id/like', likeThoughtHandler); happyRouter.patch('/:id/unlike', unLikeThoughtHandler); +happyRouter.put('/:id', updatedThoughtHandler); +happyRouter.delete('/:id', removeThoughtHandler); export default happyRouter; diff --git a/services/thoughtService.js b/services/thoughtService.js index 9ba31a8..7321805 100644 --- a/services/thoughtService.js +++ b/services/thoughtService.js @@ -19,6 +19,15 @@ export function addThought({ message }) { return newThought; } +export function getOneThought(id) { + if (!id) return null; + + const thought = thoughts.find((thought) => thought._id === String(id)); + if (!thought) return null; + + return thought; +} + export function incrementLike(id) { const foundThought = thoughts.find((thought) => thought._id === String(id)); //if the thought is not found, return null @@ -55,11 +64,10 @@ export function updateThought(id, updatedThought) { } export function removeThought(id) { - const index = thoughts.findIndex((thought) => thought._id === String(id)); - - if (index === -1) return false; - - thoughts.splice(index, 1); + const index = thoughts.findIndex((t) => t._id === String(id)); + if (index === -1) return null; - return true; + // Ta ut objektet från arrayen + const [removed] = thoughts.splice(index, 1); + return removed; // returnera det borttagna objektet } From 0c3d3498db2151872a546afa2a347de35dc10ccd Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 30 May 2025 13:33:15 +0200 Subject: [PATCH 07/48] =?UTF-8?q?Streach=20goal=20regardning=20404=20=20si?= =?UTF-8?q?ngle=E2=80=90item=E2=80=93hantering?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- routes/happyThoughts.js | 18 +++++++--- services/untils.js | 8 +++++ testService.js | 77 +++++++++++++++++++++++++++++++---------- 3 files changed, 81 insertions(+), 22 deletions(-) create mode 100644 services/untils.js diff --git a/routes/happyThoughts.js b/routes/happyThoughts.js index c7125fc..e4ebbfc 100644 --- a/routes/happyThoughts.js +++ b/routes/happyThoughts.js @@ -7,8 +7,8 @@ import { decrementLike, updateThought, removeThought, - deleteThought, } from '../services/thoughtService.js'; +import { findByPrefix } from '../services/untils'; const happyRouter = express.Router(); @@ -21,7 +21,16 @@ function getOneThoughtHandler(req, res) { const { id } = req.params; const thought = getOneThought(id); if (!thought) { - return res.status(404).json({ error: 'Thought not found' }); + const allIds = getAllThoughts().map((t) => t._id); + const suggestion = findByPrefix(id, allIds, 4); + + return res.status(404).json({ + error: 'Thought not found', + requestedId: id, + suggestion: suggestion + ? `Did you mean ${suggestion}?` + : 'Could not find a suggested ID', + }); } return res.json(thought); } @@ -78,6 +87,7 @@ function removeThoughtHandler(req, res) { return res.json({ message: `Thought: ${removedThought.message}, removed successfully`, + removedThought: removedThought, }); } @@ -85,8 +95,8 @@ function removeThoughtHandler(req, res) { happyRouter.get('/', listAllThoughtsHandler); happyRouter.get('/:id', getOneThoughtHandler); happyRouter.post('/', addThoughtHandler); -happyRouter.post('/:id/like', likeThoughtHandler); -happyRouter.patch('/:id/unlike', unLikeThoughtHandler); +happyRouter.post('/:id/likes', likeThoughtHandler); +happyRouter.delete('/:id/likes', unLikeThoughtHandler); happyRouter.put('/:id', updatedThoughtHandler); happyRouter.delete('/:id', removeThoughtHandler); diff --git a/services/untils.js b/services/untils.js new file mode 100644 index 0000000..994b98d --- /dev/null +++ b/services/untils.js @@ -0,0 +1,8 @@ +// Hittar första ID som delar prefix med targetId. +export function findByPrefix(targetId, allIds, prefixLength = 4) { + // Ta de första prefixLength tecknen från det inskickade ID:t + const prefix = targetId.slice(0, prefixLength); + + // Leta bland alla giltiga ID:n efter en som börjar med samma prefix + return allIds.find((id) => id.startsWith(prefix)) || null; +} diff --git a/testService.js b/testService.js index 397b7db..013f38e 100644 --- a/testService.js +++ b/testService.js @@ -2,6 +2,7 @@ import assert from 'assert'; import { getAllThoughts, + getOneThought, addThought, incrementLike, decrementLike, @@ -12,40 +13,80 @@ import { ////////////////////// ASSERT TESTING //////////////////////// // 1) Initial count -const before = getAllThoughts().length; +const initialCount = getAllThoughts().length; -// 2) Lägg till -const t = addThought({ message: 'Hej på dig' }); +// 2) Lägg till en ny thought +const newThought = addThought({ message: 'Test thought' }); assert.strictEqual( getAllThoughts().length, - before + 1, - `addThought: förväntar length ${before + 1}, men fick ${ + initialCount + 1, + `addThought: förväntade length ${initialCount + 1}, men fick ${ getAllThoughts().length }` ); -// 3) Like -incrementLike(t._id); +// 3) Hämta just den thought +const fetched = getOneThought(newThought._id); +assert.ok(fetched, 'getOneThought: thought ska finnas'); assert.strictEqual( - getAllThoughts().find((x) => x._id === t._id).hearts, + fetched.message, + 'Test thought', + `getOneThought: förväntade message 'Test thought', men fick '${fetched.message}'` +); + +// 4) Testa incrementLike +incrementLike(newThought._id); +assert.strictEqual( + getOneThought(newThought._id).hearts, 1, 'incrementLike: hearts borde vara 1' ); -// 4) Update -updateThought(t._id, { message: 'Uppdaterat!' }); +// 5) Testa decrementLike (får inte gå under 0) +decrementLike(newThought._id); +assert.strictEqual( + getOneThought(newThought._id).hearts, + 0, + 'decrementLike: hearts borde vara tillbaka till 0' +); +decrementLike(newThought._id); // ytterligare en decrement assert.strictEqual( - getAllThoughts().find((x) => x._id === t._id).message, - 'Uppdaterat!', - 'updateThought: message matchar inte' + getOneThought(newThought._id).hearts, + 0, + 'decrementLike: hearts borde inte gå under 0' ); -// 5) Remove -removeThought(t._id); +// 6) Testa updateThought +updateThought(newThought._id, { message: 'Updated thought' }); assert.strictEqual( - getAllThoughts().some((x) => x._id === t._id), - false, - 'removeThought: ID borde vara borttagen' + getOneThought(newThought._id).message, + 'Updated thought', + 'updateThought: message uppdaterades inte korrekt' +); + +// 7) Testa removeThought +const removed = removeThought(newThought._id); + +// 7.1) Förväntar oss ett objekt, inte bara true +assert.ok( + removed && removed._id === newThought._id, + `removeThought: förväntade borttaget objekt med _id ${newThought._id}, men fick ${removed}` +); + +// 7.2) Efter borttagningen ska getOneThought ge null +assert.strictEqual( + getOneThought(newThought._id), + null, + 'getOneThought: borde returnera null för borttagen thought' +); + +// 7.3) Totalt antal ska ha minskat med 1 (till initialCount igen) +assert.strictEqual( + getAllThoughts().length, + initialCount, + `removeThought: förväntade length ${initialCount}, men fick ${ + getAllThoughts().length + }` ); console.log('🎉 Alla service-tester gick igenom utan fel!'); From d575cca3582f0f6b0777f76edce6483a228e97c1 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 30 May 2025 13:55:45 +0200 Subject: [PATCH 08/48] paginate implemeted --- routes/happyThoughts.js | 20 ++++++++++++++++++-- services/untils.js | 25 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/routes/happyThoughts.js b/routes/happyThoughts.js index e4ebbfc..6e97b04 100644 --- a/routes/happyThoughts.js +++ b/routes/happyThoughts.js @@ -8,13 +8,29 @@ import { updateThought, removeThought, } from '../services/thoughtService.js'; -import { findByPrefix } from '../services/untils'; +import { findByPrefix, paginate } from '../services/untils'; const happyRouter = express.Router(); function listAllThoughtsHandler(req, res) { + const requestedPage = Number(req.query.page) || 1; const allThoughts = getAllThoughts(); - res.json(allThoughts); + + // Paginerings‐util returnerar page, perPage, total, totalPages och results + const { page, perPage, total, totalPages, results } = paginate( + allThoughts, + requestedPage, + 10 + ); + + // Skicka tillbaka metadata och själva sidan med tankar + res.json({ + page, // aktuell sida (1-baserad) + perPage, // antal items per sida (10) + total, // totalt antal tankar + totalPages, // hur många sidor som finns + results, // array med tankar för just den här sidan + }); } function getOneThoughtHandler(req, res) { diff --git a/services/untils.js b/services/untils.js index 994b98d..dc02c81 100644 --- a/services/untils.js +++ b/services/untils.js @@ -1,3 +1,5 @@ +//Made from ChatGPT + // Hittar första ID som delar prefix med targetId. export function findByPrefix(targetId, allIds, prefixLength = 4) { // Ta de första prefixLength tecknen från det inskickade ID:t @@ -6,3 +8,26 @@ export function findByPrefix(targetId, allIds, prefixLength = 4) { // Leta bland alla giltiga ID:n efter en som börjar med samma prefix return allIds.find((id) => id.startsWith(prefix)) || null; } + +// Paginerar en array genom att returnera både metadata och de paginerade resultaten. +export function paginate(items, page = 1, perPage = 10) { + // Räkna totalt antal items + const total = items.length; + // Beräkna hur många sidor det blir totalt + const totalPages = Math.ceil(total / perPage); + // Säkerställ att sidan är mellan 1 och totalPages + const safePage = Math.min(Math.max(1, page), totalPages); + // Beräkna startindex för slice + const start = (safePage - 1) * perPage; + // Skapa den delmängd av items som tillhör den här sidan + const results = items.slice(start, start + perPage); + + // Returnera objekt med både sidmetadata och resultaten + return { + page: safePage, + perPage, + total, + totalPages, + results, + }; +} From 4a7566f8956f237655b192d826b9024edb7572f6 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 30 May 2025 14:29:18 +0200 Subject: [PATCH 09/48] sorting works --- routes/happyThoughts.js | 29 ++++++++++++++------------ services/untils.js | 46 +++++++++++++++++++++++++++-------------- 2 files changed, 46 insertions(+), 29 deletions(-) diff --git a/routes/happyThoughts.js b/routes/happyThoughts.js index 6e97b04..1cef00d 100644 --- a/routes/happyThoughts.js +++ b/routes/happyThoughts.js @@ -8,28 +8,31 @@ import { updateThought, removeThought, } from '../services/thoughtService.js'; -import { findByPrefix, paginate } from '../services/untils'; +import { findByPrefix, paginate, sortItems } from '../services/untils'; const happyRouter = express.Router(); function listAllThoughtsHandler(req, res) { - const requestedPage = Number(req.query.page) || 1; - const allThoughts = getAllThoughts(); + let allThoughts = getAllThoughts(); + + // Om klienten begär sortering, anropa utils direkt med både fält och råparam + if (req.query.sortBy) { + allThoughts = sortItems(allThoughts, req.query.sortBy, req.query.sortDir); + } - // Paginerings‐util returnerar page, perPage, total, totalPages och results const { page, perPage, total, totalPages, results } = paginate( allThoughts, - requestedPage, - 10 + req.query.page, + req.query.perPage ); - - // Skicka tillbaka metadata och själva sidan med tankar res.json({ - page, // aktuell sida (1-baserad) - perPage, // antal items per sida (10) - total, // totalt antal tankar - totalPages, // hur många sidor som finns - results, // array med tankar för just den här sidan + page, + perPage, + total, + totalPages, + sortBy: req.query.sortBy || null, + sortDir: req.query.sortDir === 'ascending' ? 'ascending' : 'descending', + results, }); } diff --git a/services/untils.js b/services/untils.js index dc02c81..1864c2b 100644 --- a/services/untils.js +++ b/services/untils.js @@ -1,6 +1,6 @@ //Made from ChatGPT -// Hittar första ID som delar prefix med targetId. +// Hittar suggested id att använda vid felaktigt id export function findByPrefix(targetId, allIds, prefixLength = 4) { // Ta de första prefixLength tecknen från det inskickade ID:t const prefix = targetId.slice(0, prefixLength); @@ -10,24 +10,38 @@ export function findByPrefix(targetId, allIds, prefixLength = 4) { } // Paginerar en array genom att returnera både metadata och de paginerade resultaten. -export function paginate(items, page = 1, perPage = 10) { - // Räkna totalt antal items +export function paginate(items, pageParam = 1, perPageParam = 10) { + // 1) Tolka parametrarna till tal (default 1 och 10) + const requestedPage = Number(pageParam) || 1; + const perPage = Number(perPageParam) || 10; + + // 2) Totalt antal items const total = items.length; - // Beräkna hur många sidor det blir totalt + // 3) Totalt antal sidor (rundar alltid upp) const totalPages = Math.ceil(total / perPage); - // Säkerställ att sidan är mellan 1 och totalPages - const safePage = Math.min(Math.max(1, page), totalPages); - // Beräkna startindex för slice + // 4) Säker sida inom spannet [1, totalPages] + const safePage = Math.min(Math.max(1, pageParam), totalPages); + // 5) Beräkna startindex och skär ut resultat const start = (safePage - 1) * perPage; - // Skapa den delmängd av items som tillhör den här sidan const results = items.slice(start, start + perPage); - // Returnera objekt med både sidmetadata och resultaten - return { - page: safePage, - perPage, - total, - totalPages, - results, - }; + // 6) Returnera metadata + resultat + return { pageParam, perPage, total, totalPages, results }; +} + +export function sortItems(items, key, directionParam) { + // Bestäm riktning: om directionParam === 'ascending' → 'ascending', annars 'descending' + const direction = directionParam === 'ascending' ? 'ascending' : 'descending'; + const dir = direction === 'ascending' ? 1 : -1; + + // Gör en kopia så vi inte muterar originalet + const arr = [...items]; + + arr.sort((a, b) => { + if (a[key] < b[key]) return -1 * dir; + if (a[key] > b[key]) return 1 * dir; + return 0; + }); + + return arr; } From f6c02870840c36ba976e23c61ebd4950d2e00622 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 30 May 2025 14:35:16 +0200 Subject: [PATCH 10/48] added link to render.com sajten --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0f9f073..8070b3a 100644 --- a/README.md +++ b/README.md @@ -8,4 +8,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. +[Hola-Happy-Server](https://hola-happy-server.onrender.com) From f3c9678b3eb05213e42b3e610ab99693d1fd2a85 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 30 May 2025 14:44:02 +0200 Subject: [PATCH 11/48] added dotenv --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 8643ee4..22ada77 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "license": "ISC", "dependencies": { "cors": "^2.8.5", + "dotenv": "^16.5.0", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", "uuid": "^11.1.0" From 4e6e3b6f82270da9c6fe2c5c5180cbcbde24bcb2 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Tue, 3 Jun 2025 14:48:20 +0200 Subject: [PATCH 12/48] just started to add moongoose things but realised that I want to refactoring to have controller-folder. brb. --- models/Thoughts.js | 0 server.js | 8 ++++++++ 2 files changed, 8 insertions(+) create mode 100644 models/Thoughts.js diff --git a/models/Thoughts.js b/models/Thoughts.js new file mode 100644 index 0000000..e69de29 diff --git a/server.js b/server.js index 8eb2190..ce05b8b 100644 --- a/server.js +++ b/server.js @@ -3,9 +3,17 @@ import express from 'express'; import expressListEndpoints from 'express-list-endpoints'; import dotenv from 'dotenv'; import happyRouter from './routes/happyThoughts.js'; +import mongoose from 'mongoose'; +import { Thought } from './models/Thought.js'; // Ladda in .env-filen dotenv.config(); + +//Mongoose setup +const mongoUrl = process.env.MONGO_URL || 'mongodb://localhost/happyThoughts'; +mongoose.connect(mongoUrl); +mongoose.connection.on('connected', () => console.log('MongoDB connected')); + const port = process.env.PORT || 8080; // Skapa en Express-app From 2746036ce70c562a4a0264d4e60c0a46b23a801d Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Tue, 3 Jun 2025 15:12:17 +0200 Subject: [PATCH 13/48] refactored the code to have controllers --- controllers/thoughtController.js | 109 +++++++++++++++++++++++++++++++ models/Thoughts.js | 0 routes/happyThoughts.js | 107 ++---------------------------- server.js | 6 -- 4 files changed, 113 insertions(+), 109 deletions(-) create mode 100644 controllers/thoughtController.js delete mode 100644 models/Thoughts.js diff --git a/controllers/thoughtController.js b/controllers/thoughtController.js new file mode 100644 index 0000000..15b090a --- /dev/null +++ b/controllers/thoughtController.js @@ -0,0 +1,109 @@ +import express from 'express'; +import { + getAllThoughts, + getOneThought, + addThought, + incrementLike, + decrementLike, + updateThought, + removeThought, +} from '../services/thoughtService.js'; +import { findByPrefix, paginate, sortItems } from '../services/untils'; + +function listAllThoughtsHandler(req, res) { + let allThoughts = getAllThoughts(); + + // Om klienten begär sortering, anropa utils direkt med både fält och råparam + if (req.query.sortBy) { + allThoughts = sortItems(allThoughts, req.query.sortBy, req.query.sortDir); + } + + const { page, perPage, total, totalPages, results } = paginate( + allThoughts, + req.query.page, + req.query.perPage + ); + res.json({ + page, + perPage, + total, + totalPages, + sortBy: req.query.sortBy || null, + sortDir: req.query.sortDir === 'ascending' ? 'ascending' : 'descending', + results, + }); +} + +function getOneThoughtHandler(req, res) { + const { id } = req.params; + const thought = getOneThought(id); + if (!thought) { + const allIds = getAllThoughts().map((t) => t._id); + const suggestion = findByPrefix(id, allIds, 4); + + return res.status(404).json({ + error: 'Thought not found', + requestedId: id, + suggestion: suggestion + ? `Did you mean ${suggestion}?` + : 'Could not find a suggested ID', + }); + } + return res.json(thought); +} + +function addThoughtHandler(req, res) { + const message = addThought(req.body); + res.json(message); +} + +function likeThoughtHandler(req, res) { + const { id } = req.params; + const addLike = incrementLike(id); + + if (!addLike) { + return res + .status(404) + .json({ error: 'Thought not found, could not add your like' }); + } + return res.json(addLike); +} + +function unLikeThoughtHandler(req, res) { + const { id } = req.params; + const unLike = decrementLike(id); + + if (!unLike) { + return res + .status(404) + .json({ error: 'Thought not found, could not unlike your like' }); + } + return res.json(unLike); +} + +function updatedThoughtHandler(req, res) { + const { id } = req.params; + const updatedThought = req.body; + + const updated = updateThought(id, updatedThought); + + if (!updated) { + return res.status(404).json({ error: 'Thought not found' }); + } + + return res.json(updated); +} + +function removeThoughtHandler(req, res) { + const { id } = req.params; + const removedThought = removeThought(id); + + if (!removedThought) { + return res.status(404).json({ error: 'Thought not found' }); + } + + return res.json({ + message: `Thought: ${removedThought.message}, removed successfully`, + removedThought: removedThought, + }); +} diff --git a/models/Thoughts.js b/models/Thoughts.js deleted file mode 100644 index e69de29..0000000 diff --git a/routes/happyThoughts.js b/routes/happyThoughts.js index 1cef00d..8a31e43 100644 --- a/routes/happyThoughts.js +++ b/routes/happyThoughts.js @@ -1,115 +1,16 @@ import express from 'express'; import { - getAllThoughts, + listAllThoughts, getOneThought, addThought, - incrementLike, - decrementLike, + likeThought, + unLikeThought, updateThought, removeThought, -} from '../services/thoughtService.js'; -import { findByPrefix, paginate, sortItems } from '../services/untils'; +} from '../controllers/thoughtController.js'; const happyRouter = express.Router(); -function listAllThoughtsHandler(req, res) { - let allThoughts = getAllThoughts(); - - // Om klienten begär sortering, anropa utils direkt med både fält och råparam - if (req.query.sortBy) { - allThoughts = sortItems(allThoughts, req.query.sortBy, req.query.sortDir); - } - - const { page, perPage, total, totalPages, results } = paginate( - allThoughts, - req.query.page, - req.query.perPage - ); - res.json({ - page, - perPage, - total, - totalPages, - sortBy: req.query.sortBy || null, - sortDir: req.query.sortDir === 'ascending' ? 'ascending' : 'descending', - results, - }); -} - -function getOneThoughtHandler(req, res) { - const { id } = req.params; - const thought = getOneThought(id); - if (!thought) { - const allIds = getAllThoughts().map((t) => t._id); - const suggestion = findByPrefix(id, allIds, 4); - - return res.status(404).json({ - error: 'Thought not found', - requestedId: id, - suggestion: suggestion - ? `Did you mean ${suggestion}?` - : 'Could not find a suggested ID', - }); - } - return res.json(thought); -} - -function addThoughtHandler(req, res) { - const message = addThought(req.body); - res.json(message); -} - -function likeThoughtHandler(req, res) { - const { id } = req.params; - const addLike = incrementLike(id); - - if (!addLike) { - return res - .status(404) - .json({ error: 'Thought not found, could not add your like' }); - } - return res.json(addLike); -} - -function unLikeThoughtHandler(req, res) { - const { id } = req.params; - const unLike = decrementLike(id); - - if (!unLike) { - return res - .status(404) - .json({ error: 'Thought not found, could not unlike your like' }); - } - return res.json(unLike); -} - -function updatedThoughtHandler(req, res) { - const { id } = req.params; - const updatedThought = req.body; - - const updated = updateThought(id, updatedThought); - - if (!updated) { - return res.status(404).json({ error: 'Thought not found' }); - } - - return res.json(updated); -} - -function removeThoughtHandler(req, res) { - const { id } = req.params; - const removedThought = removeThought(id); - - if (!removedThought) { - return res.status(404).json({ error: 'Thought not found' }); - } - - return res.json({ - message: `Thought: ${removedThought.message}, removed successfully`, - removedThought: removedThought, - }); -} - //KOMIHÅG ATT URL börjar med /api/thoughts happyRouter.get('/', listAllThoughtsHandler); happyRouter.get('/:id', getOneThoughtHandler); diff --git a/server.js b/server.js index ce05b8b..e2ca79e 100644 --- a/server.js +++ b/server.js @@ -4,16 +4,10 @@ import expressListEndpoints from 'express-list-endpoints'; import dotenv from 'dotenv'; import happyRouter from './routes/happyThoughts.js'; import mongoose from 'mongoose'; -import { Thought } from './models/Thought.js'; // Ladda in .env-filen dotenv.config(); -//Mongoose setup -const mongoUrl = process.env.MONGO_URL || 'mongodb://localhost/happyThoughts'; -mongoose.connect(mongoUrl); -mongoose.connection.on('connected', () => console.log('MongoDB connected')); - const port = process.env.PORT || 8080; // Skapa en Express-app From 7c46cb5fe0eadfff5a9594f7a2deea914c1fd7b7 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Tue, 3 Jun 2025 15:18:31 +0200 Subject: [PATCH 14/48] installed mongoose --- package.json | 1 + server.js | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/package.json b/package.json index 22ada77..f588e89 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "dotenv": "^16.5.0", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", + "mongoose": "^8.15.1", "uuid": "^11.1.0" }, "devDependencies": { diff --git a/server.js b/server.js index e2ca79e..60d2c6a 100644 --- a/server.js +++ b/server.js @@ -8,6 +8,11 @@ import mongoose from 'mongoose'; // Ladda in .env-filen dotenv.config(); +const mongoUrl = + process.env.MONGO_URL || 'mongodb://127.0.0.1:27017/happyThoughts'; +mongoose.connect(mongoUrl); +mongoose.connection.on('connected', () => console.log('Connected to MongoDB')); + const port = process.env.PORT || 8080; // Skapa en Express-app From 9d9ae8a46b43849cb07f31603f4ba9701ae57123 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Tue, 3 Jun 2025 15:19:16 +0200 Subject: [PATCH 15/48] test --- server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server.js b/server.js index 60d2c6a..222d612 100644 --- a/server.js +++ b/server.js @@ -8,6 +8,7 @@ import mongoose from 'mongoose'; // Ladda in .env-filen dotenv.config(); +//moongoose const mongoUrl = process.env.MONGO_URL || 'mongodb://127.0.0.1:27017/happyThoughts'; mongoose.connect(mongoUrl); From 435e0ed1d18dbdbd2427f1549ad5b298cdf0c17b Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Wed, 4 Jun 2025 13:11:59 +0200 Subject: [PATCH 16/48] installed mondodb and added info to README --- README.md | 36 +++++- controllers/thoughtController.js | 191 ++++++++++++++----------------- models/Thoughts.js | 20 ++++ routes/happyThoughts.js | 26 ++--- 4 files changed, 152 insertions(+), 121 deletions(-) create mode 100644 models/Thoughts.js diff --git a/README.md b/README.md index 8070b3a..5d208e5 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,39 @@ -# Project API +# 🧠 Projekt: Happy Thoughts API – Startguide -This project includes the packages and babel setup for an express server, and is just meant to make things a little simpler to get up and running with. +## ✅ Terminalkommandon att köra när du öppnar projektet -## Getting started +1. Navigera till projektmappen: -Install dependencies with `npm install`, then start the server by running `npm run dev` +```bash +cd ~/Documents/Technigo/js-project-api +``` + +2. Installera dependencies (endast första gången eller efter nytt paket): + +```bash +npm install +``` + +3. Starta MongoDB-tjänsten via Homebrew (om den inte redan är igång): + +```bash +brew services start mongodb/brew/mongodb-community +``` + +4. Kontrollera att MongoDB körs: + +```bash +brew services list +``` + +→ Du ska se: `mongodb-community started` + +5. Starta din backend-server: + +```bash +npm run dev ## View it live [Hola-Happy-Server](https://hola-happy-server.onrender.com) +``` diff --git a/controllers/thoughtController.js b/controllers/thoughtController.js index 15b090a..f74418b 100644 --- a/controllers/thoughtController.js +++ b/controllers/thoughtController.js @@ -1,109 +1,92 @@ import express from 'express'; -import { - getAllThoughts, - getOneThought, - addThought, - incrementLike, - decrementLike, - updateThought, - removeThought, -} from '../services/thoughtService.js'; -import { findByPrefix, paginate, sortItems } from '../services/untils'; - -function listAllThoughtsHandler(req, res) { - let allThoughts = getAllThoughts(); - - // Om klienten begär sortering, anropa utils direkt med både fält och råparam - if (req.query.sortBy) { - allThoughts = sortItems(allThoughts, req.query.sortBy, req.query.sortDir); - } - - const { page, perPage, total, totalPages, results } = paginate( - allThoughts, - req.query.page, - req.query.perPage - ); - res.json({ - page, - perPage, - total, - totalPages, - sortBy: req.query.sortBy || null, - sortDir: req.query.sortDir === 'ascending' ? 'ascending' : 'descending', - results, - }); -} - -function getOneThoughtHandler(req, res) { - const { id } = req.params; - const thought = getOneThought(id); - if (!thought) { - const allIds = getAllThoughts().map((t) => t._id); - const suggestion = findByPrefix(id, allIds, 4); - - return res.status(404).json({ - error: 'Thought not found', - requestedId: id, - suggestion: suggestion - ? `Did you mean ${suggestion}?` - : 'Could not find a suggested ID', - }); - } - return res.json(thought); -} - -function addThoughtHandler(req, res) { - const message = addThought(req.body); - res.json(message); -} - -function likeThoughtHandler(req, res) { - const { id } = req.params; - const addLike = incrementLike(id); - - if (!addLike) { - return res - .status(404) - .json({ error: 'Thought not found, could not add your like' }); - } - return res.json(addLike); -} - -function unLikeThoughtHandler(req, res) { - const { id } = req.params; - const unLike = decrementLike(id); - - if (!unLike) { - return res - .status(404) - .json({ error: 'Thought not found, could not unlike your like' }); - } - return res.json(unLike); -} - -function updatedThoughtHandler(req, res) { - const { id } = req.params; - const updatedThought = req.body; - - const updated = updateThought(id, updatedThought); +import { Thought } from '../models/Thoughts'; - if (!updated) { - return res.status(404).json({ error: 'Thought not found' }); - } - - return res.json(updated); -} +export const listAllThoughts = async (req, res) => { + try { + const sortBy = req.query.sortBy || 'createdAt'; + const sortDir = req.query.sortDir === 'ascending' ? 1 : -1; -function removeThoughtHandler(req, res) { - const { id } = req.params; - const removedThought = removeThought(id); + const thoughts = await Thought.find() + .sort({ [sortBy]: sortDir }) // <– dynamisk sortering + .limit(20); - if (!removedThought) { - return res.status(404).json({ error: 'Thought not found' }); + res.json(thoughts); + } catch (error) { + console.error('Mongoose error:', error); + res.status(500).json({ error: 'Could not fetch thoughts from database' }); } - - return res.json({ - message: `Thought: ${removedThought.message}, removed successfully`, - removedThought: removedThought, - }); -} +}; + +// function getOneThoughtHandler(req, res) { +// const { id } = req.params; +// const thought = getOneThought(id); +// if (!thought) { +// const allIds = getAllThoughts().map((t) => t._id); +// const suggestion = findByPrefix(id, allIds, 4); + +// return res.status(404).json({ +// error: 'Thought not found', +// requestedId: id, +// suggestion: suggestion +// ? `Did you mean ${suggestion}?` +// : 'Could not find a suggested ID', +// }); +// } +// return res.json(thought); +// } + +// function addThoughtHandler(req, res) { +// const message = addThought(req.body); +// res.json(message); +// } + +// function likeThoughtHandler(req, res) { +// const { id } = req.params; +// const addLike = incrementLike(id); + +// if (!addLike) { +// return res +// .status(404) +// .json({ error: 'Thought not found, could not add your like' }); +// } +// return res.json(addLike); +// } + +// function unLikeThoughtHandler(req, res) { +// const { id } = req.params; +// const unLike = decrementLike(id); + +// if (!unLike) { +// return res +// .status(404) +// .json({ error: 'Thought not found, could not unlike your like' }); +// } +// return res.json(unLike); +// } + +// function updatedThoughtHandler(req, res) { +// const { id } = req.params; +// const updatedThought = req.body; + +// const updated = updateThought(id, updatedThought); + +// if (!updated) { +// return res.status(404).json({ error: 'Thought not found' }); +// } + +// return res.json(updated); +// } + +// function removeThoughtHandler(req, res) { +// const { id } = req.params; +// const removedThought = removeThought(id); + +// if (!removedThought) { +// return res.status(404).json({ error: 'Thought not found' }); +// } + +// return res.json({ +// message: `Thought: ${removedThought.message}, removed successfully`, +// removedThought: removedThought, +// }); +// } diff --git a/models/Thoughts.js b/models/Thoughts.js new file mode 100644 index 0000000..ca7cd45 --- /dev/null +++ b/models/Thoughts.js @@ -0,0 +1,20 @@ +import mongoose from 'mongoose'; + +const thoughtSchema = new mongoose.Schema({ + message: { + type: String, + required: true, + minlength: 5, + maxlength: 140, + }, + hearts: { + type: Number, + default: 0, + }, + createdAt: { + type: Date, + default: () => new Date(), // ger dagens datum + }, +}); + +export const Thought = mongoose.model('Thought', thoughtSchema); diff --git a/routes/happyThoughts.js b/routes/happyThoughts.js index 8a31e43..c033411 100644 --- a/routes/happyThoughts.js +++ b/routes/happyThoughts.js @@ -1,23 +1,23 @@ import express from 'express'; import { listAllThoughts, - getOneThought, - addThought, - likeThought, - unLikeThought, - updateThought, - removeThought, + // getOneThought, + // addThought, + // likeThought, + // unLikeThought, + // updateThought, + // removeThought, } from '../controllers/thoughtController.js'; const happyRouter = express.Router(); //KOMIHÅG ATT URL börjar med /api/thoughts -happyRouter.get('/', listAllThoughtsHandler); -happyRouter.get('/:id', getOneThoughtHandler); -happyRouter.post('/', addThoughtHandler); -happyRouter.post('/:id/likes', likeThoughtHandler); -happyRouter.delete('/:id/likes', unLikeThoughtHandler); -happyRouter.put('/:id', updatedThoughtHandler); -happyRouter.delete('/:id', removeThoughtHandler); +happyRouter.get('/', listAllThoughts); +// happyRouter.get('/:id', getOneThought); +// happyRouter.post('/', addThought); +// happyRouter.post('/:id/likes', likeThought); +// happyRouter.delete('/:id/likes', unLikeThought); +// happyRouter.put('/:id', updateThought); +// happyRouter.delete('/:id', removeThought); export default happyRouter; From e02ae736e109c1622b747886a696fa5bed5eaac7 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Wed, 4 Jun 2025 14:16:11 +0200 Subject: [PATCH 17/48] refactored getAllThoughts, getOneThought, like and unlike --- controllers/thoughtController.js | 117 ++++++++++++++++++++----------- routes/happyThoughts.js | 16 ++--- server.js | 14 ++++ services/thoughtService.js | 73 ------------------- 4 files changed, 98 insertions(+), 122 deletions(-) delete mode 100644 services/thoughtService.js diff --git a/controllers/thoughtController.js b/controllers/thoughtController.js index f74418b..885e9b3 100644 --- a/controllers/thoughtController.js +++ b/controllers/thoughtController.js @@ -17,52 +17,87 @@ export const listAllThoughts = async (req, res) => { } }; -// function getOneThoughtHandler(req, res) { -// const { id } = req.params; -// const thought = getOneThought(id); -// if (!thought) { -// const allIds = getAllThoughts().map((t) => t._id); -// const suggestion = findByPrefix(id, allIds, 4); - -// return res.status(404).json({ -// error: 'Thought not found', -// requestedId: id, -// suggestion: suggestion -// ? `Did you mean ${suggestion}?` -// : 'Could not find a suggested ID', -// }); -// } -// return res.json(thought); -// } +export const getOneThought = async (req, res) => { + const { id } = req.params; -// function addThoughtHandler(req, res) { -// const message = addThought(req.body); -// res.json(message); -// } + try { + const thought = await Thought.findById(id); + + if (!thought) { + return res.status(404).json({ + error: 'Thought not found', + requestedId: id, + }); + } + res.json(thought); + } catch (error) { + console.error('Mongoose error on getOneThought:', error); + res.status(400).json({ error: 'Invalid ID format or other error' }); + } +}; -// function likeThoughtHandler(req, res) { -// const { id } = req.params; -// const addLike = incrementLike(id); +export const addThought = async (req, res) => { + const { message } = req.body; + try { + const newThought = await Thought.create({ message }); + res.status(201).json(newThought); + } catch (error) { + console.error('Mongoose error on addThought:', error); + if (error.name === 'ValidationError') { + res + .status(400) + .json({ error: 'Validation failed', details: error.errors }); + } else { + res.status(400).json({ error: 'Could not add your thought' }); + } + } +}; -// if (!addLike) { -// return res -// .status(404) -// .json({ error: 'Thought not found, could not add your like' }); -// } -// return res.json(addLike); -// } +export const likeThought = async (req, res) => { + const { id } = req.params; + try { + const updatedThought = await Thought.findByIdAndUpdate( + id, + { $inc: { hearts: 1 } }, // 💥 Mongoose "increment" + { new: true } // returnera det uppdaterade dokumentet + ); + + if (!updatedThought) { + return res + .status(404) + .json({ error: 'Thought not found, could not add your like' }); + } + + res.json(updatedThought); + } catch (error) { + console.error('Mongoose error on likeThought:', error); + res.status(400).json({ error: 'Invalid ID format or other error' }); + } +}; -// function unLikeThoughtHandler(req, res) { -// const { id } = req.params; -// const unLike = decrementLike(id); +export const unLikeThought = async (req, res) => { + const { id } = req.params; -// if (!unLike) { -// return res -// .status(404) -// .json({ error: 'Thought not found, could not unlike your like' }); -// } -// return res.json(unLike); -// } + try { + const thought = await Thought.findById(id); + + if (!thought) { + return res + .status(404) + .json({ error: 'Thought not found, could not unlike' }); + } + + if (thought.hearts > 0) { + thought.hearts -= 1; + await thought.save(); + } + + res.json(thought); + } catch (error) { + console.error('Mongoose error on unLikeThought:', error); + res.status(400).json({ error: 'Invalid ID format or other error' }); + } +}; // function updatedThoughtHandler(req, res) { // const { id } = req.params; diff --git a/routes/happyThoughts.js b/routes/happyThoughts.js index c033411..50687ca 100644 --- a/routes/happyThoughts.js +++ b/routes/happyThoughts.js @@ -1,10 +1,10 @@ import express from 'express'; import { listAllThoughts, - // getOneThought, - // addThought, - // likeThought, - // unLikeThought, + getOneThought, + addThought, + likeThought, + unLikeThought, // updateThought, // removeThought, } from '../controllers/thoughtController.js'; @@ -13,10 +13,10 @@ const happyRouter = express.Router(); //KOMIHÅG ATT URL börjar med /api/thoughts happyRouter.get('/', listAllThoughts); -// happyRouter.get('/:id', getOneThought); -// happyRouter.post('/', addThought); -// happyRouter.post('/:id/likes', likeThought); -// happyRouter.delete('/:id/likes', unLikeThought); +happyRouter.get('/:id', getOneThought); +happyRouter.post('/', addThought); +happyRouter.post('/:id/likes', likeThought); +happyRouter.delete('/:id/likes', unLikeThought); // happyRouter.put('/:id', updateThought); // happyRouter.delete('/:id', removeThought); diff --git a/server.js b/server.js index 222d612..3ba4764 100644 --- a/server.js +++ b/server.js @@ -4,6 +4,8 @@ import expressListEndpoints from 'express-list-endpoints'; import dotenv from 'dotenv'; import happyRouter from './routes/happyThoughts.js'; import mongoose from 'mongoose'; +import data from './data.json'; +import { Thought } from './models/Thoughts.js'; // Ladda in .env-filen dotenv.config(); @@ -16,6 +18,18 @@ mongoose.connection.on('connected', () => console.log('Connected to MongoDB')); const port = process.env.PORT || 8080; +// const seedDatabase = async () => { +// try { +// await Thought.deleteMany(); // Rensa tidigare innehåll +// await Thought.insertMany(data); // in med nya tankar +// console.log('Database seeded with thoughts!'); +// } catch (error) { +// console.error('Error seeding database:', error); +// } +// }; + +// seedDatabase(); + // Skapa en Express-app const app = express(); diff --git a/services/thoughtService.js b/services/thoughtService.js deleted file mode 100644 index 7321805..0000000 --- a/services/thoughtService.js +++ /dev/null @@ -1,73 +0,0 @@ -import { thoughts } from './mockData.js'; -import { v4 as uuidv4 } from 'uuid'; - -export function getAllThoughts() { - const thoughtList = [...thoughts]; - return thoughtList; -} - -export function addThought({ message }) { - const newThought = { - _id: uuidv4(), - message: message, - hearts: 0, - createdAt: new Date().toISOString(), - __v: 0, - }; - - thoughts.push(newThought); - return newThought; -} - -export function getOneThought(id) { - if (!id) return null; - - const thought = thoughts.find((thought) => thought._id === String(id)); - if (!thought) return null; - - return thought; -} - -export function incrementLike(id) { - const foundThought = thoughts.find((thought) => thought._id === String(id)); - //if the thought is not found, return null - if (!foundThought) return null; - - //else increment the hearts count - foundThought.hearts += 1; - return foundThought; -} - -export function decrementLike(id) { - const foundThought = thoughts.find((thought) => thought._id === String(id)); - //if the thought is not found, return null - if (!foundThought) return null; - - //else decrement the hearts count - if (foundThought.hearts > 0) { - foundThought.hearts -= 1; - } - return foundThought; -} - -export function updateThought(id, updatedThought) { - const thought = thoughts.find((thought) => thought._id === String(id)); - if (!thought) return null; - - if (updatedThought.message) { - thought.message = updatedThought.message; - } - - thought.__v += 1; - - return thought; -} - -export function removeThought(id) { - const index = thoughts.findIndex((t) => t._id === String(id)); - if (index === -1) return null; - - // Ta ut objektet från arrayen - const [removed] = thoughts.splice(index, 1); - return removed; // returnera det borttagna objektet -} From 8ec062fe1a7efe2bb0c555650ec826e652a32dfe Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Wed, 4 Jun 2025 14:21:37 +0200 Subject: [PATCH 18/48] UpdateThought works now with mongo method --- controllers/thoughtController.js | 29 ++++++++++++++++++++--------- routes/happyThoughts.js | 4 ++-- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/controllers/thoughtController.js b/controllers/thoughtController.js index 885e9b3..768b6d0 100644 --- a/controllers/thoughtController.js +++ b/controllers/thoughtController.js @@ -99,18 +99,29 @@ export const unLikeThought = async (req, res) => { } }; -// function updatedThoughtHandler(req, res) { -// const { id } = req.params; -// const updatedThought = req.body; +export const updateThought = async (req, res) => { + const { id } = req.params; + const { message } = req.body; -// const updated = updateThought(id, updatedThought); + try { + const thought = await Thought.findById(id); -// if (!updated) { -// return res.status(404).json({ error: 'Thought not found' }); -// } + if (!thought) { + return res.status(404).json({ error: 'Thought not found' }); + } -// return res.json(updated); -// } + thought.message = message; + await thought.save(); // kör validering och sparar ändringarna + + res.json(thought); + } catch (error) { + console.error('Mongoose error on updateThought:', error); + res.status(400).json({ + error: 'Invalid input or ID format', + message: error.message, + }); + } +}; // function removeThoughtHandler(req, res) { // const { id } = req.params; diff --git a/routes/happyThoughts.js b/routes/happyThoughts.js index 50687ca..879de40 100644 --- a/routes/happyThoughts.js +++ b/routes/happyThoughts.js @@ -5,7 +5,7 @@ import { addThought, likeThought, unLikeThought, - // updateThought, + updateThought, // removeThought, } from '../controllers/thoughtController.js'; @@ -17,7 +17,7 @@ happyRouter.get('/:id', getOneThought); happyRouter.post('/', addThought); happyRouter.post('/:id/likes', likeThought); happyRouter.delete('/:id/likes', unLikeThought); -// happyRouter.put('/:id', updateThought); +happyRouter.put('/:id', updateThought); // happyRouter.delete('/:id', removeThought); export default happyRouter; From f2cccb3661c1033b095c7a051f49d623a3f61e05 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Wed, 4 Jun 2025 14:27:06 +0200 Subject: [PATCH 19/48] Delete thought done --- controllers/thoughtController.js | 37 +++++++++++++++++++++----------- routes/happyThoughts.js | 4 ++-- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/controllers/thoughtController.js b/controllers/thoughtController.js index 768b6d0..c601b97 100644 --- a/controllers/thoughtController.js +++ b/controllers/thoughtController.js @@ -123,16 +123,27 @@ export const updateThought = async (req, res) => { } }; -// function removeThoughtHandler(req, res) { -// const { id } = req.params; -// const removedThought = removeThought(id); - -// if (!removedThought) { -// return res.status(404).json({ error: 'Thought not found' }); -// } - -// return res.json({ -// message: `Thought: ${removedThought.message}, removed successfully`, -// removedThought: removedThought, -// }); -// } +export const removeThought = async (req, res) => { + const { id } = req.params; + + try { + const thought = await Thought.findById(id); + + if (!thought) { + return res.status(404).json({ error: 'Thought not found' }); + } + + await thought.deleteOne(); // eller await Thought.findByIdAndDelete(id); + + res.json({ + message: `Thought: "${thought.message}" removed successfully`, + removedThought: thought, + }); + } catch (error) { + console.error('Mongoose error on removeThought:', error); + res.status(400).json({ + error: 'Invalid ID format or other error', + message: error.message, + }); + } +}; diff --git a/routes/happyThoughts.js b/routes/happyThoughts.js index 879de40..ad02487 100644 --- a/routes/happyThoughts.js +++ b/routes/happyThoughts.js @@ -6,7 +6,7 @@ import { likeThought, unLikeThought, updateThought, - // removeThought, + removeThought, } from '../controllers/thoughtController.js'; const happyRouter = express.Router(); @@ -18,6 +18,6 @@ happyRouter.post('/', addThought); happyRouter.post('/:id/likes', likeThought); happyRouter.delete('/:id/likes', unLikeThought); happyRouter.put('/:id', updateThought); -// happyRouter.delete('/:id', removeThought); +happyRouter.delete('/:id', removeThought); export default happyRouter; From dcf58cea34e49289fb7e041de8fac1803ccb1e47 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Thu, 5 Jun 2025 08:17:57 +0200 Subject: [PATCH 20/48] remove thought refactored --- controllers/thoughtController.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/controllers/thoughtController.js b/controllers/thoughtController.js index c601b97..9bf0dc3 100644 --- a/controllers/thoughtController.js +++ b/controllers/thoughtController.js @@ -127,17 +127,15 @@ export const removeThought = async (req, res) => { const { id } = req.params; try { - const thought = await Thought.findById(id); + const removedThought = await Thought.findByIdAndDelete(id); - if (!thought) { + if (!removedThought) { return res.status(404).json({ error: 'Thought not found' }); } - await thought.deleteOne(); // eller await Thought.findByIdAndDelete(id); - res.json({ - message: `Thought: "${thought.message}" removed successfully`, - removedThought: thought, + message: `Thought: "${removedThought.message}" removed successfully`, + removedThought, }); } catch (error) { console.error('Mongoose error on removeThought:', error); From 36f24b92ae6a95bf6d036ae12904560e8a34ebfd Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Thu, 5 Jun 2025 08:18:33 +0200 Subject: [PATCH 21/48] =?UTF-8?q?deleted=20mockdata=20filen=20som=20jag=20?= =?UTF-8?q?anv=C3=A4nde=20tidigare?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- services/mockData.js | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 services/mockData.js diff --git a/services/mockData.js b/services/mockData.js deleted file mode 100644 index e203a14..0000000 --- a/services/mockData.js +++ /dev/null @@ -1,2 +0,0 @@ -import data from '../data.json'; -export let thoughts = data.map((item) => ({ ...item })); From 2acfdd0697113531d83535cea54d418c749c5aa3 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Thu, 5 Jun 2025 10:23:13 +0200 Subject: [PATCH 22/48] test --- controllers/thoughtController.js | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/controllers/thoughtController.js b/controllers/thoughtController.js index 9bf0dc3..36e0437 100644 --- a/controllers/thoughtController.js +++ b/controllers/thoughtController.js @@ -2,17 +2,31 @@ import express from 'express'; import { Thought } from '../models/Thoughts'; export const listAllThoughts = async (req, res) => { + const sortBy = req.query.sortBy || 'createdAt'; + const sortDir = req.query.sortDir === 'ascending' ? 1 : -1; + + const page = Math.max(Number(req.query.page) || 1, 1); // min = 1 + const rawLimit = Number(req.query.limit) || 10; + const limit = Math.min(Math.max(rawLimit, 1), 100); // mellan 1 och 100 + const skip = (page - 1) * limit; + try { - const sortBy = req.query.sortBy || 'createdAt'; - const sortDir = req.query.sortDir === 'ascending' ? 1 : -1; + const totalCount = await Thought.countDocuments(); const thoughts = await Thought.find() - .sort({ [sortBy]: sortDir }) // <– dynamisk sortering - .limit(20); + .sort({ [sortBy]: sortDir }) + .skip(skip) + .limit(limit); - res.json(thoughts); + res.json({ + page, + limit, + totalCount, + totalPages: Math.ceil(totalCount / limit), + results: thoughts, + }); } catch (error) { - console.error('Mongoose error:', error); + console.error('Mongoose error on listAllThoughts:', error); res.status(500).json({ error: 'Could not fetch thoughts from database' }); } }; From ec745e2182101f0f91be4e41b65c86bb61a9a408 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Mon, 9 Jun 2025 11:18:57 +0200 Subject: [PATCH 23/48] deleted utils and a unesssesary import --- controllers/thoughtController.js | 1 - services/untils.js | 47 -------------------------------- 2 files changed, 48 deletions(-) delete mode 100644 services/untils.js diff --git a/controllers/thoughtController.js b/controllers/thoughtController.js index 36e0437..126a4cf 100644 --- a/controllers/thoughtController.js +++ b/controllers/thoughtController.js @@ -1,4 +1,3 @@ -import express from 'express'; import { Thought } from '../models/Thoughts'; export const listAllThoughts = async (req, res) => { diff --git a/services/untils.js b/services/untils.js deleted file mode 100644 index 1864c2b..0000000 --- a/services/untils.js +++ /dev/null @@ -1,47 +0,0 @@ -//Made from ChatGPT - -// Hittar suggested id att använda vid felaktigt id -export function findByPrefix(targetId, allIds, prefixLength = 4) { - // Ta de första prefixLength tecknen från det inskickade ID:t - const prefix = targetId.slice(0, prefixLength); - - // Leta bland alla giltiga ID:n efter en som börjar med samma prefix - return allIds.find((id) => id.startsWith(prefix)) || null; -} - -// Paginerar en array genom att returnera både metadata och de paginerade resultaten. -export function paginate(items, pageParam = 1, perPageParam = 10) { - // 1) Tolka parametrarna till tal (default 1 och 10) - const requestedPage = Number(pageParam) || 1; - const perPage = Number(perPageParam) || 10; - - // 2) Totalt antal items - const total = items.length; - // 3) Totalt antal sidor (rundar alltid upp) - const totalPages = Math.ceil(total / perPage); - // 4) Säker sida inom spannet [1, totalPages] - const safePage = Math.min(Math.max(1, pageParam), totalPages); - // 5) Beräkna startindex och skär ut resultat - const start = (safePage - 1) * perPage; - const results = items.slice(start, start + perPage); - - // 6) Returnera metadata + resultat - return { pageParam, perPage, total, totalPages, results }; -} - -export function sortItems(items, key, directionParam) { - // Bestäm riktning: om directionParam === 'ascending' → 'ascending', annars 'descending' - const direction = directionParam === 'ascending' ? 'ascending' : 'descending'; - const dir = direction === 'ascending' ? 1 : -1; - - // Gör en kopia så vi inte muterar originalet - const arr = [...items]; - - arr.sort((a, b) => { - if (a[key] < b[key]) return -1 * dir; - if (a[key] > b[key]) return 1 * dir; - return 0; - }); - - return arr; -} From 49456d7c1ec476d8df1d63f46592a25c2fb350a1 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Mon, 9 Jun 2025 12:51:20 +0200 Subject: [PATCH 24/48] changed hearts to likes --- controllers/thoughtController.js | 6 +++--- models/Thoughts.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/controllers/thoughtController.js b/controllers/thoughtController.js index 126a4cf..95ec389 100644 --- a/controllers/thoughtController.js +++ b/controllers/thoughtController.js @@ -71,7 +71,7 @@ export const likeThought = async (req, res) => { try { const updatedThought = await Thought.findByIdAndUpdate( id, - { $inc: { hearts: 1 } }, // 💥 Mongoose "increment" + { $inc: { likes: 1 } }, // 💥 Mongoose "increment" { new: true } // returnera det uppdaterade dokumentet ); @@ -100,8 +100,8 @@ export const unLikeThought = async (req, res) => { .json({ error: 'Thought not found, could not unlike' }); } - if (thought.hearts > 0) { - thought.hearts -= 1; + if (thought.likes > 0) { + thought.likes -= 1; await thought.save(); } diff --git a/models/Thoughts.js b/models/Thoughts.js index ca7cd45..0978b46 100644 --- a/models/Thoughts.js +++ b/models/Thoughts.js @@ -7,7 +7,7 @@ const thoughtSchema = new mongoose.Schema({ minlength: 5, maxlength: 140, }, - hearts: { + likes: { type: Number, default: 0, }, From b9871e4cc091c8def8c653f3bd7688abbe9ebb94 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Wed, 11 Jun 2025 09:01:42 +0200 Subject: [PATCH 25/48] mongo URL --- server.js | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/server.js b/server.js index 3ba4764..a6fa49e 100644 --- a/server.js +++ b/server.js @@ -11,25 +11,14 @@ import { Thought } from './models/Thoughts.js'; dotenv.config(); //moongoose -const mongoUrl = - process.env.MONGO_URL || 'mongodb://127.0.0.1:27017/happyThoughts'; +const mongoUrl = process.env.MONGO_URL; // || 'mongodb://127.0.0.1:27017/happyThoughts'; mongoose.connect(mongoUrl); -mongoose.connection.on('connected', () => console.log('Connected to MongoDB')); +mongoose.connection.on('connected', () => + console.log('Connected to MongoDB Atlas') +); const port = process.env.PORT || 8080; -// const seedDatabase = async () => { -// try { -// await Thought.deleteMany(); // Rensa tidigare innehåll -// await Thought.insertMany(data); // in med nya tankar -// console.log('Database seeded with thoughts!'); -// } catch (error) { -// console.error('Error seeding database:', error); -// } -// }; - -// seedDatabase(); - // Skapa en Express-app const app = express(); From c305b8d13335dd3dda742e07343f1d2c15d3a7ab Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Wed, 11 Jun 2025 14:31:27 +0200 Subject: [PATCH 26/48] usermodel and first post using the userRouter to add signup --- controllers/thoughtController.js | 2 +- data.json | 121 ------------------ models/Users.js | 29 +++++ package.json | 1 + ...appyThoughts.js => happyThoughtsRouter.js} | 0 routes/userRoutes.js | 42 ++++++ server.js | 10 +- 7 files changed, 79 insertions(+), 126 deletions(-) delete mode 100644 data.json create mode 100644 models/Users.js rename routes/{happyThoughts.js => happyThoughtsRouter.js} (100%) create mode 100644 routes/userRoutes.js diff --git a/controllers/thoughtController.js b/controllers/thoughtController.js index 95ec389..c8b64a7 100644 --- a/controllers/thoughtController.js +++ b/controllers/thoughtController.js @@ -1,4 +1,4 @@ -import { Thought } from '../models/Thoughts'; +import { Thought } from '../models/Thoughts.js'; export const listAllThoughts = async (req, res) => { const sortBy = req.query.sortBy || 'createdAt'; 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/models/Users.js b/models/Users.js new file mode 100644 index 0000000..384cfb9 --- /dev/null +++ b/models/Users.js @@ -0,0 +1,29 @@ +import mongoose from 'mongoose'; +import crypto from 'crypto'; +import bcrypt from 'bcrypt'; + +const User = mongoose.model('User', { + email: { + type: String, + required: true, + unique: true, + minlength: 3, + }, + password: { + type: String, + required: true, + minlength: 6, + }, + accessToken: { + type: String, + default: crypto.randomBytes(64).toString('hex'), + }, + thoughts: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'Thought', + }, + ], +}); + +export default User; diff --git a/package.json b/package.json index f588e89..09f37b8 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "author": "", "license": "ISC", "dependencies": { + "bcrypt": "^6.0.0", "cors": "^2.8.5", "dotenv": "^16.5.0", "express": "^4.17.3", diff --git a/routes/happyThoughts.js b/routes/happyThoughtsRouter.js similarity index 100% rename from routes/happyThoughts.js rename to routes/happyThoughtsRouter.js diff --git a/routes/userRoutes.js b/routes/userRoutes.js new file mode 100644 index 0000000..d3a1535 --- /dev/null +++ b/routes/userRoutes.js @@ -0,0 +1,42 @@ +import express from 'express'; +import bcrypt from 'bcrypt'; +import User from '../models/Users.js'; + +const userRoutes = express.Router(); + +userRoutes.post('/signup', async (req, res) => { + const { email, password } = req.body; + + try { + // Kontrollera att email och password finns + if (!email || !password) { + return res.status(400).json({ error: 'Email and password are required' }); + } + + // Kolla om användaren redan finns + const existingUser = await User.findOne({ email }); + if (existingUser) { + return res.status(400).json({ error: 'Email already exists' }); + } + + // Hasha lösenordet + const salt = bcrypt.genSaltSync(); + const hashedPassword = bcrypt.hashSync(password, salt); + + // Skapa användaren + const newUser = await new User({ email, password: hashedPassword }).save(); + + // Skicka tillbaka accessToken + email + res.status(201).json({ + email: newUser.email, + accessToken: newUser.accessToken, + id: newUser._id, + }); + } catch (err) { + res + .status(500) + .json({ error: 'Internal server error', details: err.message }); + } +}); + +export default userRoutes; diff --git a/server.js b/server.js index a6fa49e..1476c6f 100644 --- a/server.js +++ b/server.js @@ -2,16 +2,17 @@ import cors from 'cors'; import express from 'express'; import expressListEndpoints from 'express-list-endpoints'; import dotenv from 'dotenv'; -import happyRouter from './routes/happyThoughts.js'; import mongoose from 'mongoose'; -import data from './data.json'; -import { Thought } from './models/Thoughts.js'; + +import happyRouter from './routes/happyThoughtsRouter.js'; +import userRoutes from './routes/userRoutes.js'; // Ladda in .env-filen dotenv.config(); //moongoose -const mongoUrl = process.env.MONGO_URL; // || 'mongodb://127.0.0.1:27017/happyThoughts'; +const mongoUrl = + process.env.MONGO_URL || 'mongodb://127.0.0.1:27017/happyThoughts'; mongoose.connect(mongoUrl); mongoose.connection.on('connected', () => console.log('Connected to MongoDB Atlas') @@ -35,6 +36,7 @@ app.get('/', ListEndpointsHandler); //HappyRouter montering app.use('/api/thoughts', happyRouter); +app.use('/', userRoutes); // Hantera 404 app.use((req, res) => { From e9cea9e98c9aa5f9e1974a8dee50f7fbd738a41b Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Wed, 11 Jun 2025 14:40:26 +0200 Subject: [PATCH 27/48] post login set --- routes/userRoutes.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/routes/userRoutes.js b/routes/userRoutes.js index d3a1535..6d2cf51 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -39,4 +39,35 @@ userRoutes.post('/signup', async (req, res) => { } }); +userRoutes.post('/login', async (req, res) => { + const { email, password } = req.body; + + try { + // Leta upp användaren + const user = await User.findOne({ email }); + + if (!user) { + return res.status(401).json({ error: 'Invalid email or password' }); + } + + // Jämför lösenord + const passwordMatch = bcrypt.compareSync(password, user.password); + + if (!passwordMatch) { + return res.status(401).json({ error: 'Invalid email or password' }); + } + + // Om allt ok! Skicka tillbaka accessToken + res.status(200).json({ + email: user.email, + accessToken: user.accessToken, + id: user._id, + }); + } catch (err) { + res + .status(500) + .json({ error: 'Internal server error', details: err.message }); + } +}); + export default userRoutes; From da1be4b8f86fcf73f7d60c05b30044d56d4ce184 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Wed, 11 Jun 2025 14:42:23 +0200 Subject: [PATCH 28/48] added middleware to use to autheticate the user, not applaied on any route yet --- middlewares/authenticateUser.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 middlewares/authenticateUser.js diff --git a/middlewares/authenticateUser.js b/middlewares/authenticateUser.js new file mode 100644 index 0000000..ceb6df1 --- /dev/null +++ b/middlewares/authenticateUser.js @@ -0,0 +1,23 @@ +import User from '../models/User.js'; + +const authenticateUser = async (req, res, next) => { + const accessToken = req.header('Authorization'); + + try { + const user = await User.findOne({ accessToken }); + + if (!user) { + return res.status(401).json({ error: 'Please log in' }); + } + + // Allt ok – lägg användaren i request-objektet + req.user = user; + next(); + } catch (err) { + res + .status(500) + .json({ error: 'Internal server error', details: err.message }); + } +}; + +export default authenticateUser; From a896b5ab87634bb5568616dcdfd2a71436249996 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Wed, 11 Jun 2025 15:50:14 +0200 Subject: [PATCH 29/48] using bearer token and the middleware works great on addThought, yey --- controllers/thoughtController.js | 15 ++++++++++++++- middlewares/authenticateUser.js | 15 ++++++++++----- models/Thoughts.js | 5 +++++ models/Users.js | 6 ++++-- routes/happyThoughtsRouter.js | 4 +++- server.js | 16 ++++++++++++---- 6 files changed, 48 insertions(+), 13 deletions(-) diff --git a/controllers/thoughtController.js b/controllers/thoughtController.js index c8b64a7..4209b9a 100644 --- a/controllers/thoughtController.js +++ b/controllers/thoughtController.js @@ -51,8 +51,21 @@ export const getOneThought = async (req, res) => { export const addThought = async (req, res) => { const { message } = req.body; + + // Validate message length + if (!message || message.length < 5 || message.length > 140) { + return res.status(400).json({ + error: 'Message is required and must be between 5 and 140 characters', + }); + } + try { - const newThought = await Thought.create({ message }); + const newThought = await Thought.create({ + message, + createdBy: req.user._id, + // likes and createdAt will be set by defaults in the model + }); + res.status(201).json(newThought); } catch (error) { console.error('Mongoose error on addThought:', error); diff --git a/middlewares/authenticateUser.js b/middlewares/authenticateUser.js index ceb6df1..241bc59 100644 --- a/middlewares/authenticateUser.js +++ b/middlewares/authenticateUser.js @@ -1,16 +1,21 @@ -import User from '../models/User.js'; +import User from '../models/Users.js'; -const authenticateUser = async (req, res, next) => { - const accessToken = req.header('Authorization'); +export const authenticateUser = async (req, res, next) => { + const authHeader = req.header('Authorization'); + + if (!authHeader || !authHeader.startsWith('Bearer ')) { + return res.status(401).json({ error: 'Missing or invalid token' }); + } + + const accessToken = authHeader.replace('Bearer ', ''); try { const user = await User.findOne({ accessToken }); if (!user) { - return res.status(401).json({ error: 'Please log in' }); + return res.status(401).json({ error: 'Invalid token' }); } - // Allt ok – lägg användaren i request-objektet req.user = user; next(); } catch (err) { diff --git a/models/Thoughts.js b/models/Thoughts.js index 0978b46..f7ea6d8 100644 --- a/models/Thoughts.js +++ b/models/Thoughts.js @@ -15,6 +15,11 @@ const thoughtSchema = new mongoose.Schema({ type: Date, default: () => new Date(), // ger dagens datum }, + createdBy: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: true, + }, }); export const Thought = mongoose.model('Thought', thoughtSchema); diff --git a/models/Users.js b/models/Users.js index 384cfb9..a60aa73 100644 --- a/models/Users.js +++ b/models/Users.js @@ -2,7 +2,7 @@ import mongoose from 'mongoose'; import crypto from 'crypto'; import bcrypt from 'bcrypt'; -const User = mongoose.model('User', { +const userSchema = new mongoose.Schema({ email: { type: String, required: true, @@ -16,7 +16,7 @@ const User = mongoose.model('User', { }, accessToken: { type: String, - default: crypto.randomBytes(64).toString('hex'), + default: () => crypto.randomBytes(64).toString('hex'), }, thoughts: [ { @@ -26,4 +26,6 @@ const User = mongoose.model('User', { ], }); +const User = mongoose.model('User', userSchema); + export default User; diff --git a/routes/happyThoughtsRouter.js b/routes/happyThoughtsRouter.js index ad02487..05f6543 100644 --- a/routes/happyThoughtsRouter.js +++ b/routes/happyThoughtsRouter.js @@ -1,4 +1,6 @@ import express from 'express'; +import authenticateUser from '../middlewares/authenticateUser.js'; + import { listAllThoughts, getOneThought, @@ -14,7 +16,7 @@ const happyRouter = express.Router(); //KOMIHÅG ATT URL börjar med /api/thoughts happyRouter.get('/', listAllThoughts); happyRouter.get('/:id', getOneThought); -happyRouter.post('/', addThought); +happyRouter.post('/', authenticateUser, addThought); happyRouter.post('/:id/likes', likeThought); happyRouter.delete('/:id/likes', unLikeThought); happyRouter.put('/:id', updateThought); diff --git a/server.js b/server.js index 1476c6f..8422d69 100644 --- a/server.js +++ b/server.js @@ -13,10 +13,18 @@ dotenv.config(); //moongoose const mongoUrl = process.env.MONGO_URL || 'mongodb://127.0.0.1:27017/happyThoughts'; -mongoose.connect(mongoUrl); -mongoose.connection.on('connected', () => - console.log('Connected to MongoDB Atlas') -); +mongoose + .connect(mongoUrl) + .then(() => { + console.log('Connected to MongoDB Atlas'); + }) + .catch((error) => { + console.error('MongoDB connection error:', error); + }); + +mongoose.connection.on('error', (error) => { + console.error('MongoDB connection error:', error); +}); const port = process.env.PORT || 8080; From 67e98066118ebec45b42a6f25bb60a8d9c762e95 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Tue, 17 Jun 2025 08:34:28 +0200 Subject: [PATCH 30/48] middleware on put and delete thought and controllers refactored --- controllers/thoughtController.js | 47 ++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/controllers/thoughtController.js b/controllers/thoughtController.js index 4209b9a..215f08e 100644 --- a/controllers/thoughtController.js +++ b/controllers/thoughtController.js @@ -136,16 +136,21 @@ export const updateThought = async (req, res) => { return res.status(404).json({ error: 'Thought not found' }); } + // Kontrollera att den inloggade användaren äger tanken + if (thought.createdBy.toString() !== req.user._id.toString()) { + return res + .status(403) + .json({ error: 'You are not allowed to update this thought' }); + } + thought.message = message; - await thought.save(); // kör validering och sparar ändringarna + const updatedThought = await thought.save(); - res.json(thought); - } catch (error) { - console.error('Mongoose error on updateThought:', error); - res.status(400).json({ - error: 'Invalid input or ID format', - message: error.message, - }); + res.status(200).json(updatedThought); + } catch (err) { + res + .status(500) + .json({ error: 'Could not update thought', details: err.message }); } }; @@ -153,21 +158,23 @@ export const removeThought = async (req, res) => { const { id } = req.params; try { - const removedThought = await Thought.findByIdAndDelete(id); + const thought = await Thought.findById(id); - if (!removedThought) { + if (!thought) { return res.status(404).json({ error: 'Thought not found' }); } - res.json({ - message: `Thought: "${removedThought.message}" removed successfully`, - removedThought, - }); - } catch (error) { - console.error('Mongoose error on removeThought:', error); - res.status(400).json({ - error: 'Invalid ID format or other error', - message: error.message, - }); + if (thought.createdBy.toString() !== req.user._id.toString()) { + return res + .status(403) + .json({ error: 'You are not allowed to delete this thought' }); + } + + await thought.deleteOne(); + res.status(200).json({ message: 'Thought deleted successfully' }); + } catch (err) { + res + .status(500) + .json({ error: 'Could not delete thought', details: err.message }); } }; From 50e7fea688acc8fca50b3b6959e552a029fe5400 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Mon, 23 Jun 2025 10:26:27 +0200 Subject: [PATCH 31/48] dont remeber what I did, forgot to commit. I think it was the adding the Auth middlewere to post and login --- controllers/thoughtController.js | 6 ++++++ middlewares/authenticateUser.js | 2 +- routes/happyThoughtsRouter.js | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/controllers/thoughtController.js b/controllers/thoughtController.js index 215f08e..590bf7e 100644 --- a/controllers/thoughtController.js +++ b/controllers/thoughtController.js @@ -1,4 +1,5 @@ import { Thought } from '../models/Thoughts.js'; +import mongoose from 'mongoose'; export const listAllThoughts = async (req, res) => { const sortBy = req.query.sortBy || 'createdAt'; @@ -158,6 +159,11 @@ export const removeThought = async (req, res) => { const { id } = req.params; try { + // Validate if the ID is a valid MongoDB ObjectId + if (!mongoose.Types.ObjectId.isValid(id)) { + return res.status(400).json({ error: 'Invalid thought ID format' }); + } + const thought = await Thought.findById(id); if (!thought) { diff --git a/middlewares/authenticateUser.js b/middlewares/authenticateUser.js index 241bc59..cdfd1a6 100644 --- a/middlewares/authenticateUser.js +++ b/middlewares/authenticateUser.js @@ -1,6 +1,6 @@ import User from '../models/Users.js'; -export const authenticateUser = async (req, res, next) => { +const authenticateUser = async (req, res, next) => { const authHeader = req.header('Authorization'); if (!authHeader || !authHeader.startsWith('Bearer ')) { diff --git a/routes/happyThoughtsRouter.js b/routes/happyThoughtsRouter.js index 05f6543..d540c41 100644 --- a/routes/happyThoughtsRouter.js +++ b/routes/happyThoughtsRouter.js @@ -19,7 +19,7 @@ happyRouter.get('/:id', getOneThought); happyRouter.post('/', authenticateUser, addThought); happyRouter.post('/:id/likes', likeThought); happyRouter.delete('/:id/likes', unLikeThought); -happyRouter.put('/:id', updateThought); -happyRouter.delete('/:id', removeThought); +happyRouter.put('/:id', authenticateUser, updateThought); +happyRouter.delete('/:id', authenticateUser, removeThought); export default happyRouter; From ca69441ef56561157f06589e789c459774b0706e Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Mon, 23 Jun 2025 11:17:30 +0200 Subject: [PATCH 32/48] toggle like works --- controllers/thoughtController.js | 65 +++++++++++++++++--------------- models/Thoughts.js | 8 +++- routes/happyThoughtsRouter.js | 4 +- 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/controllers/thoughtController.js b/controllers/thoughtController.js index 590bf7e..f83d9b9 100644 --- a/controllers/thoughtController.js +++ b/controllers/thoughtController.js @@ -82,47 +82,50 @@ export const addThought = async (req, res) => { export const likeThought = async (req, res) => { const { id } = req.params; - try { - const updatedThought = await Thought.findByIdAndUpdate( - id, - { $inc: { likes: 1 } }, // 💥 Mongoose "increment" - { new: true } // returnera det uppdaterade dokumentet - ); - - if (!updatedThought) { - return res - .status(404) - .json({ error: 'Thought not found, could not add your like' }); - } - - res.json(updatedThought); - } catch (error) { - console.error('Mongoose error on likeThought:', error); - res.status(400).json({ error: 'Invalid ID format or other error' }); - } -}; - -export const unLikeThought = 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({ error: 'Thought not found, could not unlike' }); + return res.status(404).json({ error: 'Thought not found' }); } - if (thought.likes > 0) { - thought.likes -= 1; - await thought.save(); + if (userId) { + const userIdStr = userId.toString(); + // Convert likedBy to array of strings for logic + let likedByStrArr = thought.likedBy.map((id) => id.toString()); + console.log('Before toggle:', { userIdStr, likedBy: likedByStrArr }); + const hasLiked = likedByStrArr.includes(userIdStr); + + if (hasLiked) { + likedByStrArr = likedByStrArr.filter((id) => id !== userIdStr); + console.log('User unliked. After removal:', likedByStrArr); + } else { + likedByStrArr.push(userIdStr); + console.log('User liked. After addition:', likedByStrArr); + } + thought.likes = likedByStrArr.length; + console.log('Final likedBy and likes:', { + likedBy: likedByStrArr, + likes: thought.likes, + }); + // Convert likedBy back to ObjectIds before saving + thought.likedBy = likedByStrArr.map( + (id) => new mongoose.Types.ObjectId(id) + ); + + const updatedThought = await thought.save(); + return res.status(200).json(updatedThought); } - res.json(thought); + // Guests should not be able to like + return res.status(401).json({ error: 'Authentication required to like' }); } catch (error) { - console.error('Mongoose error on unLikeThought:', error); - res.status(400).json({ error: 'Invalid ID format or other error' }); + console.error('Error in likeThought:', error); + res + .status(500) + .json({ error: 'Could not toggle like', details: error.message }); } }; diff --git a/models/Thoughts.js b/models/Thoughts.js index f7ea6d8..4fab534 100644 --- a/models/Thoughts.js +++ b/models/Thoughts.js @@ -11,6 +11,12 @@ const thoughtSchema = new mongoose.Schema({ type: Number, default: 0, }, + likedBy: [ + { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + }, + ], createdAt: { type: Date, default: () => new Date(), // ger dagens datum @@ -18,7 +24,7 @@ const thoughtSchema = new mongoose.Schema({ createdBy: { type: mongoose.Schema.Types.ObjectId, ref: 'User', - required: true, + required: false, }, }); diff --git a/routes/happyThoughtsRouter.js b/routes/happyThoughtsRouter.js index d540c41..cc53fc8 100644 --- a/routes/happyThoughtsRouter.js +++ b/routes/happyThoughtsRouter.js @@ -6,7 +6,6 @@ import { getOneThought, addThought, likeThought, - unLikeThought, updateThought, removeThought, } from '../controllers/thoughtController.js'; @@ -17,8 +16,7 @@ const happyRouter = express.Router(); happyRouter.get('/', listAllThoughts); happyRouter.get('/:id', getOneThought); happyRouter.post('/', authenticateUser, addThought); -happyRouter.post('/:id/likes', likeThought); -happyRouter.delete('/:id/likes', unLikeThought); +happyRouter.post('/:id/likes', authenticateUser, likeThought); happyRouter.put('/:id', authenticateUser, updateThought); happyRouter.delete('/:id', authenticateUser, removeThought); From 4c739a5dbe47aaed0990f85feec04a3d52e9187f Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Mon, 23 Jun 2025 11:42:30 +0200 Subject: [PATCH 33/48] refactored the userRoute to using userController for easier readning --- controllers/userController.js | 63 +++++++++++++++++++++++++++++++ routes/userRoutes.js | 71 +++-------------------------------- 2 files changed, 69 insertions(+), 65 deletions(-) create mode 100644 controllers/userController.js diff --git a/controllers/userController.js b/controllers/userController.js new file mode 100644 index 0000000..0231f90 --- /dev/null +++ b/controllers/userController.js @@ -0,0 +1,63 @@ +import User from '../models/Users.js'; +import bcrypt from 'bcrypt'; +import crypto from 'crypto'; + +export const signup = async (req, res) => { + const { email, password } = req.body; + + try { + if (!email || !password) { + return res.status(400).json({ error: 'Email and password are required' }); + } + const existingUser = await User.findOne({ email }); + if (existingUser) { + return res.status(400).json({ error: 'Email already exists' }); + } + const salt = bcrypt.genSaltSync(); + const hashedPassword = bcrypt.hashSync(password, salt); + const newUser = await new User({ email, password: hashedPassword }).save(); + res.status(201).json({ + email: newUser.email, + accessToken: newUser.accessToken, + id: newUser._id, + }); + } catch (err) { + res + .status(500) + .json({ error: 'Internal server error', details: err.message }); + } +}; + +export const login = async (req, res) => { + const { email, password } = req.body; + + try { + const user = await User.findOne({ email }); + if (!user) { + return res.status(401).json({ error: 'Invalid email or password' }); + } + const passwordMatch = bcrypt.compareSync(password, user.password); + if (!passwordMatch) { + return res.status(401).json({ error: 'Invalid email or password' }); + } + res.status(200).json({ + email: user.email, + accessToken: user.accessToken, + id: user._id, + }); + } catch (err) { + res + .status(500) + .json({ error: 'Internal server error', details: err.message }); + } +}; + +export const logout = async (req, res) => { + try { + req.user.accessToken = crypto.randomBytes(64).toString('hex'); + await req.user.save(); + res.status(200).json({ message: 'Logged out successfully' }); + } catch (err) { + res.status(500).json({ error: 'Could not log out', details: err.message }); + } +}; diff --git a/routes/userRoutes.js b/routes/userRoutes.js index 6d2cf51..e1bfae6 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -1,73 +1,14 @@ import express from 'express'; import bcrypt from 'bcrypt'; import User from '../models/Users.js'; +import authenticateUser from '../middlewares/authenticateUser.js'; +import crypto from 'crypto'; +import { signup, login, logout } from '../controllers/userController.js'; const userRoutes = express.Router(); -userRoutes.post('/signup', async (req, res) => { - const { email, password } = req.body; - - try { - // Kontrollera att email och password finns - if (!email || !password) { - return res.status(400).json({ error: 'Email and password are required' }); - } - - // Kolla om användaren redan finns - const existingUser = await User.findOne({ email }); - if (existingUser) { - return res.status(400).json({ error: 'Email already exists' }); - } - - // Hasha lösenordet - const salt = bcrypt.genSaltSync(); - const hashedPassword = bcrypt.hashSync(password, salt); - - // Skapa användaren - const newUser = await new User({ email, password: hashedPassword }).save(); - - // Skicka tillbaka accessToken + email - res.status(201).json({ - email: newUser.email, - accessToken: newUser.accessToken, - id: newUser._id, - }); - } catch (err) { - res - .status(500) - .json({ error: 'Internal server error', details: err.message }); - } -}); - -userRoutes.post('/login', async (req, res) => { - const { email, password } = req.body; - - try { - // Leta upp användaren - const user = await User.findOne({ email }); - - if (!user) { - return res.status(401).json({ error: 'Invalid email or password' }); - } - - // Jämför lösenord - const passwordMatch = bcrypt.compareSync(password, user.password); - - if (!passwordMatch) { - return res.status(401).json({ error: 'Invalid email or password' }); - } - - // Om allt ok! Skicka tillbaka accessToken - res.status(200).json({ - email: user.email, - accessToken: user.accessToken, - id: user._id, - }); - } catch (err) { - res - .status(500) - .json({ error: 'Internal server error', details: err.message }); - } -}); +userRoutes.post('/signup', signup); +userRoutes.post('/login', login); +userRoutes.post('/logout', authenticateUser, logout); export default userRoutes; From 4f6aa9fb4b4a50f60f52ae67878b8e40616983da Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Thu, 26 Jun 2025 16:22:11 +0200 Subject: [PATCH 34/48] populate insted of just ID --- controllers/thoughtController.js | 43 +++++++++++++++----------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/controllers/thoughtController.js b/controllers/thoughtController.js index f83d9b9..532597b 100644 --- a/controllers/thoughtController.js +++ b/controllers/thoughtController.js @@ -5,26 +5,11 @@ export const listAllThoughts = async (req, res) => { const sortBy = req.query.sortBy || 'createdAt'; const sortDir = req.query.sortDir === 'ascending' ? 1 : -1; - const page = Math.max(Number(req.query.page) || 1, 1); // min = 1 - const rawLimit = Number(req.query.limit) || 10; - const limit = Math.min(Math.max(rawLimit, 1), 100); // mellan 1 och 100 - const skip = (page - 1) * limit; - try { - const totalCount = await Thought.countDocuments(); - const thoughts = await Thought.find() .sort({ [sortBy]: sortDir }) - .skip(skip) - .limit(limit); - - res.json({ - page, - limit, - totalCount, - totalPages: Math.ceil(totalCount / limit), - results: thoughts, - }); + .populate('createdBy', '_id email'); + res.json(thoughts); } catch (error) { console.error('Mongoose error on listAllThoughts:', error); res.status(500).json({ error: 'Could not fetch thoughts from database' }); @@ -35,7 +20,7 @@ export const getOneThought = async (req, res) => { const { id } = req.params; try { - const thought = await Thought.findById(id); + let thought = await Thought.findById(id); if (!thought) { return res.status(404).json({ @@ -43,6 +28,7 @@ export const getOneThought = async (req, res) => { requestedId: id, }); } + thought = await thought.populate('createdBy', '_id email'); res.json(thought); } catch (error) { console.error('Mongoose error on getOneThought:', error); @@ -54,7 +40,7 @@ export const addThought = async (req, res) => { const { message } = req.body; // Validate message length - if (!message || message.length < 5 || message.length > 140) { + if (!message || message.length < 4 || message.length > 140) { return res.status(400).json({ error: 'Message is required and must be between 5 and 140 characters', }); @@ -67,7 +53,11 @@ export const addThought = async (req, res) => { // likes and createdAt will be set by defaults in the model }); - res.status(201).json(newThought); + const populatedThought = await newThought.populate( + 'createdBy', + '_id email' + ); + res.status(201).json(populatedThought); } catch (error) { console.error('Mongoose error on addThought:', error); if (error.name === 'ValidationError') { @@ -116,7 +106,11 @@ export const likeThought = async (req, res) => { ); const updatedThought = await thought.save(); - return res.status(200).json(updatedThought); + const populatedThought = await updatedThought.populate( + 'createdBy', + '_id email' + ); + return res.status(200).json(populatedThought); } // Guests should not be able to like @@ -149,8 +143,11 @@ export const updateThought = async (req, res) => { thought.message = message; const updatedThought = await thought.save(); - - res.status(200).json(updatedThought); + const populatedThought = await updatedThought.populate( + 'createdBy', + '_id email' + ); + res.status(200).json(populatedThought); } catch (err) { res .status(500) From a01c6f41f7710a8658c2449057e0ff7c180f197a Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 27 Jun 2025 14:14:19 +0200 Subject: [PATCH 35/48] Having trouble to deploy to render.com --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 09f37b8..ce37a80 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "version": "1.0.0", "description": "Project API", "scripts": { - "start": "babel-node server.js", + "build": "babel . -d dist", + "start": "node dist/server.js", "dev": "nodemon server.js --exec babel-node", "test:service": "babel-node testService.js" }, From 7e5ca47bc3aa91459a2d1a04cec0a0f872c53ca5 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 27 Jun 2025 14:20:48 +0200 Subject: [PATCH 36/48] changed the dependencis --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index ce37a80..c03cd0d 100644 --- a/package.json +++ b/package.json @@ -17,12 +17,12 @@ "express": "^4.17.3", "express-list-endpoints": "^7.1.1", "mongoose": "^8.15.1", - "uuid": "^11.1.0" - }, - "devDependencies": { + "uuid": "^11.1.0", "@babel/core": "^7.27.3", "@babel/node": "^7.27.1", - "@babel/preset-env": "^7.27.2", + "@babel/preset-env": "^7.27.2" + }, + "devDependencies": { "nodemon": "^3.0.1" } } From 2d1aec7cf15865109ca597025b73750a6399db60 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 27 Jun 2025 14:22:47 +0200 Subject: [PATCH 37/48] trying things out to make this render.com work --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index c03cd0d..c272b70 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,7 @@ "version": "1.0.0", "description": "Project API", "scripts": { - "build": "babel . -d dist", - "start": "node dist/server.js", + "start": "babel-node server.js", "dev": "nodemon server.js --exec babel-node", "test:service": "babel-node testService.js" }, From bf7667f289c916e7e6e0f91f4d5e269ebc6bd0ca Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 27 Jun 2025 14:27:39 +0200 Subject: [PATCH 38/48] trying everything to make this build work on render --- package.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index c272b70..9130576 100644 --- a/package.json +++ b/package.json @@ -10,18 +10,19 @@ "author": "", "license": "ISC", "dependencies": { + "@babel/core": "^7.27.3", + "@babel/node": "^7.27.1", + "@babel/preset-env": "^7.27.2", "bcrypt": "^6.0.0", "cors": "^2.8.5", "dotenv": "^16.5.0", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", "mongoose": "^8.15.1", - "uuid": "^11.1.0", - "@babel/core": "^7.27.3", - "@babel/node": "^7.27.1", - "@babel/preset-env": "^7.27.2" + "uuid": "^11.1.0" }, "devDependencies": { + "@babel/cli": "^7.27.2", "nodemon": "^3.0.1" } } From aaa66f445f207b7f1c5081ba54d6e225c2f1149e Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 27 Jun 2025 14:35:00 +0200 Subject: [PATCH 39/48] forgot to savepacjege.json --- package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 9130576..b81e085 100644 --- a/package.json +++ b/package.json @@ -3,26 +3,26 @@ "version": "1.0.0", "description": "Project API", "scripts": { - "start": "babel-node server.js", + "build": "babel server.js --out-dir dist", + "start": "node dist/server.js", "dev": "nodemon server.js --exec babel-node", "test:service": "babel-node testService.js" }, "author": "", "license": "ISC", "dependencies": { - "@babel/core": "^7.27.3", - "@babel/node": "^7.27.1", - "@babel/preset-env": "^7.27.2", "bcrypt": "^6.0.0", "cors": "^2.8.5", "dotenv": "^16.5.0", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", "mongoose": "^8.15.1", - "uuid": "^11.1.0" + "uuid": "^11.1.0", + "@babel/core": "^7.27.3", + "@babel/node": "^7.27.1", + "@babel/preset-env": "^7.27.2" }, "devDependencies": { - "@babel/cli": "^7.27.2", "nodemon": "^3.0.1" } } From 32169d1f81e6e5c95e9aaa5abf12bd365a1fe5de Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 27 Jun 2025 14:38:45 +0200 Subject: [PATCH 40/48] installed npm install --save-dev @babel/cli --- dist/server.js | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 9 ++++---- 2 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 dist/server.js diff --git a/dist/server.js b/dist/server.js new file mode 100644 index 0000000..22d212f --- /dev/null +++ b/dist/server.js @@ -0,0 +1,62 @@ +"use strict"; + +var _cors = _interopRequireDefault(require("cors")); +var _express = _interopRequireDefault(require("express")); +var _expressListEndpoints = _interopRequireDefault(require("express-list-endpoints")); +var _dotenv = _interopRequireDefault(require("dotenv")); +var _mongoose = _interopRequireDefault(require("mongoose")); +var _happyThoughtsRouter = _interopRequireDefault(require("./routes/happyThoughtsRouter.js")); +var _userRoutes = _interopRequireDefault(require("./routes/userRoutes.js")); +function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; } +// Ladda in .env-filen +_dotenv["default"].config(); + +//moongoose +var mongoUrl = process.env.MONGO_URL || 'mongodb://127.0.0.1:27017/happyThoughts'; +_mongoose["default"].connect(mongoUrl).then(function () { + console.log('Connected to MongoDB Atlas'); +})["catch"](function (error) { + console.error('MongoDB connection error:', error); +}); +_mongoose["default"].connection.on('error', function (error) { + console.error('MongoDB connection error:', error); +}); +var port = process.env.PORT || 8080; + +// Skapa en Express-app +var app = (0, _express["default"])(); + +// Middleware +app.use((0, _cors["default"])()); // Aktivera CORS +app.use(_express["default"].json()); // Aktivera JSON-parsing + +// Rot-endpoint: lista alla endpoints requriement +function ListEndpointsHandler(req, res) { + var endpoints = (0, _expressListEndpoints["default"])(app); + res.json(endpoints); +} +app.get('/', ListEndpointsHandler); + +//HappyRouter montering +app.use('/api/thoughts', _happyThoughtsRouter["default"]); +app.use('/', _userRoutes["default"]); + +// Hantera 404 +app.use(function (req, res) { + res.status(404).json({ + error: 'Not Found' + }); +}); + +//Felhantering +app.use(function (err, req, res, next) { + console.error('💥 Server Error:', err); + res.status(err.status || 500).json({ + error: err.message || 'Internal Server Error' + }); +}); + +// Starta servern +app.listen(port, function () { + console.log("Server running on http://localhost:".concat(port)); +}); \ No newline at end of file diff --git a/package.json b/package.json index b81e085..38fa59f 100644 --- a/package.json +++ b/package.json @@ -11,18 +11,19 @@ "author": "", "license": "ISC", "dependencies": { + "@babel/core": "^7.27.3", + "@babel/node": "^7.27.1", + "@babel/preset-env": "^7.27.2", "bcrypt": "^6.0.0", "cors": "^2.8.5", "dotenv": "^16.5.0", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", "mongoose": "^8.15.1", - "uuid": "^11.1.0", - "@babel/core": "^7.27.3", - "@babel/node": "^7.27.1", - "@babel/preset-env": "^7.27.2" + "uuid": "^11.1.0" }, "devDependencies": { + "@babel/cli": "^7.27.2", "nodemon": "^3.0.1" } } From 88a385aae343e89441ed9b1825835c55690b92a7 Mon Sep 17 00:00:00 2001 From: Casandra Gustafsson <113009662+HolaCarmensita@users.noreply.github.com> Date: Fri, 27 Jun 2025 14:40:33 +0200 Subject: [PATCH 41/48] Update README.md --- README.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/README.md b/README.md index 5d208e5..afa6446 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,6 @@ # 🧠 Projekt: Happy Thoughts API – Startguide -## ✅ Terminalkommandon att köra när du öppnar projektet - -1. Navigera till projektmappen: - -```bash -cd ~/Documents/Technigo/js-project-api -``` +1. clone project 2. Installera dependencies (endast första gången eller efter nytt paket): From 42803689ebbd22a91aec9bc8bdc6cfb2c83e8182 Mon Sep 17 00:00:00 2001 From: Casandra Gustafsson <113009662+HolaCarmensita@users.noreply.github.com> Date: Fri, 27 Jun 2025 14:43:59 +0200 Subject: [PATCH 42/48] Update README.md --- README.md | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index afa6446..88c484f 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,7 @@ -# 🧠 Projekt: Happy Thoughts API – Startguide +# 🧠 Projekt: Happy Thoughts API -1. clone project - -2. Installera dependencies (endast första gången eller efter nytt paket): - -```bash -npm install -``` - -3. Starta MongoDB-tjänsten via Homebrew (om den inte redan är igång): - -```bash -brew services start mongodb/brew/mongodb-community -``` - -4. Kontrollera att MongoDB körs: - -```bash -brew services list -``` - -→ Du ska se: `mongodb-community started` - -5. Starta din backend-server: +[Hola-Happy-Server](https://hola-happy-server.onrender.com) -```bash -npm run dev +[Hola-Happy-App](https://holahappythoughts.netlify.app/) -## View it live -[Hola-Happy-Server](https://hola-happy-server.onrender.com) -``` From 53f5962edfdea0da609db4e9203449afd886cfc8 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 27 Jun 2025 14:49:13 +0200 Subject: [PATCH 43/48] added npx --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 38fa59f..6193c52 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "description": "Project API", "scripts": { - "build": "babel server.js --out-dir dist", + "build": "npx babel server.js --out-dir dist", "start": "node dist/server.js", "dev": "nodemon server.js --exec babel-node", "test:service": "babel-node testService.js" From f270f1033c92db9e2739fee6d6333d5578609c10 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 27 Jun 2025 14:50:55 +0200 Subject: [PATCH 44/48] Revert "added npx" This reverts commit 53f5962edfdea0da609db4e9203449afd886cfc8. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6193c52..38fa59f 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "description": "Project API", "scripts": { - "build": "npx babel server.js --out-dir dist", + "build": "babel server.js --out-dir dist", "start": "node dist/server.js", "dev": "nodemon server.js --exec babel-node", "test:service": "babel-node testService.js" From ce4510e7375eb8530b478b5c6e5e95327202b992 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 27 Jun 2025 14:53:15 +0200 Subject: [PATCH 45/48] npx --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 38fa59f..6193c52 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "description": "Project API", "scripts": { - "build": "babel server.js --out-dir dist", + "build": "npx babel server.js --out-dir dist", "start": "node dist/server.js", "dev": "nodemon server.js --exec babel-node", "test:service": "babel-node testService.js" From ff6ddee4ee0c68ec2c05548fce1c131fd0caf503 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 27 Jun 2025 15:11:46 +0200 Subject: [PATCH 46/48] delited modules --- dist/server.js | 62 -------------------------------------------------- package.json | 10 ++++---- 2 files changed, 5 insertions(+), 67 deletions(-) delete mode 100644 dist/server.js diff --git a/dist/server.js b/dist/server.js deleted file mode 100644 index 22d212f..0000000 --- a/dist/server.js +++ /dev/null @@ -1,62 +0,0 @@ -"use strict"; - -var _cors = _interopRequireDefault(require("cors")); -var _express = _interopRequireDefault(require("express")); -var _expressListEndpoints = _interopRequireDefault(require("express-list-endpoints")); -var _dotenv = _interopRequireDefault(require("dotenv")); -var _mongoose = _interopRequireDefault(require("mongoose")); -var _happyThoughtsRouter = _interopRequireDefault(require("./routes/happyThoughtsRouter.js")); -var _userRoutes = _interopRequireDefault(require("./routes/userRoutes.js")); -function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; } -// Ladda in .env-filen -_dotenv["default"].config(); - -//moongoose -var mongoUrl = process.env.MONGO_URL || 'mongodb://127.0.0.1:27017/happyThoughts'; -_mongoose["default"].connect(mongoUrl).then(function () { - console.log('Connected to MongoDB Atlas'); -})["catch"](function (error) { - console.error('MongoDB connection error:', error); -}); -_mongoose["default"].connection.on('error', function (error) { - console.error('MongoDB connection error:', error); -}); -var port = process.env.PORT || 8080; - -// Skapa en Express-app -var app = (0, _express["default"])(); - -// Middleware -app.use((0, _cors["default"])()); // Aktivera CORS -app.use(_express["default"].json()); // Aktivera JSON-parsing - -// Rot-endpoint: lista alla endpoints requriement -function ListEndpointsHandler(req, res) { - var endpoints = (0, _expressListEndpoints["default"])(app); - res.json(endpoints); -} -app.get('/', ListEndpointsHandler); - -//HappyRouter montering -app.use('/api/thoughts', _happyThoughtsRouter["default"]); -app.use('/', _userRoutes["default"]); - -// Hantera 404 -app.use(function (req, res) { - res.status(404).json({ - error: 'Not Found' - }); -}); - -//Felhantering -app.use(function (err, req, res, next) { - console.error('💥 Server Error:', err); - res.status(err.status || 500).json({ - error: err.message || 'Internal Server Error' - }); -}); - -// Starta servern -app.listen(port, function () { - console.log("Server running on http://localhost:".concat(port)); -}); \ No newline at end of file diff --git a/package.json b/package.json index 6193c52..216eee7 100644 --- a/package.json +++ b/package.json @@ -11,19 +11,19 @@ "author": "", "license": "ISC", "dependencies": { - "@babel/core": "^7.27.3", - "@babel/node": "^7.27.1", - "@babel/preset-env": "^7.27.2", "bcrypt": "^6.0.0", "cors": "^2.8.5", "dotenv": "^16.5.0", "express": "^4.17.3", "express-list-endpoints": "^7.1.1", "mongoose": "^8.15.1", - "uuid": "^11.1.0" + "uuid": "^11.1.0", + "@babel/core": "^7.27.3", + "@babel/node": "^7.27.1", + "@babel/preset-env": "^7.27.2", + "@babel/cli": "^7.27.2" }, "devDependencies": { - "@babel/cli": "^7.27.2", "nodemon": "^3.0.1" } } From 06d26a8311723e0409a93d270c81971610a4f5f7 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 27 Jun 2025 15:23:26 +0200 Subject: [PATCH 47/48] GAAAH --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 216eee7..fb6e3f0 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "description": "Project API", "scripts": { - "build": "npx babel server.js --out-dir dist", + "build": "npx babel server.js controllers models middlewares routes --out-dir dist", "start": "node dist/server.js", "dev": "nodemon server.js --exec babel-node", "test:service": "babel-node testService.js" From 690c056a888d51facb18eef77fffa1e7dfc44817 Mon Sep 17 00:00:00 2001 From: HolaCarmensita Date: Fri, 27 Jun 2025 15:30:24 +0200 Subject: [PATCH 48/48] delited babel --- package.json | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index fb6e3f0..b26d4ef 100644 --- a/package.json +++ b/package.json @@ -2,11 +2,10 @@ "name": "project-api", "version": "1.0.0", "description": "Project API", + "type": "module", "scripts": { - "build": "npx babel server.js controllers models middlewares routes --out-dir dist", - "start": "node dist/server.js", - "dev": "nodemon server.js --exec babel-node", - "test:service": "babel-node testService.js" + "start": "node server.js", + "dev": "nodemon server.js" }, "author": "", "license": "ISC", @@ -17,11 +16,7 @@ "express": "^4.17.3", "express-list-endpoints": "^7.1.1", "mongoose": "^8.15.1", - "uuid": "^11.1.0", - "@babel/core": "^7.27.3", - "@babel/node": "^7.27.1", - "@babel/preset-env": "^7.27.2", - "@babel/cli": "^7.27.2" + "uuid": "^11.1.0" }, "devDependencies": { "nodemon": "^3.0.1"