From 38534fbf9ce0ff8727207b199cbf8c6c8f1c137c Mon Sep 17 00:00:00 2001 From: Nikita Stefanchuk Date: Sun, 27 Apr 2025 09:34:35 +0200 Subject: [PATCH 1/5] prep exc --- week1/prep-exercises/1-web-server/server.js | 43 +++++++++++++++++---- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/week1/prep-exercises/1-web-server/server.js b/week1/prep-exercises/1-web-server/server.js index 90cb5ee65..0ca2b6c30 100644 --- a/week1/prep-exercises/1-web-server/server.js +++ b/week1/prep-exercises/1-web-server/server.js @@ -1,14 +1,43 @@ /** * Exercise 3: Create an HTTP web server */ - -const http = require('http'); +const fs = require('fs').promises +const path = require('path') +const http = require('http') //create a server -let server = http.createServer(function (req, res) { +let server = http.createServer(async function (req, res) { // YOUR CODE GOES IN HERE - res.write('Hello World!'); // Sends a response back to the client - res.end(); // Ends the response -}); + try { + if (req.url === '/') { + const data = await fs.readFile(path.join(__dirname, 'index.html')) + res.writeHead(200, { + 'Content-Type': 'text/html', + }) + res.end(data) + } else if (req.url === '/index.js') { + const data = await fs.readFile(path.join(__dirname, 'index.js')) + res.writeHead(200, { + 'Content-Type': 'application/javascript', + }) + res.end(data) + } else { + res.writeHead(404, { + 'Content-Type': 'text/plain', + }) + res.end('404 not found') + } + } catch (err) { + res.writeHead(500, { + 'Content-Type': 'text/plain', + }) + res.end('server error') + console.error(err) + } + // 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 +server.listen(3000, () => { + console.log('server is running (listen on port 3000)') +}) // The server starts to listen on port 3000 From d99ab745b3854b0f87e30b017f0f9191c6c74c3a Mon Sep 17 00:00:00 2001 From: Nikita Stefanchuk Date: Sat, 3 May 2025 13:18:09 +0200 Subject: [PATCH 2/5] prep ex 2 week --- week2/prep-exercises/1-blog-API/My first blog | 1 + week2/prep-exercises/1-blog-API/package.json | 5 +- week2/prep-exercises/1-blog-API/server.js | 62 +++++++++++++++++-- 3 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 week2/prep-exercises/1-blog-API/My first blog diff --git a/week2/prep-exercises/1-blog-API/My first blog b/week2/prep-exercises/1-blog-API/My first blog new file mode 100644 index 000000000..e5d353447 --- /dev/null +++ b/week2/prep-exercises/1-blog-API/My first blog @@ -0,0 +1 @@ +Lorem ipsum \ No newline at end of file diff --git a/week2/prep-exercises/1-blog-API/package.json b/week2/prep-exercises/1-blog-API/package.json index d89c4bd76..6ebc27dd3 100644 --- a/week2/prep-exercises/1-blog-API/package.json +++ b/week2/prep-exercises/1-blog-API/package.json @@ -5,11 +5,12 @@ "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "node server.js" + "start": "nodemon server.js" }, "author": "", "license": "ISC", "dependencies": { - "express": "^4.17.1" + "express": "^4.17.1", + "nodemon": "^3.1.10" } } diff --git a/week2/prep-exercises/1-blog-API/server.js b/week2/prep-exercises/1-blog-API/server.js index 3f615e8f5..8bf3e3e75 100644 --- a/week2/prep-exercises/1-blog-API/server.js +++ b/week2/prep-exercises/1-blog-API/server.js @@ -1,10 +1,64 @@ const express = require('express') -const app = express(); - +const app = express() +const fs = require('fs') + +app.use(express.json()) // to read requests format in JSON + +app.post('/blogs', (req, res) => { + // const content = req.body.content + // const title = req.body.title + const { title, content } = req.body + fs.writeFileSync(title, content) + res.end('ok') +}) + +app.put('/posts/:title', (req, res) => { + // console.log(req.query) + const { title, content } = req.body + if (title || content) { + if (fs.existsSync(title)) { + fs.writeFileSync(title, content) + res.end('ok') + } else { + res.end('This post does not exist!') + } + } else { + res.end('the request does not have a title and/or content') + } +}) + +app.delete('/blogs/:title', (req, res) => { + // console.log(req.params.title) + const title = req.params.title + if (fs.existsSync(title)) { + fs.unlinkSync(title); + res.end('ok'); + } else { + res.end('This blog does not exist!') + } +}) + +app.get('/blogs/:title', (req, res) => { + + // How to get the title from the url parameters? + const title = req.params.title + // check if post exists + if (fs.existsSync(title)) { + const post = fs.readFileSync(title); + res.end(`Your post content is: ${post}`) + } else { + res.end('This post does not exist!') + } + + + // send response +}) // YOUR CODE GOES IN HERE app.get('/', function (req, res) { res.send('Hello World') }) - -app.listen(3000) \ No newline at end of file + +app.listen(3000, () => { + console.log(`server started on http://localhost:3000`) +}) From 28734c9b46e0e28e01d30f2ba601fe7398da0c77 Mon Sep 17 00:00:00 2001 From: Nikita Stefanchuk Date: Mon, 5 May 2025 21:13:31 +0200 Subject: [PATCH 3/5] smth --- .../1-joke-api/package.json | 16 +++++++++++++ week2/practice-exercises/1-joke-api/script.js | 23 ++++++++++++------- 2 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 week2/practice-exercises/1-joke-api/package.json diff --git a/week2/practice-exercises/1-joke-api/package.json b/week2/practice-exercises/1-joke-api/package.json new file mode 100644 index 000000000..798ac30b4 --- /dev/null +++ b/week2/practice-exercises/1-joke-api/package.json @@ -0,0 +1,16 @@ +{ + "name": "1-joke-api", + "type": "module", + "version": "1.0.0", + "description": "Did you know that there is an API for Chuck Norris jokes? That's incredible, right!?", + "main": "script.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "node-fetch": "^3.3.2" + } +} diff --git a/week2/practice-exercises/1-joke-api/script.js b/week2/practice-exercises/1-joke-api/script.js index be4d84612..c0cddb830 100644 --- a/week2/practice-exercises/1-joke-api/script.js +++ b/week2/practice-exercises/1-joke-api/script.js @@ -1,18 +1,25 @@ /** * 1. Chuck Norris programs do not accept input - * + * * `GET` a random joke inside the function, using the API: http://www.icndb.com/api/ - * (use `node-fetch`) and print it to the console. + * (use `node-fetch`) and print it to the console. * Make use of `async/await` and `try/catch` - * + * * Hints * - To install node dependencies you should first initialize npm * - Print the entire response to the console to see how it is structured. */ +import fetch from 'node-fetch' -function printChuckNorrisJoke() { - // YOUR CODE GOES IN HERE - +async function printChuckNorrisJoke() { + try { + const response = await fetch('https://api.chucknorris.io/jokes/random') + // const body = await response.text() + const data = await response.json() + // console.log(response); + console.log(data.value) + } catch (err) { + console.error(err) + } } - -printChuckNorrisJoke(); \ No newline at end of file +printChuckNorrisJoke() From 7fd70323b05262c1abd67f26bea30bdd4fe2f76f Mon Sep 17 00:00:00 2001 From: Nikita Stefanchuk Date: Mon, 5 May 2025 21:14:43 +0200 Subject: [PATCH 4/5] 1 week assignment approved --- hackyourtemperature/package.json | 21 ++++++++++++++++ hackyourtemperature/server.js | 25 +++++++++++++++++++ hackyourtemperature/views/home.handlebars | 0 .../views/layouts/main.handlebars | 1 + 4 files changed, 47 insertions(+) create mode 100644 hackyourtemperature/package.json create mode 100644 hackyourtemperature/server.js create mode 100644 hackyourtemperature/views/home.handlebars create mode 100644 hackyourtemperature/views/layouts/main.handlebars diff --git a/hackyourtemperature/package.json b/hackyourtemperature/package.json new file mode 100644 index 000000000..066c18ba4 --- /dev/null +++ b/hackyourtemperature/package.json @@ -0,0 +1,21 @@ +{ + "name": "hackyourtemperature", + "version": "1.0.0", + "main": "server.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js", + "dev": "nodemon server.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "express": "^5.1.0", + "express-handlebars": "^8.0.3", + "node-fetch": "^3.3.2", + "nodemon": "^3.1.10" + } +} diff --git a/hackyourtemperature/server.js b/hackyourtemperature/server.js new file mode 100644 index 000000000..1c8b0b174 --- /dev/null +++ b/hackyourtemperature/server.js @@ -0,0 +1,25 @@ +import express from 'express' +import { engine } from 'express-handlebars' +import fetch from 'node-fetch' + + +const app = express() +app.engine('handlebars', engine()) +app.set('view engine', 'handlebars') +app.set('views', './views') + +app.get('/', (req, res) => { + res.render('home') +}) + +app.use(express.json()) + +app.post('/weather', (req, res) => { + const cityName = req.body.cityName + res.json({message: 'City name: ' + cityName}) +}) + + +app.listen(3000, () => { + console.log(`server started on http://localhost:3000`) +}) diff --git a/hackyourtemperature/views/home.handlebars b/hackyourtemperature/views/home.handlebars new file mode 100644 index 000000000..e69de29bb diff --git a/hackyourtemperature/views/layouts/main.handlebars b/hackyourtemperature/views/layouts/main.handlebars new file mode 100644 index 000000000..87d24ab87 --- /dev/null +++ b/hackyourtemperature/views/layouts/main.handlebars @@ -0,0 +1 @@ +

Hello from backend to frontend!

\ No newline at end of file From 43ce52cac1adfb953e46e4b9a6de558653710429 Mon Sep 17 00:00:00 2001 From: Nikita Stefanchuk Date: Wed, 7 May 2025 14:23:30 +0200 Subject: [PATCH 5/5] 2 week assignment --- hackyourtemperature/__tests__/app.test.js | 45 +++++++++++++++++++++ hackyourtemperature/app.js | 48 +++++++++++++++++++++++ hackyourtemperature/babel.config.cjs | 13 ++++++ hackyourtemperature/jest.config.js | 8 ++++ hackyourtemperature/package.json | 8 +++- hackyourtemperature/server.js | 22 +---------- hackyourtemperature/sources/keys.js | 1 + 7 files changed, 122 insertions(+), 23 deletions(-) create mode 100644 hackyourtemperature/__tests__/app.test.js create mode 100644 hackyourtemperature/app.js create mode 100644 hackyourtemperature/babel.config.cjs create mode 100644 hackyourtemperature/jest.config.js create mode 100644 hackyourtemperature/sources/keys.js diff --git a/hackyourtemperature/__tests__/app.test.js b/hackyourtemperature/__tests__/app.test.js new file mode 100644 index 000000000..e169111ef --- /dev/null +++ b/hackyourtemperature/__tests__/app.test.js @@ -0,0 +1,45 @@ +import app from '../app.js' +import supertest from 'supertest' +import fetch from 'node-fetch' + +jest.mock('node-fetch', () => jest.fn()) + +const request = supertest(app) + +describe('POST /', () => { + it('returns temperature for a valid city', async () => { + const fakeGeoData = [{ lat: 52.37, lon: 4.89 }] + const fakeWeatherData = { + main: { + temp: 283.15, + }, + } + + fetch + .mockResolvedValueOnce({ + json: async () => fakeGeoData, + }) + .mockResolvedValueOnce({ + json: async () => fakeWeatherData, + }) + + const response = await request.post('/').send({ cityName: 'Amsterdam' }) + + expect(response.statusCode).toBe(200) + expect(response.body).toEqual({ + cityName: 'Amsterdam', + temperature: '10.0', + }) + }) + + it('returns error message for unknown city', async () => { + fetch.mockResolvedValueOnce({ + json: async () => [], + }) + + const response = await request.post('/').send({ cityName: 'FakeCityXYZ' }) + + expect(response.statusCode).toBe(200) + expect(response.body).toBe('City is not found') + }) +}) diff --git a/hackyourtemperature/app.js b/hackyourtemperature/app.js new file mode 100644 index 000000000..f8c7c52ec --- /dev/null +++ b/hackyourtemperature/app.js @@ -0,0 +1,48 @@ +import express from 'express' +import { engine } from 'express-handlebars' +import fetch from 'node-fetch' +import { API_KEY } from './sources/keys.js' + + +const app = express() + +app.engine('handlebars', engine()) +app.set('view engine', 'handlebars') +app.set('views', './views') + +app.get('/', (req, res) => { + res.render('home') +}) + +app.use(express.json()) + +app.post('/', async (req, res) => { + try { + const cityName = req.body.cityName + const geoData = await fetch( + `http://api.openweathermap.org/geo/1.0/direct?q=${cityName}&limit=1&appid=${API_KEY}` + ) + const geoResponse = await geoData.json() + console.log(geoResponse) + if (geoResponse.length == 0) { + throw new Error('City is not found') + } + + const lat = geoResponse[0].lat + const lon = geoResponse[0].lon + console.log(lat, lon) + + const weatherData = await fetch( + `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${API_KEY}` + ) + const weatherResponse = await weatherData.json() + res.json({ + cityName: cityName, + temperature: (weatherResponse.main.temp - 273.15).toFixed(1) + }); + } catch (err) { + res.json(err.message) + } +}) + +export default app diff --git a/hackyourtemperature/babel.config.cjs b/hackyourtemperature/babel.config.cjs new file mode 100644 index 000000000..fbb629af6 --- /dev/null +++ b/hackyourtemperature/babel.config.cjs @@ -0,0 +1,13 @@ +module.exports = { + presets: [ + [ + // This is a configuration, here we are telling babel what configuration to use + "@babel/preset-env", + { + targets: { + node: "current", + }, + }, + ], + ], +}; diff --git a/hackyourtemperature/jest.config.js b/hackyourtemperature/jest.config.js new file mode 100644 index 000000000..19ba9649e --- /dev/null +++ b/hackyourtemperature/jest.config.js @@ -0,0 +1,8 @@ +export default { + // Tells jest that any file that has 2 .'s in it and ends with either js or jsx should be run through the babel-jest transformer + transform: { + "^.+\\.jsx?$": "babel-jest", + }, + // By default our `node_modules` folder is ignored by jest, this tells jest to transform those as well + transformIgnorePatterns: [], +}; diff --git a/hackyourtemperature/package.json b/hackyourtemperature/package.json index 066c18ba4..2d7e556a0 100644 --- a/hackyourtemperature/package.json +++ b/hackyourtemperature/package.json @@ -4,7 +4,7 @@ "main": "server.js", "type": "module", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", + "test": "jest", "start": "node server.js", "dev": "nodemon server.js" }, @@ -13,9 +13,13 @@ "license": "ISC", "description": "", "dependencies": { + "@babel/preset-env": "^7.27.2", + "babel-jest": "^29.7.0", "express": "^5.1.0", "express-handlebars": "^8.0.3", + "jest": "^29.7.0", "node-fetch": "^3.3.2", - "nodemon": "^3.1.10" + "nodemon": "^3.1.10", + "supertest": "^7.1.0" } } diff --git a/hackyourtemperature/server.js b/hackyourtemperature/server.js index 1c8b0b174..9805cebc4 100644 --- a/hackyourtemperature/server.js +++ b/hackyourtemperature/server.js @@ -1,24 +1,4 @@ -import express from 'express' -import { engine } from 'express-handlebars' -import fetch from 'node-fetch' - - -const app = express() -app.engine('handlebars', engine()) -app.set('view engine', 'handlebars') -app.set('views', './views') - -app.get('/', (req, res) => { - res.render('home') -}) - -app.use(express.json()) - -app.post('/weather', (req, res) => { - const cityName = req.body.cityName - res.json({message: 'City name: ' + cityName}) -}) - +import app from './app.js' app.listen(3000, () => { console.log(`server started on http://localhost:3000`) diff --git a/hackyourtemperature/sources/keys.js b/hackyourtemperature/sources/keys.js new file mode 100644 index 000000000..976b30002 --- /dev/null +++ b/hackyourtemperature/sources/keys.js @@ -0,0 +1 @@ +export const API_KEY = '7d47d5f41dcdf3b026655cb15bf3ff0a'