From ba2908b2b7da8b2d91c01188c0d2311aee9a2e6d Mon Sep 17 00:00:00 2001 From: "bteicho@gmail.com" Date: Sat, 21 Sep 2024 23:59:11 +0200 Subject: [PATCH 1/6] ex-1 node finished --- week1/prep-exercises/1-web-server/server.js | 31 +++++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/week1/prep-exercises/1-web-server/server.js b/week1/prep-exercises/1-web-server/server.js index 90cb5ee65..64ae5a5b9 100644 --- a/week1/prep-exercises/1-web-server/server.js +++ b/week1/prep-exercises/1-web-server/server.js @@ -3,12 +3,37 @@ */ const http = require('http'); +const fs = require('fs'); // import the file system module //create a server let server = http.createServer(function (req, res) { - // YOUR CODE GOES IN HERE - res.write('Hello World!'); // Sends a response back to the client - res.end(); // Ends the response + // we check if the request URL(req.url) is /, if it is, we use fs.readFile() to read the index.html file + // if success, we set the content-Type to text/html and send the file content as the response. + + if (req.url === '/') { + fs.readFile('index.html', (err, data) => { + if (err) { + res.writeHead(500, { 'content-type': 'text/plain' }); + res.end('service error'); + } else { + res.writeHead(200, { 'content-type': 'text/html' }); + res.end(data); + } + }); + } else if (req.url === '/index.js') { + fs.readFile('index.js', (err, data) => { + if (err) { + res.writeHead(500, { 'content-type': 'text/plain' }); + res.end('service error'); + } else { + res.writeHead(200, { 'content-type': 'application/javascript' }); + res.end(data); + } + }); + } else { + res.writeHead(404, { 'content-type': 'text/plain' }); + res.end('404 Not Found'); + } }); server.listen(3000); // The server starts to listen on port 3000 From a47edec6180479b7f16735884b7aff7c56c4de9b Mon Sep 17 00:00:00 2001 From: "bteicho@gmail.com" Date: Mon, 30 Sep 2024 21:18:09 +0200 Subject: [PATCH 2/6] Revert "ex-1 node finished" This reverts commit ba2908b2b7da8b2d91c01188c0d2311aee9a2e6d. --- week1/prep-exercises/1-web-server/server.js | 31 ++------------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/week1/prep-exercises/1-web-server/server.js b/week1/prep-exercises/1-web-server/server.js index 64ae5a5b9..90cb5ee65 100644 --- a/week1/prep-exercises/1-web-server/server.js +++ b/week1/prep-exercises/1-web-server/server.js @@ -3,37 +3,12 @@ */ const http = require('http'); -const fs = require('fs'); // import the file system module //create a server let server = http.createServer(function (req, res) { - // we check if the request URL(req.url) is /, if it is, we use fs.readFile() to read the index.html file - // if success, we set the content-Type to text/html and send the file content as the response. - - if (req.url === '/') { - fs.readFile('index.html', (err, data) => { - if (err) { - res.writeHead(500, { 'content-type': 'text/plain' }); - res.end('service error'); - } else { - res.writeHead(200, { 'content-type': 'text/html' }); - res.end(data); - } - }); - } else if (req.url === '/index.js') { - fs.readFile('index.js', (err, data) => { - if (err) { - res.writeHead(500, { 'content-type': 'text/plain' }); - res.end('service error'); - } else { - res.writeHead(200, { 'content-type': 'application/javascript' }); - res.end(data); - } - }); - } else { - res.writeHead(404, { 'content-type': 'text/plain' }); - res.end('404 Not Found'); - } + // YOUR CODE GOES IN HERE + res.write('Hello World!'); // Sends a response back to the client + res.end(); // Ends the response }); server.listen(3000); // The server starts to listen on port 3000 From 1c1315c20afda953d96ca74456fecbe575e47b26 Mon Sep 17 00:00:00 2001 From: "bteicho@gmail.com" Date: Tue, 1 Oct 2024 22:12:44 +0200 Subject: [PATCH 3/6] assignment node.js week2 done --- .../hackyourtemperature/__tests__/app.test.js | 28 ++++++ .../hackyourtemperature/babel.config.cjs | 12 +++ .../hackyourtemperature/jest.config.cjs | 7 ++ assignments/hackyourtemperature/package.json | 90 +++++++++++++++++++ assignments/hackyourtemperature/server.js | 37 ++++++++ assignments/hackyourtemperature/source/key.js | 1 + 6 files changed, 175 insertions(+) create mode 100644 assignments/hackyourtemperature/__tests__/app.test.js create mode 100644 assignments/hackyourtemperature/babel.config.cjs create mode 100644 assignments/hackyourtemperature/jest.config.cjs create mode 100644 assignments/hackyourtemperature/package.json create mode 100644 assignments/hackyourtemperature/server.js create mode 100644 assignments/hackyourtemperature/source/key.js diff --git a/assignments/hackyourtemperature/__tests__/app.test.js b/assignments/hackyourtemperature/__tests__/app.test.js new file mode 100644 index 000000000..d1052cdbe --- /dev/null +++ b/assignments/hackyourtemperature/__tests__/app.test.js @@ -0,0 +1,28 @@ +import app from '../server.js'; +import supertest from 'supertest'; + +const request = supertest(app); + +describe('POST /weather', () => { + it('should return 400 if cityName is missing', async () => { + const response = await request.post('/weather').send({}); + expect(response.status).toBe(400); + expect(response.body.error).toBe('cityName is required'); + }); + + it('should return 404 if cityName is invalid', async () => { + const response = await request + .post('/weather') + .send({ cityName: 'invalidcity' }); + expect(response.status).toBe(404); + expect(response.body.error).toBe('city not found'); + }); + + it('should return temperature if cityName is valid', async () => { + const response = await request + .post('/weather') + .send({ cityName: 'London' }); + expect(response.status).toBe(200); + expect(response.body.weatherText).toContain('The temperature in London is'); + }); +}); diff --git a/assignments/hackyourtemperature/babel.config.cjs b/assignments/hackyourtemperature/babel.config.cjs new file mode 100644 index 000000000..f037a1a2a --- /dev/null +++ b/assignments/hackyourtemperature/babel.config.cjs @@ -0,0 +1,12 @@ +module.exports = { + presets: [ + [ + '@babel/preset-env', + { + targets: { + node: 'current', + }, + }, + ], + ], +}; diff --git a/assignments/hackyourtemperature/jest.config.cjs b/assignments/hackyourtemperature/jest.config.cjs new file mode 100644 index 000000000..de0a3bf54 --- /dev/null +++ b/assignments/hackyourtemperature/jest.config.cjs @@ -0,0 +1,7 @@ +module.exports = { + transform: { + '^.+\\.js$': 'babel-jest', + }, + transformIgnorePatterns: ['node_modules/(?!node-fetch)'], + testEnvironment: 'node', +}; diff --git a/assignments/hackyourtemperature/package.json b/assignments/hackyourtemperature/package.json new file mode 100644 index 000000000..684429934 --- /dev/null +++ b/assignments/hackyourtemperature/package.json @@ -0,0 +1,90 @@ +{ + "name": "hackyourtemperature", + "version": "1.0.0", + "description": "", + "main": "server.js", + "dependencies": { + "accepts": "^1.3.8", + "array-flatten": "^1.1.1", + "body-parser": "^1.20.3", + "bytes": "^3.1.2", + "call-bind": "^1.0.7", + "content-disposition": "^0.5.4", + "content-type": "^1.0.5", + "cookie": "^0.6.0", + "cookie-signature": "^1.0.6", + "data-uri-to-buffer": "^4.0.1", + "debug": "^2.6.9", + "define-data-property": "^1.1.4", + "depd": "^2.0.0", + "destroy": "^1.2.0", + "ee-first": "^1.1.1", + "encodeurl": "^2.0.0", + "epxress": "^0.0.1-security", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "express": "^4.21.0", + "express-handlers": "^1.0.0", + "fetch": "^1.1.0", + "fetch-blob": "^3.2.0", + "finalhandler": "^1.3.1", + "formdata-polyfill": "^4.0.10", + "forwarded": "^0.2.0", + "fresh": "^0.5.2", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "http-errors": "^2.0.0", + "iconv-lite": "^0.4.24", + "inherits": "^2.0.4", + "ipaddr.js": "^1.9.1", + "media-typer": "^0.3.0", + "merge-descriptors": "^1.0.3", + "methods": "^1.1.2", + "mime": "^1.6.0", + "mime-db": "^1.52.0", + "mime-types": "^2.1.35", + "ms": "^2.0.0", + "negotiator": "^0.6.3", + "node-domexception": "^1.0.0", + "node-fetch": "^3.3.2", + "object-inspect": "^1.13.2", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "path-to-regexp": "^0.1.10", + "proxy-addr": "^2.0.7", + "qs": "^6.13.0", + "range-parser": "^1.2.1", + "raw-body": "^2.5.2", + "safe-buffer": "^5.2.1", + "safer-buffer": "^2.1.2", + "send": "^0.19.0", + "serve-static": "^1.16.2", + "set-function-length": "^1.2.2", + "setprototypeof": "^1.2.0", + "side-channel": "^1.0.6", + "statuses": "^2.0.1", + "toidentifier": "^1.0.1", + "type-is": "^1.6.18", + "undici-types": "^6.19.8", + "unpipe": "^1.0.0", + "utils-merge": "^1.0.1", + "vary": "^1.1.2", + "web-streams-polyfill": "^3.3.3" + }, + "scripts": { + "test": "jest", + "start": "node server.js" + + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "module" +} diff --git a/assignments/hackyourtemperature/server.js b/assignments/hackyourtemperature/server.js new file mode 100644 index 000000000..b18331922 --- /dev/null +++ b/assignments/hackyourtemperature/server.js @@ -0,0 +1,37 @@ +import fetch from 'node-fetch'; +import { API_KEY } from './source/key.js'; +import express from 'express'; + +const app = express(); +app.use(express.json()); + +app.get('/', (req, res) => { + res.send('hello from backend to frontend'); +}); + +app.post('/weather', async (req, res) => { + const cityName = req.body.cityName; + const url = `http://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=${API_KEY}&units=metric`; + if (!cityName) { + return res.status(400).json({ error: 'cityName is required' }); + } + try { + const response = await fetch(url); + const data = await response.json(); + + if (data.cod === '404') { + return res.status(404).json({ error: 'city not found' }); + } + const temperature = data.main.temp; + + res.status(200).json({ + weatherText: `The temperature in ${cityName} is ${temperature}°C`, + }); + } catch (error) { + res.status(500).json({ error: 'server error' }); + } +}); + +app.listen(3000, () => { + console.log('Server is running on port 3000'); +}); diff --git a/assignments/hackyourtemperature/source/key.js b/assignments/hackyourtemperature/source/key.js new file mode 100644 index 000000000..8ddb2d1d2 --- /dev/null +++ b/assignments/hackyourtemperature/source/key.js @@ -0,0 +1 @@ +export const API_KEY = '5b880f4ee3e43bab62bd1d03019f09c2'; From 9889a1804cd888e56576eaef82fa2b889bcba8aa Mon Sep 17 00:00:00 2001 From: "bteicho@gmail.com" Date: Tue, 1 Oct 2024 22:34:53 +0200 Subject: [PATCH 4/6] updated branch from local --- assignments/hackyourtemperature/source/key.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignments/hackyourtemperature/source/key.js b/assignments/hackyourtemperature/source/key.js index 8ddb2d1d2..3818d0346 100644 --- a/assignments/hackyourtemperature/source/key.js +++ b/assignments/hackyourtemperature/source/key.js @@ -1 +1 @@ -export const API_KEY = '5b880f4ee3e43bab62bd1d03019f09c2'; +export const AIP_KEY = '5b880f4ee3e43bab62bd1d03019f09c2'; From 78cafe9477cdc82c99306d4d048ed968460a2d13 Mon Sep 17 00:00:00 2001 From: "bteicho@gmail.com" Date: Sat, 5 Oct 2024 19:01:04 +0200 Subject: [PATCH 5/6] prep-exe-w3 --- week3/prep-exercise/server/app.js | 13 ++++-- week3/prep-exercise/server/users.js | 66 +++++++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 8 deletions(-) diff --git a/week3/prep-exercise/server/app.js b/week3/prep-exercise/server/app.js index a94f09af8..b0341332b 100644 --- a/week3/prep-exercise/server/app.js +++ b/week3/prep-exercise/server/app.js @@ -1,11 +1,16 @@ import express from 'express'; -// TODO Use below import statement for importing middlewares from users.js for your routes -// TODO import { ....... } from "./users.js"; - +import { register, login, getProfile, logout } from './users.js'; let app = express(); app.use(express.json()); -// TODO: Create routes here, e.g. app.post("/register", .......) + +app.post('/auth/register', register); + +app.post('/auth/login', login); + +app.get('/auth/profile', getProfile); + +app.post('/auth/logout', logout); // Serve the front-end application from the `client` folder app.use(express.static('client')); diff --git a/week3/prep-exercise/server/users.js b/week3/prep-exercise/server/users.js index fbf91e6c2..d88f9461a 100644 --- a/week3/prep-exercise/server/users.js +++ b/week3/prep-exercise/server/users.js @@ -1,12 +1,70 @@ -import newDatabase from './database.js' +import newDatabase from './database.js'; +import bcrypt from 'bcrypt'; +import jwt from 'jsonwebtoken'; // Change this boolean to true if you wish to keep your // users between restart of your application -const isPersistent = false -const database = newDatabase({isPersistent}) - +const isPersistent = true; +const database = newDatabase({ isPersistent }); +const secretKey = 'super-secret-key'; // Create middlewares required for routes defined in app.js + +//register // export const register = async (req, res) => {}; +export const register = async (req, res) => { + const { username, password } = req.body; + if (!username || !password) { + return res.status(400).send('Username and password are required'); + } + try { + const hashedPassword = await bcrypt.hash(password, 10); + const newUser = database.create({ username, password: hashedPassword }); + res.status(201).json({ id: newUser.id, username: newUser.username }); + } catch (error) { + res.status(500).send('An error occurred while registering the user'); + } +}; + +//login +export const login = async (req, res) => { + const { username, password } = req.body; + const users = database.getAll(); + const user = users.find((user) => user.username === username); + + if (!user) { + return res.status(404).send('User not found'); + } + const isPasswordCorrect = await bcrypt.compare(password, user.password); + if (!isPasswordCorrect) { + return res.status(401).json({ message: 'Invalid password' }); + } + const token = jwt.sign({ id: user.id }, secretKey, { expiresIn: '1h' }); + return res.status(200).json({ token }); +}; + +//getProfile + +export const getProfile = async (req, res) => { + const authHeader = req.headers['authorization']; + const token = authHeader && authHeader.split(' ')[1]; + if (!token) { + return res.status(401).json({ message: 'Unauthorized' }); + } + try { + const decoded = jwt.verify(token, secretKey); + const user = database.getById(decoded.id); + if (!user) { + res.status(404).json({ message: 'User not found' }); + } + res.status(200).json({ id: user.id, username: user.username }); + } catch (error) { + res.status(401).json({ message: 'Unauthorized' }); + } +}; // You can also create helper functions in this file to help you implement logic // inside middlewares +//logout +export const logout = async (req, res) => { + res.status(204).send('Logged out successfully'); +}; From 468243426c97e7be15d631057ba9ddff4a95cf91 Mon Sep 17 00:00:00 2001 From: "bteicho@gmail.com" Date: Sat, 5 Oct 2024 19:02:17 +0200 Subject: [PATCH 6/6] week3 prepexercise done --- week3/prep-exercise/package.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/week3/prep-exercise/package.json b/week3/prep-exercise/package.json index 6d4a60eeb..70a538fe8 100644 --- a/week3/prep-exercise/package.json +++ b/week3/prep-exercise/package.json @@ -1,7 +1,7 @@ { "name": "build-with-students", "version": "1.0.0", - "description": "", + "description": "In this exercise, you will build a secure authentication and authorization system using Node.js and Express.js with four main endpoints: `register`, `login`, `getProfile`, and `logout`. The system will utilize JWT (JSON Web Tokens) for managing user sessions.", "main": "app.js", "types": "module", "scripts": { @@ -15,13 +15,12 @@ "license": "ISC", "dependencies": { "bcrypt": "^5.1.1", - "express": "^4.18.2", - "lokijs": "^1.5.12", + "express": "^4.21.0", "jsonwebtoken": "^9.0.2", + "lokijs": "^1.5.12", "uuid": "^9.0.1" }, "devDependencies": { "nodemon": "^3.1.0" } } -